Bug 673451 - Add getters and setters to make JS write barriers easier to implement (r=cdleary)
authorBill McCloskey <wmccloskey@mozilla.com>
Wed, 13 Jul 2011 15:43:33 -0700
changeset 73439 ed434f4c233eee7090fb9b38229bdc1354f1555f
parent 73438 0737efca777e16746dd9435bad830164d3f2f5fd
child 73440 dbefaf7244f1885b217e37e7f3716282b23b2ea8
push idunknown
push userunknown
push dateunknown
reviewerscdleary
bugs673451
milestone8.0a1
Bug 673451 - Add getters and setters to make JS write barriers easier to implement (r=cdleary)
js/src/jsapi-tests/testConservativeGC.cpp
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jsarray.h
js/src/jscntxtinlines.h
js/src/jsdate.cpp
js/src/jsexn.cpp
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsfuninlines.h
js/src/jsinterp.cpp
js/src/jsiter.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jsscope.cpp
js/src/jstracer.cpp
js/src/jstracer.h
js/src/jstypedarray.cpp
js/src/jstypedarrayinlines.h
js/src/jsvalue.h
js/src/methodjit/BaseAssembler.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/MonoIC.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/tracejit/Writer.h
js/src/vm/ArgumentsObject-inl.h
js/src/vm/ArgumentsObject.h
js/src/vm/GlobalObject.cpp
js/src/vm/GlobalObject.h
js/src/vm/Stack-inl.h
--- a/js/src/jsapi-tests/testConservativeGC.cpp
+++ b/js/src/jsapi-tests/testConservativeGC.cpp
@@ -47,17 +47,17 @@ BEGIN_TEST(testConservativeGC)
 
 bool checkObjectFields(JSObject *savedCopy, JSObject *obj)
 {
     /*
      * The GC can change the shape and shrink dslots so we update them before
      * doing memcmp.
      */
     savedCopy->objShape = obj->objShape;
-    savedCopy->slots = obj->slots;
+    savedCopy->setSlotsPtr(obj->getSlotsPtr());
     CHECK(!memcmp(savedCopy, obj, sizeof(*obj)));
     return true;
 }
 
 END_TEST(testConservativeGC)
 
 BEGIN_TEST(testDerivedValues)
 {
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -4000,17 +4000,17 @@ JS_NewPropertyIterator(JSContext *cx, JS
         if (!ida)
             return NULL;
         pdata = ida;
         index = ida->length;
     }
 
     /* iterobj cannot escape to other threads here. */
     iterobj->setPrivate(const_cast<void *>(pdata));
-    iterobj->getSlotRef(JSSLOT_ITER_INDEX).setInt32(index);
+    iterobj->setSlot(JSSLOT_ITER_INDEX, Int32Value(index));
     return iterobj;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp)
 {
     jsint i;
     const Shape *shape;
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -268,17 +268,17 @@ JSObject::willBeSparseDenseArray(uintN r
     uintN minimalDenseCount = requiredCapacity / 4;
     if (newElementsHint >= minimalDenseCount)
         return false;
     minimalDenseCount -= newElementsHint;
 
     if (minimalDenseCount > cap)
         return true;
 
-    Value *elems = getDenseArrayElements();
+    const Value *elems = getDenseArrayElements();
     for (uintN i = 0; i < cap; i++) {
         if (!elems[i].isMagic(JS_ARRAY_HOLE) && !--minimalDenseCount)
             return false;
     }
     return true;
 }
 
 static bool
@@ -368,19 +368,20 @@ GetElementsSlow(JSContext *cx, JSObject 
 }
 
 bool
 GetElements(JSContext *cx, JSObject *aobj, jsuint length, Value *vp)
 {
     if (aobj->isDenseArray() && length <= aobj->getDenseArrayCapacity() &&
         !js_PrototypeHasIndexedProperties(cx, aobj)) {
         /* The prototype does not have indexed properties so hole = undefined */
-        Value *srcbeg = aobj->getDenseArrayElements();
-        Value *srcend = srcbeg + length;
-        for (Value *dst = vp, *src = srcbeg; src < srcend; ++dst, ++src)
+        const Value *srcbeg = aobj->getDenseArrayElements();
+        const Value *srcend = srcbeg + length;
+        const Value *src = srcbeg;
+        for (Value *dst = vp; src < srcend; ++dst, ++src)
             *dst = src->isMagic(JS_ARRAY_HOLE) ? UndefinedValue() : *src;
         return true;
     }
 
     if (aobj->isArguments()) {
         ArgumentsObject *argsobj = aobj->asArguments();
         if (!argsobj->hasOverriddenLength()) {
             if (argsobj->getElements(0, length, vp))
@@ -892,17 +893,17 @@ array_deleteProperty(JSContext *cx, JSOb
 } // namespace js
 
 static void
 array_trace(JSTracer *trc, JSObject *obj)
 {
     JS_ASSERT(obj->isDenseArray());
 
     uint32 capacity = obj->getDenseArrayCapacity();
-    MarkValueRange(trc, capacity, obj->slots, "element");
+    MarkValueRange(trc, capacity, obj->getSlotsPtr(), "element");
 }
 
 static JSBool
 array_fix(JSContext *cx, JSObject *obj, bool *success, AutoIdVector *props)
 {
     JS_ASSERT(obj->isDenseArray());
 
     /*
@@ -1264,19 +1265,19 @@ array_toString_sub(JSContext *cx, JSObje
     jsuint length;
     if (!js_GetLengthProperty(cx, obj, &length))
         return false;
 
     StringBuffer sb(cx);
 
     if (!locale && !seplen && obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj)) {
         /* Elements beyond 'capacity' are 'undefined' and thus can be ignored. */
-        Value *beg = obj->getDenseArrayElements();
-        Value *end = beg + Min(length, obj->getDenseArrayCapacity());
-        for (Value *vp = beg; vp != end; ++vp) {
+        const Value *beg = obj->getDenseArrayElements();
+        const Value *end = beg + Min(length, obj->getDenseArrayCapacity());
+        for (const Value *vp = beg; vp != end; ++vp) {
             if (!JS_CHECK_OPERATION_LIMIT(cx))
                 return false;
 
             if (!vp->isMagic(JS_ARRAY_HOLE) && !vp->isNullOrUndefined()) {
                 if (!ValueToStringBuffer(cx, *vp, sb))
                     return false;
             }
         }
@@ -1391,17 +1392,17 @@ InitArrayElements(JSContext *cx, JSObjec
             JS_ASSERT(result == JSObject::ED_SPARSE);
             break;
         }
         jsuint newlen = start + count;
         if (newlen > obj->getArrayLength())
             obj->setArrayLength(newlen);
 
         JS_ASSERT(count < uint32(-1) / sizeof(Value));
-        memcpy(obj->getDenseArrayElements() + start, vector, sizeof(jsval) * count);
+        obj->copyDenseArrayElements(start, vector, count);
         JS_ASSERT_IF(count != 0, !obj->getDenseArrayElement(newlen - 1).isMagic(JS_ARRAY_HOLE));
         return true;
     } while (false);
 
     Value* end = vector + count;
     while (vector != end && start < MAXINDEX) {
         if (!JS_CHECK_OPERATION_LIMIT(cx) ||
             !SetArrayElement(cx, obj, start++, *vector++)) {
@@ -1440,17 +1441,17 @@ InitArrayObject(JSContext *cx, JSObject 
     JS_ASSERT(obj->isDenseArray());
     obj->setArrayLength(length);
     if (!vector || !length)
         return true;
 
     /* Avoid ensureDenseArrayElements to skip sparse array checks there. */
     if (!obj->ensureSlots(cx, length))
         return false;
-    memcpy(obj->getDenseArrayElements(), vector, length * sizeof(Value));
+    obj->copyDenseArrayElements(0, vector, length);
     return true;
 }
 
 /*
  * Perl-inspired join, reverse, and sort.
  */
 static JSBool
 array_join(JSContext *cx, uintN argc, Value *vp)
@@ -2188,18 +2189,17 @@ array_shift(JSContext *cx, uintN argc, V
     } else {
         length--;
 
         if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
             length < obj->getDenseArrayCapacity()) {
             *vp = obj->getDenseArrayElement(0);
             if (vp->isMagic(JS_ARRAY_HOLE))
                 vp->setUndefined();
-            Value *elems = obj->getDenseArrayElements();
-            memmove(elems, elems + 1, length * sizeof(jsval));
+            obj->moveDenseArrayElements(0, 1, length);
             obj->setDenseArrayElement(length, MagicValue(JS_ARRAY_HOLE));
             obj->setArrayLength(length);
             if (!js_SuppressDeletedProperty(cx, obj, INT_TO_JSID(length)))
                 return JS_FALSE;
             return JS_TRUE;
         }
 
         /* Get the to-be-deleted property's value into vp ASAP. */
@@ -2251,18 +2251,17 @@ array_unshift(JSContext *cx, uintN argc,
                     break;
                 JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, length, argc);
                 if (result != JSObject::ED_OK) {
                     if (result == JSObject::ED_FAILED)
                         return false;
                     JS_ASSERT(result == JSObject::ED_SPARSE);
                     break;
                 }
-                Value *elems = obj->getDenseArrayElements();
-                memmove(elems + argc, elems, length * sizeof(jsval));
+                obj->moveDenseArrayElements(argc, 0, length);
                 for (uint32 i = 0; i < argc; i++)
                     obj->setDenseArrayElement(i, MagicValue(JS_ARRAY_HOLE));
                 optimized = true;
             } while (false);
 
             if (!optimized) {
                 last = length;
                 jsdouble upperIndex = last + argc;
@@ -2390,22 +2389,17 @@ array_splice(JSContext *cx, uintN argc, 
                 break;
             JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, length, delta);
             if (result != JSObject::ED_OK) {
                 if (result == JSObject::ED_FAILED)
                     return false;
                 JS_ASSERT(result == JSObject::ED_SPARSE);
                 break;
             }
-            Value *arraybeg = obj->getDenseArrayElements();
-            Value *srcbeg = arraybeg + last - 1;
-            Value *srcend = arraybeg + end - 1;
-            Value *dstbeg = srcbeg + delta;
-            for (Value *src = srcbeg, *dst = dstbeg; src > srcend; --src, --dst)
-                *dst = *src;
+            obj->moveDenseArrayElements(end + delta, end, last - end);
 
             obj->setArrayLength(obj->getArrayLength() + delta);
             optimized = true;
         } while (false);
 
         if (!optimized) {
             /* (uint) end could be 0, so we can't use a vanilla >= test. */
             while (last-- > end) {
@@ -2417,22 +2411,17 @@ array_splice(JSContext *cx, uintN argc, 
             }
         }
         length += delta;
     } else if (argc < count) {
         delta = count - (jsuint)argc;
         if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
             length <= obj->getDenseArrayCapacity()) {
 
-            Value *arraybeg = obj->getDenseArrayElements();
-            Value *srcbeg = arraybeg + end;
-            Value *srcend = arraybeg + length;
-            Value *dstbeg = srcbeg - delta;
-            for (Value *src = srcbeg, *dst = dstbeg; src < srcend; ++src, ++dst)
-                *dst = *src;
+            obj->moveDenseArrayElements(end - delta, end, length - end);
         } else {
             for (last = end; last < length; last++) {
                 if (!JS_CHECK_OPERATION_LIMIT(cx) ||
                     !GetElement(cx, obj, last, &hole, tvr.addr()) ||
                     !SetOrDeleteArrayElement(cx, obj, last - delta, hole, tvr.value())) {
                     return JS_FALSE;
                 }
             }
@@ -3086,26 +3075,26 @@ NewDenseAllocatedArray(JSContext *cx, ui
 
 JSObject * JS_FASTCALL
 NewDenseUnallocatedArray(JSContext *cx, uint32 length, JSObject *proto)
 {
     return NewArray<false>(cx, length, proto);
 }
 
 JSObject *
-NewDenseCopiedArray(JSContext *cx, uintN length, Value *vp, JSObject *proto)
+NewDenseCopiedArray(JSContext *cx, uintN length, const Value *vp, JSObject *proto)
 {
     JSObject* obj = NewArray<true>(cx, length, proto);
     if (!obj)
         return NULL;
 
     JS_ASSERT(obj->getDenseArrayCapacity() >= length);
 
     if (vp)
-        memcpy(obj->getDenseArrayElements(), vp, length * sizeof(Value));
+        obj->copyDenseArrayElements(0, vp, length);
 
     return obj;
 }
 
 #ifdef JS_TRACER
 JS_DEFINE_CALLINFO_2(extern, OBJECT, NewDenseEmptyArray, CONTEXT, OBJECT, 0,
                      nanojit::ACCSET_STORE_ANY)
 JS_DEFINE_CALLINFO_3(extern, OBJECT, NewDenseAllocatedArray, CONTEXT, UINT32, OBJECT, 0,
--- a/js/src/jsarray.h
+++ b/js/src/jsarray.h
@@ -174,17 +174,17 @@ NewDenseAllocatedArray(JSContext *cx, ui
  * Create a dense array with a set length, but without allocating space for the
  * contents. This is useful, e.g., when accepting length from the user.
  */
 extern JSObject * JS_FASTCALL
 NewDenseUnallocatedArray(JSContext *cx, uint length, JSObject *proto=NULL);
 
 /* Create a dense array with a copy of vp. */
 extern JSObject *
-NewDenseCopiedArray(JSContext *cx, uint length, Value *vp, JSObject *proto=NULL);
+NewDenseCopiedArray(JSContext *cx, uint length, const Value *vp, JSObject *proto=NULL);
 
 /* Create a sparse array. */
 extern JSObject *
 NewSlowEmptyArray(JSContext *cx);
 
 }
 
 extern JSBool
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -369,17 +369,17 @@ CallSetter(JSContext *cx, JSObject *obj,
  */
 JS_FORCES_STACK JS_FRIEND_API(void)
 DeepBail(JSContext *cx);
 #endif
 
 static JS_INLINE void
 LeaveTraceIfGlobalObject(JSContext *cx, JSObject *obj)
 {
-    if (!obj->parent)
+    if (!obj->getParent())
         LeaveTrace(cx);
 }
 
 static JS_INLINE void
 LeaveTraceIfArgumentsObject(JSContext *cx, JSObject *obj)
 {
     if (obj->isArguments())
         LeaveTrace(cx);
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -1236,17 +1236,17 @@ GetUTCTime(JSContext *cx, JSObject *obj,
  */
 static JSBool
 SetUTCTime(JSContext *cx, JSObject *obj, jsdouble t, Value *vp = NULL)
 {
     JS_ASSERT(obj->isDate());
 
     size_t slotCap = JS_MIN(obj->numSlots(), JSObject::DATE_CLASS_RESERVED_SLOTS);
     for (size_t ind = JSObject::JSSLOT_DATE_COMPONENTS_START; ind < slotCap; ind++)
-        obj->getSlotRef(ind).setUndefined();
+        obj->setSlot(ind, UndefinedValue());
 
     obj->setDateUTCTime(DoubleValue(t));
     if (vp)
         vp->setDouble(t);
     return true;
 }
 
 static void
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -1032,17 +1032,17 @@ js_InitExceptionClasses(JSContext *cx, J
         JSObject *proto =
             DefineConstructorAndPrototype(cx, obj, protoKey, atom,
                                           (i == JSEXN_ERR) ? obj_proto : error_proto,
                                           &js_ErrorClass, Exception, 1,
                                           NULL, (i == JSEXN_ERR) ? exception_methods : NULL,
                                           NULL, NULL);
         if (!proto)
             return NULL;
-        JS_ASSERT(proto->privateData == NULL);
+        JS_ASSERT(proto->getPrivate() == NULL);
 
         if (i == JSEXN_ERR)
             error_proto = proto;
 
         /* Add properties to the prototype. */
         JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING);
         if (!DefineNativeProperty(cx, proto, nameId, StringValue(atom),
                                   PropertyStub, StrictPropertyStub, 0, 0, 0) ||
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -865,19 +865,18 @@ js_CreateCallObjectOnTrace(JSContext *cx
 
 JS_DEFINE_CALLINFO_4(extern, OBJECT, js_CreateCallObjectOnTrace, CONTEXT, FUNCTION, OBJECT, OBJECT,
                      0, nanojit::ACCSET_STORE_ANY)
 
 inline static void
 CopyValuesToCallObject(JSObject &callobj, uintN nargs, Value *argv, uintN nvars, Value *slots)
 {
     JS_ASSERT(callobj.numSlots() >= JSObject::CALL_RESERVED_SLOTS + nargs + nvars);
-    Value *base = callobj.getSlots() + JSObject::CALL_RESERVED_SLOTS;
-    memcpy(base, argv, nargs * sizeof(Value));
-    memcpy(base + nargs, slots, nvars * sizeof(Value));
+    callobj.copySlots(JSObject::CALL_RESERVED_SLOTS, argv, nargs);
+    callobj.copySlots(JSObject::CALL_RESERVED_SLOTS + nargs, slots, nvars);
 }
 
 void
 js_PutCallObject(StackFrame *fp)
 {
     JSObject &callobj = fp->callObj();
     JS_ASSERT(callobj.getPrivate() == fp);
     JS_ASSERT_IF(fp->isEvalFrame(), fp->isStrictEvalFrame());
@@ -1009,24 +1008,21 @@ GetCallArg(JSContext *cx, JSObject *obj,
 }
 
 JSBool
 SetCallArg(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
 {
     JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
     uintN i = (uint16) JSID_TO_INT(id);
 
-    Value *argp;
     if (StackFrame *fp = obj->maybeCallObjStackFrame())
-        argp = &fp->formalArg(i);
+        fp->formalArg(i) = *vp;
     else
-        argp = &obj->callObjArg(i);
-
-    GCPoke(cx, *argp);
-    *argp = *vp;
+        obj->setCallObjArg(i, *vp);
+
     return true;
 }
 
 JSBool
 GetCallUpvar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
     uintN i = (uint16) JSID_TO_INT(id);
@@ -1036,20 +1032,17 @@ GetCallUpvar(JSContext *cx, JSObject *ob
 }
 
 JSBool
 SetCallUpvar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
 {
     JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
     uintN i = (uint16) JSID_TO_INT(id);
 
-    Value *up = &obj->getCallObjCallee()->getFlatClosureUpvar(i);
-
-    GCPoke(cx, *up);
-    *up = *vp;
+    obj->getCallObjCallee()->setFlatClosureUpvar(i, *vp);
     return true;
 }
 
 JSBool
 GetCallVar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
     uintN i = (uint16) JSID_TO_INT(id);
@@ -1079,24 +1072,21 @@ SetCallVar(JSContext *cx, JSObject *obj,
 #ifdef JS_TRACER
     if (JS_ON_TRACE(cx)) {
         TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx);
         if (tm->recorder && tm->tracecx)
             AbortRecording(cx, "upvar write in nested tree");
     }
 #endif
 
-    Value *varp;
     if (StackFrame *fp = obj->maybeCallObjStackFrame())
-        varp = &fp->varSlot(i);
+        fp->varSlot(i) = *vp;
     else
-        varp = &obj->callObjVar(i);
-
-    GCPoke(cx, *varp);
-    *varp = *vp;
+        obj->setCallObjVar(i, *vp);
+
     return true;
 }
 
 } // namespace js
 
 #if JS_TRACER
 JSBool JS_FASTCALL
 js_SetCallArg(JSContext *cx, JSObject *obj, jsid slotid, ValueArgType arg)
@@ -1169,17 +1159,17 @@ call_trace(JSTracer *trc, JSObject *obj)
          * for JS objects (including Call objects), so is unable to collect
          * cycles involving Call objects whose frames are active without this
          * hiding hack.
          */
         uintN first = JSObject::CALL_RESERVED_SLOTS;
         uintN count = fp->script()->bindings.countArgsAndVars();
 
         JS_ASSERT(obj->numSlots() >= first + count);
-        SetValueRangeToUndefined(obj->getSlots() + first, count);
+        obj->setSlotsUndefined(first, count);
     }
 
     MaybeMarkGenerator(trc, obj);
 }
 
 JS_PUBLIC_DATA(Class) js_CallClass = {
     "Call",
     JSCLASS_HAS_PRIVATE |
@@ -1918,32 +1908,32 @@ CallOrConstructBoundFunction(JSContext *
 
 inline bool
 JSObject::initBoundFunction(JSContext *cx, const Value &thisArg,
                             const Value *args, uintN argslen)
 {
     JS_ASSERT(isFunction());
 
     flags |= JSObject::BOUND_FUNCTION;
-    getSlotRef(JSSLOT_BOUND_FUNCTION_THIS) = thisArg;
-    getSlotRef(JSSLOT_BOUND_FUNCTION_ARGS_COUNT).setPrivateUint32(argslen);
+    setSlot(JSSLOT_BOUND_FUNCTION_THIS, thisArg);
+    setSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT, PrivateUint32Value(argslen));
     if (argslen != 0) {
         /* FIXME? Burn memory on an empty scope whose shape covers the args slots. */
-        EmptyShape *empty = EmptyShape::create(cx, clasp);
+        EmptyShape *empty = EmptyShape::create(cx, getClass());
         if (!empty)
             return false;
 
         empty->slotSpan += argslen;
         setMap(empty);
 
         if (!ensureInstanceReservedSlots(cx, argslen))
             return false;
 
         JS_ASSERT(numSlots() >= argslen + FUN_CLASS_RESERVED_SLOTS);
-        memcpy(getSlots() + FUN_CLASS_RESERVED_SLOTS, args, argslen * sizeof(Value));
+        copySlots(FUN_CLASS_RESERVED_SLOTS, args, argslen);
     }
     return true;
 }
 
 inline JSObject *
 JSObject::getBoundFunctionTarget() const
 {
     JS_ASSERT(isFunction());
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -185,37 +185,30 @@ struct JSFunction : public JSObject_Slot
      * a compiler-created function object use the first one to hold a mutable
      * methodAtom() state variable, needed for correct foo.caller handling.
      */
     enum {
         METHOD_ATOM_SLOT  = JSSLOT_FUN_METHOD_ATOM
     };
 
   public:
-    void setJoinable() {
-        JS_ASSERT(FUN_INTERPRETED(this));
-        getSlotRef(METHOD_ATOM_SLOT).setNull();
-        flags |= JSFUN_JOINABLE;
-    }
+    inline void setJoinable();
 
     /*
      * Method name imputed from property uniquely assigned to or initialized,
      * where the function does not need to be cloned to carry a scope chain or
      * flattened upvars.
      */
     JSAtom *methodAtom() const {
         return (joinable() && getSlot(METHOD_ATOM_SLOT).isString())
                ? &getSlot(METHOD_ATOM_SLOT).toString()->asAtom()
                : NULL;
     }
 
-    void setMethodAtom(JSAtom *atom) {
-        JS_ASSERT(joinable());
-        getSlotRef(METHOD_ATOM_SLOT).setString(atom);
-    }
+    inline void setMethodAtom(JSAtom *atom);
 
     JSScript *script() const {
         JS_ASSERT(isInterpreted());
         return u.i.script;
     }
 
     js::Native native() const {
         JS_ASSERT(isNative());
--- a/js/src/jsfuninlines.h
+++ b/js/src/jsfuninlines.h
@@ -44,9 +44,24 @@
 #include "jsscript.h"
 
 inline bool
 JSFunction::inStrictMode() const
 {
     return script()->strictModeCode;
 }
 
+inline void
+JSFunction::setJoinable()
+{
+    JS_ASSERT(FUN_INTERPRETED(this));
+    setSlot(METHOD_ATOM_SLOT, js::NullValue());
+    flags |= JSFUN_JOINABLE;
+}
+
+inline void
+JSFunction::setMethodAtom(JSAtom *atom)
+{
+    JS_ASSERT(joinable());
+    setSlot(METHOD_ATOM_SLOT, js::StringValue(atom));
+}
+
 #endif /* jsfuninlines_h___ */
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -3269,23 +3269,23 @@ BEGIN_CASE(JSOP_GNAMEDEC)
 
     JSObject *obj2;
     PropertyCacheEntry *entry;
     JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom);
     if (!atom) {
         ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry);
         if (obj == obj2 && entry->vword.isSlot()) {
             uint32 slot = entry->vword.toSlot();
-            Value &rref = obj->nativeGetSlotRef(slot);
+            const Value &rref = obj->nativeGetSlot(slot);
             int32_t tmp;
             if (JS_LIKELY(rref.isInt32() && CanIncDecWithoutOverflow(tmp = rref.toInt32()))) {
                 int32_t inc = tmp + ((js_CodeSpec[op].format & JOF_INC) ? 1 : -1);
                 if (!(js_CodeSpec[op].format & JOF_POST))
                     tmp = inc;
-                rref.getInt32Ref() = inc;
+                obj->nativeSetSlot(slot, Int32Value(inc));
                 PUSH_INT32(tmp);
                 len = JSOP_INCNAME_LENGTH;
                 DO_NEXT_OP(len);
             }
         }
         LOAD_ATOM(0, atom);
     }
 
@@ -3848,26 +3848,26 @@ BEGIN_CASE(JSOP_GETELEM)
     Value rval;
     jsid id;
     if (rref.isInt32()) {
         int32_t i = rref.toInt32();
         if (obj->isDenseArray()) {
             jsuint idx = jsuint(i);
 
             if (idx < obj->getDenseArrayCapacity()) {
-                copyFrom = obj->addressOfDenseArrayElement(idx);
+                copyFrom = &obj->getDenseArrayElement(idx);
                 if (!copyFrom->isMagic())
                     goto end_getelem;
             }
         } else if (obj->isArguments()) {
             uint32 arg = uint32(i);
             ArgumentsObject *argsobj = obj->asArguments();
 
             if (arg < argsobj->initialLength()) {
-                copyFrom = argsobj->addressOfElement(arg);
+                copyFrom = &argsobj->element(arg);
                 if (!copyFrom->isMagic(JS_ARGS_HOLE)) {
                     if (StackFrame *afp = reinterpret_cast<StackFrame *>(argsobj->getPrivate()))
                         copyFrom = &afp->canonicalActualArg(arg);
                     goto end_getelem;
                 }
             }
         }
         if (JS_LIKELY(INT_FITS_IN_JSID(i)))
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -225,17 +225,17 @@ EnumerateDenseArrayProperties(JSContext 
 {
     if (!Enumerate(cx, obj, pobj, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), false,
                    flags, ht, props)) {
         return false;
     }
 
     if (pobj->getArrayLength() > 0) {
         size_t capacity = pobj->getDenseArrayCapacity();
-        Value *vp = pobj->getDenseArrayElements();
+        const Value *vp = pobj->getDenseArrayElements();
         for (size_t i = 0; i < capacity; ++i, ++vp) {
             if (!vp->isMagic(JS_ARRAY_HOLE)) {
                 /* Dense arrays never get so large that i would not fit into an integer id. */
                 if (!Enumerate(cx, obj, pobj, INT_TO_JSID(i), true, flags, ht, props))
                     return false;
             }
         }
     }
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2925,17 +2925,17 @@ js_CreateThisFromTrace(JSContext *cx, JS
     const Shape *shape = ctor->nativeLookup(id);
     JS_ASSERT(shape->slot == protoSlot);
     JS_ASSERT(!shape->configurable());
     JS_ASSERT(!shape->isMethod());
 #endif
 
     JSObject *parent = ctor->getParent();
     JSObject *proto;
-    const Value &protov = ctor->getSlotRef(protoSlot);
+    const Value &protov = ctor->getSlot(protoSlot);
     if (protov.isObject()) {
         proto = &protov.toObject();
     } else {
         /*
          * GetInterpretedFunctionPrototype found that ctor.prototype is
          * primitive. Use Object.prototype for proto, per ES5 13.2.2 step 7.
          */
         if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
@@ -3252,17 +3252,17 @@ js_PutBlockObject(JSContext *cx, JSBool 
     JS_ASSERT(count <= size_t(cx->regs().sp - fp->base() - depth));
 
     /* See comments in CheckDestructuring from jsparse.cpp. */
     JS_ASSERT(count >= 1);
 
     if (normalUnwind) {
         uintN slot = JSSLOT_BLOCK_FIRST_FREE_SLOT;
         depth += fp->numFixed();
-        memcpy(obj->getSlots() + slot, fp->slots() + depth, count * sizeof(Value));
+        obj->copySlots(slot, fp->slots() + depth, count);
     }
 
     /* We must clear the private slot even with errors. */
     obj->setPrivate(NULL);
     fp->setScopeChainNoCallObj(*obj->getParent());
     return normalUnwind;
 }
 
@@ -3380,26 +3380,26 @@ CopySlots(JSContext *cx, JSObject *from,
     JS_ASSERT(!from->isNative() && !to->isNative());
     size_t nslots = from->numSlots();
     if (to->ensureSlots(cx, nslots))
         return false;
 
     size_t n = 0;
     if (to->isWrapper() &&
         (JSWrapper::wrapperHandler(to)->flags() & JSWrapper::CROSS_COMPARTMENT)) {
-        to->slots[0] = from->slots[0];
-        to->slots[1] = from->slots[1];
+        to->setSlot(0, from->getSlot(0));
+        to->setSlot(1, from->getSlot(1));
         n = 2;
     }
 
     for (; n < nslots; ++n) {
-        Value v = from->slots[n];
+        Value v = from->getSlot(n);
         if (!cx->compartment->wrap(cx, &v))
             return false;
-        to->slots[n] = v;
+        to->setSlot(n, v);
     }
     return true;
 }
 
 JSObject *
 JSObject::clone(JSContext *cx, JSObject *proto, JSObject *parent)
 {
     /*
@@ -3466,19 +3466,19 @@ TradeGuts(JSObject *a, JSObject *b)
         JS_ASSERT(size <= sizeof(tmp));
 
         memcpy(tmp, a, size);
         memcpy(a, b, size);
         memcpy(b, tmp, size);
 
         /* Fixup pointers for inline slots on the objects. */
         if (aInline)
-            b->slots = b->fixedSlots();
+            b->setSlotsPtr(b->fixedSlots());
         if (bInline)
-            a->slots = a->fixedSlots();
+            a->setSlotsPtr(a->fixedSlots());
     } else {
         /*
          * If the objects are of differing sizes, then we only copy over the
          * JSObject portion (things like class, etc.) and leave it to
          * JSObject::clone to copy over the dynamic slots for us.
          */
         if (a->isFunction()) {
             JSFunction tmp;
@@ -3782,17 +3782,17 @@ DefineConstructorAndPrototype(JSContext 
     /*
      * Create the prototype object.  (GlobalObject::createBlankPrototype isn't
      * used because it parents the prototype object to the global and because
      * it uses WithProto::Given.  FIXME: Undo dependencies on this parentage
      * [which already needs to happen for bug 638316], figure out nicer
      * semantics for null-protoProto, and use createBlankPrototype.)
      */
     JSObject *proto = NewObject<WithProto::Class>(cx, clasp, protoProto, obj);
-    if (!proto || !proto->getEmptyShape(cx, proto->clasp, gc::FINALIZE_OBJECT0))
+    if (!proto || !proto->getEmptyShape(cx, proto->getClass(), gc::FINALIZE_OBJECT0))
         return NULL;
 
     proto->syncSpecialEquality();
 
     /* After this point, control must exit via label bad or out. */
     JSObject *ctor;
     bool named = false;
     if (!constructor) {
@@ -4060,17 +4060,17 @@ JSObject::shrinkSlots(JSContext *cx, siz
 }
 
 bool
 JSObject::ensureInstanceReservedSlots(JSContext *cx, size_t nreserved)
 {
     JS_ASSERT_IF(isNative(),
                  isBlock() || isCall() || (isFunction() && isBoundFunction()));
 
-    uintN nslots = JSSLOT_FREE(clasp) + nreserved;
+    uintN nslots = JSSLOT_FREE(getClass()) + nreserved;
     return nslots <= numSlots() || allocSlots(cx, nslots);
 }
 
 static JSObject *
 js_InitNullClass(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(0);
     return NULL;
@@ -4314,36 +4314,37 @@ js_ConstructObject(JSContext *cx, Class 
     }
     return obj;
 }
 
 bool
 JSObject::allocSlot(JSContext *cx, uint32 *slotp)
 {
     uint32 slot = slotSpan();
-    JS_ASSERT(slot >= JSSLOT_FREE(clasp));
+    JS_ASSERT(slot >= JSSLOT_FREE(getClass()));
 
     /*
      * If this object is in dictionary mode and it has a property table, try to
      * pull a free slot from the property table's slot-number freelist.
      */
     if (inDictionaryMode() && lastProp->hasTable()) {
-        uint32 &last = lastProp->getTable()->freelist;
+        PropertyTable *table = lastProp->getTable();
+        uint32 last = table->freelist;
         if (last != SHAPE_INVALID_SLOT) {
 #ifdef DEBUG
             JS_ASSERT(last < slot);
             uint32 next = getSlot(last).toPrivateUint32();
             JS_ASSERT_IF(next != SHAPE_INVALID_SLOT, next < slot);
 #endif
 
             *slotp = last;
 
-            Value &vref = getSlotRef(last);
-            last = vref.toPrivateUint32();
-            vref.setUndefined();
+            const Value &vref = getSlot(last);
+            table->freelist = vref.toPrivateUint32();
+            setSlot(last, UndefinedValue());
             return true;
         }
     }
 
     if (slot >= numSlots() && !growSlots(cx, slot + 1))
         return false;
 
     /* JSObject::growSlots or JSObject::freeSlot should set the free slots to void. */
@@ -4353,37 +4354,36 @@ JSObject::allocSlot(JSContext *cx, uint3
 }
 
 bool
 JSObject::freeSlot(JSContext *cx, uint32 slot)
 {
     uint32 limit = slotSpan();
     JS_ASSERT(slot < limit);
 
-    Value &vref = getSlotRef(slot);
     if (inDictionaryMode() && lastProp->hasTable()) {
         uint32 &last = lastProp->getTable()->freelist;
 
         /* Can't afford to check the whole freelist, but let's check the head. */
         JS_ASSERT_IF(last != SHAPE_INVALID_SLOT, last < limit && last != slot);
 
         /*
          * Freeing a slot other than the last one mapped by this object's
          * shape (and not a reserved slot; see bug 595230): push the slot onto
          * the dictionary property table's freelist. We want to let the last
          * slot be freed by shrinking the dslots vector; see js_TraceObject.
          */
-        if (JSSLOT_FREE(clasp) <= slot && slot + 1 < limit) {
+        if (JSSLOT_FREE(getClass()) <= slot && slot + 1 < limit) {
             JS_ASSERT_IF(last != SHAPE_INVALID_SLOT, last < slotSpan());
-            vref.setPrivateUint32(last);
+            setSlot(slot, PrivateUint32Value(last));
             last = slot;
             return true;
         }
     }
-    vref.setUndefined();
+    setSlot(slot, UndefinedValue());
     return false;
 }
 
 /* JSBOXEDWORD_INT_MAX as a string */
 #define JSBOXEDWORD_INT_MAX_STRING "1073741823"
 
 /*
  * Convert string indexes that convert to int jsvals as ints to save memory.
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -388,18 +388,23 @@ struct JSObject : js::gc::Cell {
     /* If prototype, lazily filled array of empty shapes for each object size. */
     js::EmptyShape **emptyShapes;
 
     JSObject    *proto;                     /* object's prototype */
     JSObject    *parent;                    /* object's parent */
     void        *privateData;               /* private data */
     jsuword     capacity;                   /* number of slots; for ArrayBuffer the number 
                                                may be be non-integral, so this may underestimate */
+  private:
     js::Value   *slots;                     /* dynamically allocated slots,
                                                or pointer to fixedSlots() */
+  public:
+    static size_t offsetOfSlots() {
+        return offsetof(JSObject, slots);
+    }
 
     /*
      * Return an immutable, shareable, empty shape with the same clasp as this
      * and the same slotSpan as this had when empty.
      *
      * If |this| is the scope of an object |proto|, the resulting scope can be
      * used as the scope of a new object whose prototype is |proto|.
      */
@@ -637,18 +642,29 @@ struct JSObject : js::gc::Cell {
      * their initial map.
      */
     bool ensureInstanceReservedSlots(JSContext *cx, size_t nreserved);
 
     /*
      * Get a direct pointer to the object's slots.
      * This can be reallocated if the object is modified, watch out!
      */
-    js::Value *getSlots() const {
-        return slots;
+    const js::Value *getSlots() const { return slots; }
+
+    js::Value *getSlotsPtr() { return slots; }
+    void setSlotsPtr(js::Value *vp) { slots = vp; }
+
+    void copySlots(uint32 dstStart, const js::Value *src, uint32 count) {
+        JS_ASSERT(dstStart + count <= capacity);
+        memcpy(slots + dstStart, src, count * sizeof(js::Value));
+    }
+
+    void setSlotsUndefined(uint32 start, uint32 count) {
+        JS_ASSERT(start + count <= capacity);
+        js::SetValueRangeToUndefined(slots + start, count);
     }
 
     /*
      * NB: ensureClassReservedSlotsForEmptyObject asserts that nativeEmpty()
      * Use ensureClassReservedSlots for any object, either empty or already
      * extended with properties.
      */
     bool ensureClassReservedSlotsForEmptyObject(JSContext *cx);
@@ -780,20 +796,21 @@ struct JSObject : js::gc::Cell {
     /*
      * Array-specific getters and setters (for both dense and slow arrays).
      */
 
     inline uint32 getArrayLength() const;
     inline void setArrayLength(uint32 length);
 
     inline uint32 getDenseArrayCapacity();
-    inline js::Value* getDenseArrayElements();
+    inline const js::Value* getDenseArrayElements();
     inline const js::Value &getDenseArrayElement(uintN idx);
-    inline js::Value* addressOfDenseArrayElement(uintN idx);
     inline void setDenseArrayElement(uintN idx, const js::Value &val);
+    inline void copyDenseArrayElements(uintN dstStart, const js::Value *src, uintN count);
+    inline void moveDenseArrayElements(uintN dstStart, uintN srcStart, uintN count);
     inline void shrinkDenseArrayElements(JSContext *cx, uintN cap);
 
     /*
      * ensureDenseArrayElements ensures that the dense array can hold at least
      * index + extra elements. It returns ED_OK on success, ED_FAILED on
      * failure to grow the array, ED_SPARSE when the array is too sparse to
      * grow (this includes the case of index + extra overflow). In the last
      * two cases the array is kept intact.
@@ -847,21 +864,21 @@ struct JSObject : js::gc::Cell {
     inline JSFunction *getCallObjCalleeFunction() const; 
     inline void setCallObjCallee(JSObject *callee);
 
     inline const js::Value &getCallObjArguments() const;
     inline void setCallObjArguments(const js::Value &v);
 
     /* Returns the formal argument at the given index. */
     inline const js::Value &callObjArg(uintN i) const;
-    inline js::Value &callObjArg(uintN i);
+    inline void setCallObjArg(uintN i, const js::Value &v);
 
     /* Returns the variable at the given index. */
     inline const js::Value &callObjVar(uintN i) const;
-    inline js::Value &callObjVar(uintN i);
+    inline void setCallObjVar(uintN i, const js::Value &v);
 
     /*
      * Date-specific getters and setters.
      */
 
     static const uint32 JSSLOT_DATE_UTC_TIME = 0;
 
     /*
@@ -912,17 +929,18 @@ struct JSObject : js::gc::Cell {
 
   public:
     static const uint32 FUN_CLASS_RESERVED_SLOTS = 2;
 
     inline JSFunction *getFunctionPrivate() const;
 
     inline js::Value *getFlatClosureUpvars() const;
     inline js::Value getFlatClosureUpvar(uint32 i) const;
-    inline js::Value &getFlatClosureUpvar(uint32 i);
+    inline const js::Value &getFlatClosureUpvar(uint32 i);
+    inline void setFlatClosureUpvar(uint32 i, const js::Value &v);
     inline void setFlatClosureUpvars(js::Value *upvars);
 
     inline bool hasMethodObj(const JSObject& obj) const;
     inline void setMethodObj(JSObject& obj);
 
     inline bool initBoundFunction(JSContext *cx, const js::Value &thisArg,
                                   const js::Value *args, uintN argslen);
 
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -119,17 +119,17 @@ JSObject::unbrand(JSContext *cx)
     }
     setGeneric();
     return true;
 }
 
 inline void
 JSObject::syncSpecialEquality()
 {
-    if (clasp->ext.equality)
+    if (getClass()->ext.equality)
         flags |= JSObject::HAS_EQUALITY;
 }
 
 inline void
 JSObject::finalize(JSContext *cx)
 {
     /* Cope with stillborn objects that have no map. */
     if (isNewborn())
@@ -355,45 +355,54 @@ JSObject::setArrayLength(uint32 length)
 
 inline uint32
 JSObject::getDenseArrayCapacity()
 {
     JS_ASSERT(isDenseArray());
     return numSlots();
 }
 
-inline js::Value*
+inline const js::Value *
 JSObject::getDenseArrayElements()
 {
     JS_ASSERT(isDenseArray());
     return getSlots();
 }
 
 inline const js::Value &
 JSObject::getDenseArrayElement(uintN idx)
 {
     JS_ASSERT(isDenseArray());
     return getSlot(idx);
 }
 
-inline js::Value *
-JSObject::addressOfDenseArrayElement(uintN idx)
-{
-    JS_ASSERT(isDenseArray());
-    return &getSlotRef(idx);
-}
-
 inline void
 JSObject::setDenseArrayElement(uintN idx, const js::Value &val)
 {
     JS_ASSERT(isDenseArray());
     setSlot(idx, val);
 }
 
 inline void
+JSObject::copyDenseArrayElements(uintN dstStart, const js::Value *src, uintN count)
+{
+    JS_ASSERT(isDenseArray());
+    copySlots(dstStart, src, count);
+}
+
+inline void
+JSObject::moveDenseArrayElements(uintN dstStart, uintN srcStart, uintN count)
+{
+    JS_ASSERT(isDenseArray());
+    JS_ASSERT(dstStart + count <= capacity);
+    JS_ASSERT(srcStart + count <= capacity);
+    memmove(slots + dstStart, getSlots() + srcStart, count * sizeof(js::Value));
+}
+
+inline void
 JSObject::shrinkDenseArrayElements(JSContext *cx, uintN cap)
 {
     JS_ASSERT(isDenseArray());
     shrinkSlots(cx, cap);
 }
 
 inline bool
 JSObject::callIsForEval() const
@@ -412,17 +421,17 @@ JSObject::maybeCallObjStackFrame() const
     return reinterpret_cast<js::StackFrame *>(getPrivate());
 }
 
 inline void
 JSObject::setCallObjCallee(JSObject *callee)
 {
     JS_ASSERT(isCall());
     JS_ASSERT_IF(callee, callee->isFunction());
-    return getSlotRef(JSSLOT_CALL_CALLEE).setObjectOrNull(callee);
+    setSlot(JSSLOT_CALL_CALLEE, js::ObjectOrNullValue(callee));
 }
 
 inline JSObject *
 JSObject::getCallObjCallee() const
 {
     JS_ASSERT(isCall());
     return getSlot(JSSLOT_CALL_CALLEE).toObjectOrNull();
 }
@@ -453,40 +462,40 @@ JSObject::setCallObjArguments(const js::
 inline const js::Value &
 JSObject::callObjArg(uintN i) const
 {
     JS_ASSERT(isCall());
     JS_ASSERT(i < getCallObjCalleeFunction()->nargs);
     return getSlot(JSObject::CALL_RESERVED_SLOTS + i);
 }
 
-inline js::Value &
-JSObject::callObjArg(uintN i)
+inline void
+JSObject::setCallObjArg(uintN i, const js::Value &v)
 {
     JS_ASSERT(isCall());
     JS_ASSERT(i < getCallObjCalleeFunction()->nargs);
-    return getSlotRef(JSObject::CALL_RESERVED_SLOTS + i);
+    setSlot(JSObject::CALL_RESERVED_SLOTS + i, v);
 }
 
 inline const js::Value &
 JSObject::callObjVar(uintN i) const
 {
     JSFunction *fun = getCallObjCalleeFunction();
     JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
     JS_ASSERT(i < fun->script()->bindings.countVars());
     return getSlot(JSObject::CALL_RESERVED_SLOTS + fun->nargs + i);
 }
 
-inline js::Value &
-JSObject::callObjVar(uintN i)
+inline void
+JSObject::setCallObjVar(uintN i, const js::Value &v)
 {
     JSFunction *fun = getCallObjCalleeFunction();
     JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
     JS_ASSERT(i < fun->script()->bindings.countVars());
-    return getSlotRef(JSObject::CALL_RESERVED_SLOTS + fun->nargs + i);
+    setSlot(JSObject::CALL_RESERVED_SLOTS + fun->nargs + i, v);
 }
 
 inline const js::Value &
 JSObject::getDateUTCTime() const
 {
     JS_ASSERT(isDate());
     return getSlot(JSSLOT_DATE_UTC_TIME);
 }
@@ -511,43 +520,50 @@ JSObject::getFlatClosureUpvars() const
 
 inline js::Value
 JSObject::getFlatClosureUpvar(uint32 i) const
 {
     JS_ASSERT(i < getFunctionPrivate()->script()->bindings.countUpvars());
     return getFlatClosureUpvars()[i];
 }
 
-inline js::Value &
+inline const js::Value &
 JSObject::getFlatClosureUpvar(uint32 i)
 {
     JS_ASSERT(i < getFunctionPrivate()->script()->bindings.countUpvars());
     return getFlatClosureUpvars()[i];
 }
 
 inline void
+JSObject::setFlatClosureUpvar(uint32 i, const js::Value &v)
+{
+    JS_ASSERT(i < getFunctionPrivate()->script()->bindings.countUpvars());
+    getFlatClosureUpvars()[i] = v;
+}
+
+inline void
 JSObject::setFlatClosureUpvars(js::Value *upvars)
 {
     JS_ASSERT(isFunction());
     JS_ASSERT(FUN_FLAT_CLOSURE(getFunctionPrivate()));
-    getSlotRef(JSSLOT_FLAT_CLOSURE_UPVARS).setPrivate(upvars);
+    setSlot(JSSLOT_FLAT_CLOSURE_UPVARS, PrivateValue(upvars));
 }
 
 inline bool
 JSObject::hasMethodObj(const JSObject& obj) const
 {
     return JSSLOT_FUN_METHOD_OBJ < numSlots() &&
            getSlot(JSSLOT_FUN_METHOD_OBJ).isObject() &&
            getSlot(JSSLOT_FUN_METHOD_OBJ).toObject() == obj;
 }
 
 inline void
 JSObject::setMethodObj(JSObject& obj)
 {
-    getSlotRef(JSSLOT_FUN_METHOD_OBJ).setObject(obj);
+    setSlot(JSSLOT_FUN_METHOD_OBJ, js::ObjectValue(obj));
 }
 
 inline js::NativeIterator *
 JSObject::getNativeIterator() const
 {
     return (js::NativeIterator *) getPrivate();
 }
 
@@ -648,17 +664,17 @@ inline JSObject *
 JSObject::getWithThis() const
 {
     return &getSlot(JSSLOT_WITH_THIS).toObject();
 }
 
 inline void
 JSObject::setWithThis(JSObject *thisp)
 {
-    getSlotRef(JSSLOT_WITH_THIS).setObject(*thisp);
+    setSlot(JSSLOT_WITH_THIS, js::ObjectValue(*thisp));
 }
 
 inline void
 JSObject::init(JSContext *cx, js::Class *aclasp, JSObject *proto, JSObject *parent,
                void *priv, bool useHoles)
 {
     clasp = aclasp;
     flags = 0;
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -582,17 +582,17 @@ JSObject::checkShapeConsistency()
 
     Shape *shape = lastProp;
     Shape *prev = NULL;
 
     if (inDictionaryMode()) {
         if (shape->hasTable()) {
             PropertyTable *table = shape->getTable();
             for (uint32 fslot = table->freelist; fslot != SHAPE_INVALID_SLOT;
-                 fslot = getSlotRef(fslot).toPrivateUint32()) {
+                 fslot = getSlot(fslot).toPrivateUint32()) {
                 JS_ASSERT(fslot < shape->slotSpan);
             }
 
             for (int n = throttle; --n >= 0 && shape->parent; shape = shape->parent) {
                 JS_ASSERT_IF(shape != lastProp, !shape->hasTable());
 
                 Shape **spp = table->search(shape->propid, false);
                 JS_ASSERT(SHAPE_FETCH(spp) == shape);
@@ -901,17 +901,17 @@ JSObject::putProperty(JSContext *cx, jsi
      * has no slot. But we do not need to free oldSlot (and must not, as trying
      * to will botch an assertion in JSObject::freeSlot) if the new lastProp
      * (shape here) has a slotSpan that does not cover it.
      */
     if (hadSlot && !shape->hasSlot()) {
         if (oldSlot < shape->slotSpan)
             freeSlot(cx, oldSlot);
         else
-            getSlotRef(oldSlot).setUndefined();
+            setSlot(oldSlot, UndefinedValue());
         JS_ATOMIC_INCREMENT(&cx->runtime->propertyRemovals);
     }
 
     CHECK_SHAPE_CONSISTENCY(this);
 
     return js_UpdateWatchpointsForShape(cx, this, shape);
 }
 
@@ -1097,17 +1097,17 @@ JSObject::removeProperty(JSContext *cx, 
                 if (table->freelist != SHAPE_INVALID_SLOT) {
                     lastProp->slotSpan = shape->slotSpan;
 
                     /*
                      * Add the slot to the freelist if it wasn't added in
                      * freeSlot and it is not a reserved slot.
                      */
                     if (hadSlot && !addedToFreelist && JSSLOT_FREE(clasp) <= shape->slot) {
-                        getSlotRef(shape->slot).setPrivateUint32(table->freelist);
+                        setSlot(shape->slot, PrivateUint32Value(table->freelist));
                         table->freelist = shape->slot;
                     }
                 }
             }
 
             /* Hand off table from old to new lastProp. */
             oldLastProp->setTable(NULL);
             lastProp->setTable(table);
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -3043,17 +3043,17 @@ TraceMonitor::mark(JSTracer *trc)
 
 /*
  * Box a value from the native stack back into the Value format.
  */
 static inline void
 NativeToValue(JSContext* cx, Value& v, JSValueType type, double* slot)
 {
     if (type == JSVAL_TYPE_DOUBLE) {
-        v.setNumber(*slot);
+        v = NumberValue(*slot);
     } else if (JS_LIKELY(type <= JSVAL_UPPER_INCL_TYPE_OF_BOXABLE_SET)) {
         v.boxNonDoubleFrom(type, (uint64 *)slot);
     } else if (type == JSVAL_TYPE_STRORNULL) {
         JSString *str = *(JSString **)slot;
         v = str ? StringValue(str) : NullValue();
     } else if (type == JSVAL_TYPE_OBJORNULL) {
         JSObject *obj = *(JSObject **)slot;
         v = obj ? ObjectValue(*obj) : NullValue();
@@ -3832,17 +3832,17 @@ TraceRecorder::isValidSlot(JSObject *obj
 
 /* Lazily import a global slot if we don't already have it in the tracker. */
 JS_REQUIRES_STACK void
 TraceRecorder::importGlobalSlot(unsigned slot)
 {
     JS_ASSERT(slot == uint16(slot));
     JS_ASSERT(globalObj->numSlots() <= MAX_GLOBAL_SLOTS);
 
-    Value* vp = &globalObj->getSlotRef(slot);
+    const Value* vp = &globalObj->getSlot(slot);
     JS_ASSERT(!known(vp));
 
     /* Add the slot to the list of interned global slots. */
     JSValueType type;
     int index = tree->globalSlots->offsetOf(uint16(slot));
     if (index == -1) {
         type = getCoercedType(*vp);
         if (type == JSVAL_TYPE_INT32 && (!oracle || oracle->isGlobalSlotUndemotable(cx, slot)))
@@ -3865,17 +3865,17 @@ TraceRecorder::lazilyImportGlobalSlot(un
     if (slot != uint16(slot)) /* we use a table of 16-bit ints, bail out if that's not enough */
         return false;
     /*
      * If the global object grows too large, alloca in ExecuteTree might fail,
      * so abort tracing on global objects with unreasonably many slots.
      */
     if (globalObj->numSlots() > MAX_GLOBAL_SLOTS)
         return false;
-    Value* vp = &globalObj->getSlotRef(slot);
+    const Value* vp = &globalObj->getSlot(slot);
     if (known(vp))
         return true; /* we already have it */
     importGlobalSlot(slot);
     return true;
 }
 
 /* Write back a value onto the stack or global frames. */
 LIns*
@@ -3898,17 +3898,17 @@ TraceRecorder::writeBack(LIns* ins, LIns
         unsigned slot = unsigned(offset / sizeof(double));
         (void)pendingGlobalSlotsToSet.append(slot);  /* OOM is safe. */
     }
     return w.st(ins, addr);
 }
 
 /* Update the tracker, then issue a write back store. */
 JS_REQUIRES_STACK void
-TraceRecorder::setImpl(void* p, LIns* i, bool shouldDemoteToInt32)
+TraceRecorder::setImpl(const void* p, LIns* i, bool shouldDemoteToInt32)
 {
     JS_ASSERT(i != NULL);
     checkForGlobalObjectReallocation();
     tracker.set(p, i);
 
     /*
      * If we are writing to this location for the first time, calculate the
      * offset into the native frame manually. Otherwise just look up the last
@@ -3943,17 +3943,17 @@ TraceRecorder::setImpl(void* p, LIns* i,
                             ? nativespOffsetImpl(p)
                             : nativeGlobalOffset((Value *)p)));
 
         writeBack(i, base, disp, shouldDemoteToInt32);
     }
 }
 
 JS_REQUIRES_STACK inline void
-TraceRecorder::set(Value* p, LIns* i, bool shouldDemoteToInt32)
+TraceRecorder::set(const Value* p, LIns* i, bool shouldDemoteToInt32)
 {
     return setImpl(p, i, shouldDemoteToInt32);
 }
 
 JS_REQUIRES_STACK void
 TraceRecorder::setFrameObjPtr(void* p, LIns* i, bool shouldDemoteToInt32)
 {
     JS_ASSERT(isValidFrameObjPtr(p));
@@ -4066,18 +4066,18 @@ TraceRecorder::known(JSObject** p)
  * The slots of the global object are sometimes reallocated by the interpreter.
  * This function check for that condition and re-maps the entries of the tracker
  * accordingly.
  */
 JS_REQUIRES_STACK void
 TraceRecorder::checkForGlobalObjectReallocationHelper()
 {
     debug_only_print0(LC_TMTracer, "globalObj->slots relocated, updating tracker\n");
-    Value* src = global_slots;
-    Value* dst = globalObj->getSlots();
+    const Value* src = global_slots;
+    const Value* dst = globalObj->getSlots();
     jsuint length = globalObj->capacity;
     LIns** map = (LIns**)alloca(sizeof(LIns*) * length);
     for (jsuint n = 0; n < length; ++n) {
         map[n] = tracker.get(src);
         tracker.set(src++, NULL);
     }
     for (jsuint n = 0; n < length; ++n)
         tracker.set(dst++, map[n]);
@@ -5453,17 +5453,17 @@ TraceRecorder::emitTreeCall(TreeFragment
 #endif
 
     /* The inner tree may modify currently-tracked upvars, so flush everything. */
     ClearSlotsVisitor visitor(tracker);
     VisitStackSlots(visitor, cx, callDepth);
     SlotList& gslots = *tree->globalSlots;
     for (unsigned i = 0; i < gslots.length(); i++) {
         unsigned slot = gslots[i];
-        Value* vp = &globalObj->getSlotRef(slot);
+        const Value* vp = &globalObj->getSlot(slot);
         tracker.set(vp, NULL);
     }
 
     /* Set stack slots from the innermost frame. */
     importTypeMap.setLength(NativeStackSlots(cx, callDepth));
     unsigned startOfInnerFrame = importTypeMap.length() - exit->numStackSlots;
     for (unsigned i = 0; i < exit->numStackSlots; i++)
         importTypeMap[startOfInnerFrame + i] = exit->stackTypeMap()[i];
@@ -8144,17 +8144,17 @@ JS_DEFINE_CALLINFO_4(extern, UINT32, Get
  * generate LIR to access the given property. Return RECORD_CONTINUE on success,
  * otherwise abort and return RECORD_STOP. There are 3 outparams:
  *
  *     vp           the address of the current property value
  *     ins          LIR instruction representing the property value on trace
  *     NameResult   describes how to look up name; see comment for NameResult in jstracer.h
  */
 JS_REQUIRES_STACK AbortableRecordingStatus
-TraceRecorder::scopeChainProp(JSObject* chainHead, Value*& vp, LIns*& ins, NameResult& nr,
+TraceRecorder::scopeChainProp(JSObject* chainHead, const Value*& vp, LIns*& ins, NameResult& nr,
                               JSObject** scopeObjp)
 {
     JS_ASSERT(chainHead == &cx->fp()->scopeChain());
     JS_ASSERT(chainHead != globalObj);
 
     TraceMonitor &localtm = *traceMonitor;
 
     JSAtom* atom = atoms[GET_INDEX(cx->regs().pc)];
@@ -8194,17 +8194,17 @@ TraceRecorder::scopeChainProp(JSObject* 
         if (obj2 != obj)
             RETURN_STOP_A("prototype property");
 
         Shape* shape = (Shape*) prop;
         if (!isValidSlot(obj, shape))
             return ARECORD_STOP;
         if (!lazilyImportGlobalSlot(shape->slot))
             RETURN_STOP_A("lazy import of global slot failed");
-        vp = &obj->getSlotRef(shape->slot);
+        vp = &obj->getSlot(shape->slot);
         ins = get(vp);
         nr.tracked = true;
         return ARECORD_CONTINUE;
     }
 
     if (obj == obj2 && obj->isCall()) {
         AbortableRecordingStatus status =
             InjectStatus(callProp(obj, prop, ATOM_TO_JSID(atom), vp, ins, nr));
@@ -8213,17 +8213,17 @@ TraceRecorder::scopeChainProp(JSObject* 
 
     RETURN_STOP_A("fp->scopeChain is not global or active call object");
 }
 
 /*
  * Generate LIR to access a property of a Call object.
  */
 JS_REQUIRES_STACK RecordingStatus
-TraceRecorder::callProp(JSObject* obj, JSProperty* prop, jsid id, Value*& vp,
+TraceRecorder::callProp(JSObject* obj, JSProperty* prop, jsid id, const Value*& vp,
                         LIns*& ins, NameResult& nr)
 {
     Shape *shape = (Shape*) prop;
 
     JSOp op = JSOp(*cx->regs().pc);
     uint32 setflags = (js_CodeSpec[op].format & (JOF_SET | JOF_INCDEC | JOF_FOR));
     if (setflags && !shape->writable())
         RETURN_STOP("writing to a read-only property");
@@ -8921,31 +8921,31 @@ TraceRecorder::incProp(jsint incr, bool 
 
     uint32 slot;
     LIns* v_ins;
     CHECK_STATUS_A(prop(obj, obj_ins, &slot, &v_ins, NULL));
 
     if (slot == SHAPE_INVALID_SLOT)
         RETURN_STOP_A("incProp on invalid slot");
 
-    Value& v = obj->getSlotRef(slot);
+    const Value& v = obj->getSlot(slot);
     Value v_after;
     CHECK_STATUS_A(inc(v, v_ins, v_after, incr, pre));
 
     LIns* slots_ins = NULL;
     stobj_set_slot(obj, obj_ins, slot, slots_ins, v_after, v_ins);
     return ARECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::incElem(jsint incr, bool pre)
 {
     Value& r = stackval(-1);
     Value& l = stackval(-2);
-    Value* vp;
+    const Value* vp;
     LIns* v_ins;
     LIns* addr_ins;
 
     if (!l.isPrimitive() && l.toObject().isDenseArray() && r.isInt32()) {
         guardDenseArray(get(&l), MISMATCH_EXIT);
         CHECK_STATUS(denseArrayElement(l, r, vp, v_ins, addr_ins, snapshot(BRANCH_EXIT)));
         if (!addr_ins) // if we read a hole, abort
             return RECORD_STOP;
@@ -11921,17 +11921,17 @@ JS_REQUIRES_STACK AbortableRecordingStat
 TraceRecorder::record_JSOP_DECELEM()
 {
     return InjectStatus(incElem(-1));
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::incName(jsint incr, bool pre)
 {
-    Value* vp;
+    const Value* vp;
     LIns* v_ins;
     LIns* v_ins_after;
     NameResult nr;
 
     CHECK_STATUS_A(name(vp, v_ins, nr));
     Value v = nr.tracked ? *vp : nr.v;
     Value v_after;
     CHECK_STATUS_A(incHelper(v, v_ins, v_after, v_ins_after, incr));
@@ -13015,17 +13015,17 @@ TraceRecorder::record_JSOP_GETELEM()
                 set(&idx, obj_ins);
             return ARECORD_CONTINUE;
         }
         RETURN_STOP_A("can't reach arguments object's frame");
     }
 
     if (obj->isDenseArray()) {
         // Fast path for dense arrays accessed with a integer index.
-        Value* vp;
+        const Value* vp;
         LIns* addr_ins;
 
         VMSideExit* branchExit = snapshot(BRANCH_EXIT);
         guardDenseArray(obj_ins, branchExit);
         CHECK_STATUS_A(denseArrayElement(lval, idx, vp, v_ins, addr_ins, branchExit));
         set(&lval, v_ins);
         if (call)
             set(&idx, obj_ins);
@@ -13387,17 +13387,17 @@ JS_DEFINE_CALLINFO_2(static, BOOL, Check
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_CALLNAME()
 {
     JSObject* scopeObj = &cx->fp()->scopeChain();
     LIns *funobj_ins;
     JSObject *funobj;
     if (scopeObj != globalObj) {
-        Value* vp;
+        const Value* vp;
         NameResult nr;
         CHECK_STATUS_A(scopeChainProp(scopeObj, vp, funobj_ins, nr, &scopeObj));
         if (!nr.tracked)
             vp = &nr.v;
         if (!vp->isObject())
             RETURN_STOP_A("callee is not an object");
         funobj = &vp->toObject();
         if (!funobj->isFunction())
@@ -13964,17 +13964,17 @@ TraceRecorder::record_NativeCallComplete
     }
 
     // We'll null pendingSpecializedNative in monitorRecording, on the next op
     // cycle.  There must be a next op since the stack is non-empty.
     return ARECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
-TraceRecorder::name(Value*& vp, LIns*& ins, NameResult& nr)
+TraceRecorder::name(const Value*& vp, LIns*& ins, NameResult& nr)
 {
     JSObject* obj = &cx->fp()->scopeChain();
     JSOp op = JSOp(*cx->regs().pc);
     if (js_CodeSpec[op].format & JOF_GNAME)
         obj = obj->getGlobal();
     if (obj != globalObj)
         return scopeChainProp(obj, vp, ins, nr);
 
@@ -14206,17 +14206,17 @@ TraceRecorder::propTail(JSObject* obj, L
     return RECORD_CONTINUE;
 }
 
 /*
  * When we end up with a hole, read it as undefined, and make sure to set
  * addr_ins to null.
  */
 JS_REQUIRES_STACK RecordingStatus
-TraceRecorder::denseArrayElement(Value& oval, Value& ival, Value*& vp, LIns*& v_ins,
+TraceRecorder::denseArrayElement(Value& oval, Value& ival, const Value*& vp, LIns*& v_ins,
                                  LIns*& addr_ins, VMSideExit* branchExit)
 {
     JS_ASSERT(oval.isObject() && ival.isInt32());
 
     JSObject* obj = &oval.toObject();
     LIns* obj_ins = get(&oval);
     jsint idx = ival.toInt32();
     LIns* idx_ins;
@@ -14242,18 +14242,18 @@ TraceRecorder::denseArrayElement(Value& 
         addr_ins = NULL;
         return RECORD_CONTINUE;
     }
 
     /* Guard that index is within capacity. */
     guard(true, w.name(w.ltui(idx_ins, capacity_ins), "inRange"), branchExit);
 
     /* Load the value and guard on its type to unbox it. */
-    vp = &obj->slots[jsuint(idx)];
-	JS_ASSERT(sizeof(Value) == 8); // The |3| in the following statement requires this.
+    vp = &obj->getSlot(jsuint(idx));
+    JS_ASSERT(sizeof(Value) == 8); // The |3| in the following statement requires this.
     addr_ins = w.name(w.getDslotAddress(obj_ins, idx_ins), "elemp");
     v_ins = unbox_value(*vp, DSlotsAddress(addr_ins), branchExit);
 
     /* Don't let the hole value escape. Turn it into an undefined. */
     if (vp->isMagic()) {
         CHECK_STATUS(guardPrototypeHasNoIndexedProperties(obj, obj_ins, snapshot(MISMATCH_EXIT)));
         v_ins = w.immiUndefined();
         addr_ins = NULL;
@@ -14363,17 +14363,17 @@ TraceRecorder::getProp(Value& v)
         RETURN_STOP_A("primitive lhs");
 
     return getProp(&v.toObject(), get(&v));
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_NAME()
 {
-    Value* vp;
+    const Value* vp;
     LIns* v_ins;
     NameResult nr;
     CHECK_STATUS_A(name(vp, v_ins, nr));
     stack(0, v_ins);
     return ARECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
@@ -16105,17 +16105,17 @@ TraceRecorder::record_JSOP_STOP()
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GETXPROP()
 {
     Value& l = stackval(-1);
     if (l.isPrimitive())
         RETURN_STOP_A("primitive-this for GETXPROP?");
 
-    Value* vp;
+    const Value* vp;
     LIns* v_ins;
     NameResult nr;
     CHECK_STATUS_A(name(vp, v_ins, nr));
     stack(-1, v_ins);
     return ARECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
@@ -16422,17 +16422,17 @@ TraceRecorder::record_JSOP_GETGLOBAL()
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_CALLGLOBAL()
 {
     uint32 slot = cx->fp()->script()->getGlobalSlot(GET_SLOTNO(cx->regs().pc));
     if (!lazilyImportGlobalSlot(slot))
          RETURN_STOP_A("lazy import of global slot failed");
 
-    Value &v = globalObj->getSlotRef(slot);
+    const Value &v = globalObj->getSlot(slot);
     stack(0, get(&v));
     stack(1, w.immiUndefined());
     return ARECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GETGNAME()
 {
--- a/js/src/jstracer.h
+++ b/js/src/jstracer.h
@@ -1058,17 +1058,17 @@ class TraceRecorder
 
     /* Maps interpreter stack values to the instruction generating that value. */
     Tracker                         tracker;
 
     /* Maps interpreter stack values to the instruction writing back to the native stack. */
     Tracker                         nativeFrameTracker;
 
     /* The start of the global object's slots we assume for the trackers. */
-    Value*                          global_slots;
+    const Value*                    global_slots;
 
     /* The number of interpreted calls entered (and not yet left) since recording began. */
     unsigned                        callDepth;
 
     /* The current atom table, mirroring the interpreter loop's variable of the same name. */
     JSAtom**                        atoms;
     Value*                          consts;
 
@@ -1216,18 +1216,18 @@ class TraceRecorder
     nanojit::LIns* writeBack(nanojit::LIns* i, nanojit::LIns* base, ptrdiff_t offset,
                              bool shouldDemoteToInt32);
 
 #ifdef DEBUG
     bool isValidFrameObjPtr(void *obj);
 #endif
     void assertInsideLoop();
 
-    JS_REQUIRES_STACK void setImpl(void* p, nanojit::LIns* l, bool shouldDemoteToInt32 = true);
-    JS_REQUIRES_STACK void set(Value* p, nanojit::LIns* l, bool shouldDemoteToInt32 = true);
+    JS_REQUIRES_STACK void setImpl(const void* p, nanojit::LIns* l, bool shouldDemoteToInt32 = true);
+    JS_REQUIRES_STACK void set(const Value* p, nanojit::LIns* l, bool shouldDemoteToInt32 = true);
     JS_REQUIRES_STACK void setFrameObjPtr(void* p, nanojit::LIns* l,
                                           bool shouldDemoteToInt32 = true);
     nanojit::LIns* getFromTrackerImpl(const void *p);
     nanojit::LIns* getFromTracker(const Value* p);
     JS_REQUIRES_STACK nanojit::LIns* getImpl(const void* p);
     JS_REQUIRES_STACK nanojit::LIns* get(const Value* p);
     JS_REQUIRES_STACK nanojit::LIns* getFrameObjPtr(void* p);
     JS_REQUIRES_STACK nanojit::LIns* attemptImport(const Value* p);
@@ -1269,18 +1269,18 @@ class TraceRecorder
         js::Shape        *shape;         // shape name was resolved to
     };
 
     JS_REQUIRES_STACK nanojit::LIns* scopeChain();
     JS_REQUIRES_STACK nanojit::LIns* entryScopeChain() const;
     JS_REQUIRES_STACK nanojit::LIns* entryFrameIns() const;
     JS_REQUIRES_STACK StackFrame* frameIfInRange(JSObject* obj, unsigned* depthp = NULL) const;
     JS_REQUIRES_STACK RecordingStatus traverseScopeChain(JSObject *obj, nanojit::LIns *obj_ins, JSObject *obj2, nanojit::LIns *&obj2_ins);
-    JS_REQUIRES_STACK AbortableRecordingStatus scopeChainProp(JSObject* obj, Value*& vp, nanojit::LIns*& ins, NameResult& nr, JSObject **scopeObjp = NULL);
-    JS_REQUIRES_STACK RecordingStatus callProp(JSObject* obj, JSProperty* shape, jsid id, Value*& vp, nanojit::LIns*& ins, NameResult& nr);
+    JS_REQUIRES_STACK AbortableRecordingStatus scopeChainProp(JSObject* obj, const Value*& vp, nanojit::LIns*& ins, NameResult& nr, JSObject **scopeObjp = NULL);
+    JS_REQUIRES_STACK RecordingStatus callProp(JSObject* obj, JSProperty* shape, jsid id, const Value*& vp, nanojit::LIns*& ins, NameResult& nr);
 
     JS_REQUIRES_STACK nanojit::LIns* arg(unsigned n);
     JS_REQUIRES_STACK void arg(unsigned n, nanojit::LIns* i);
     JS_REQUIRES_STACK nanojit::LIns* var(unsigned n);
     JS_REQUIRES_STACK void var(unsigned n, nanojit::LIns* i);
     JS_REQUIRES_STACK nanojit::LIns* upvar(JSScript* script, JSUpvarArray* uva, uintN index, Value& v);
     nanojit::LIns* stackLoad(tjit::Address addr, uint8 type);
     JS_REQUIRES_STACK nanojit::LIns* stack(int n);
@@ -1349,25 +1349,25 @@ class TraceRecorder
     void stobj_set_dslot(nanojit::LIns *obj_ins, unsigned slot,
                          nanojit::LIns*& slots_ins, const Value &v, nanojit::LIns* v_ins);
     void stobj_set_slot(JSObject *obj, nanojit::LIns* obj_ins, unsigned slot,
                         nanojit::LIns*& slots_ins, const Value &v, nanojit::LIns* v_ins);
 
     nanojit::LIns* unbox_slot(JSObject *obj, nanojit::LIns *obj_ins, uint32 slot,
                               VMSideExit *exit);
 
-    JS_REQUIRES_STACK AbortableRecordingStatus name(Value*& vp, nanojit::LIns*& ins, NameResult& nr);
+    JS_REQUIRES_STACK AbortableRecordingStatus name(const Value*& vp, nanojit::LIns*& ins, NameResult& nr);
     JS_REQUIRES_STACK AbortableRecordingStatus prop(JSObject* obj, nanojit::LIns* obj_ins,
                                                     uint32 *slotp, nanojit::LIns** v_insp,
                                                     Value* outp);
     JS_REQUIRES_STACK RecordingStatus propTail(JSObject* obj, nanojit::LIns* obj_ins,
                                                JSObject* obj2, PCVal pcval,
                                                uint32 *slotp, nanojit::LIns** v_insp,
                                                Value* outp);
-    JS_REQUIRES_STACK RecordingStatus denseArrayElement(Value& oval, Value& idx, Value*& vp,
+    JS_REQUIRES_STACK RecordingStatus denseArrayElement(Value& oval, Value& idx, const Value*& vp,
                                                         nanojit::LIns*& v_ins,
                                                         nanojit::LIns*& addr_ins,
                                                         VMSideExit* exit);
     JS_REQUIRES_STACK nanojit::LIns *canonicalizeNaNs(nanojit::LIns *dval_ins);
     JS_REQUIRES_STACK AbortableRecordingStatus typedArrayElement(Value& oval, Value& idx, Value*& vp,
                                                                  nanojit::LIns*& v_ins);
     JS_REQUIRES_STACK AbortableRecordingStatus getProp(JSObject* obj, nanojit::LIns* obj_ins);
     JS_REQUIRES_STACK AbortableRecordingStatus getProp(Value& v);
@@ -1633,17 +1633,17 @@ class TraceRecorder
 
     bool globalSetExpected(unsigned slot) {
         unsigned *pi = Find(pendingGlobalSlotsToSet, slot);
         if (pi == pendingGlobalSlotsToSet.end()) {
             /*
              * Do slot arithmetic manually to avoid getSlotRef assertions which
              * do not need to be satisfied for this purpose.
              */
-            Value *vp = globalObj->getSlots() + slot;
+            const Value *vp = &globalObj->getSlot(slot);
 
             /* If this global is definitely being tracked, then the write is unexpected. */
             if (tracker.has(vp))
                 return false;
             
             /*
              * Otherwise, only abort if the global is not present in the
              * import typemap. Just deep aborting false here is not acceptable,
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -153,27 +153,27 @@ static inline JSBool
 AllocateSlots(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->slots = tmpslots;
+        obj->setSlotsPtr(tmpslots);
         /*
          * Note that |bytes| may not be a multiple of |sizeof(Value)|, so
          * |capacity * sizeof(Value)| may underestimate the size by up to
          * |sizeof(Value) - 1| bytes.
          */
         obj->capacity = bytes / sizeof(Value);
     } else {
-        memset(obj->slots, 0, bytes);
+        memset(obj->getSlotsPtr(), 0, bytes);
     }
-    *((uint32*)obj->slots) = size;
+    *((uint32*)obj->getSlotsPtr()) = size;
     return true;
 }
 
 static JSObject *
 DelegateObject(JSContext *cx, JSObject *obj)
 {
     if (!obj->getPrivate()) {
         JSObject *delegate = NewNonFunction<WithProto::Given>(cx, &js_ObjectClass, obj->getProto(), NULL);
@@ -1317,17 +1317,17 @@ class TypedArrayTemplate
 
         JS_ASSERT(offset <= thisTypedArray->length);
         JS_ASSERT(len <= thisTypedArray->length - offset);
         NativeType *dest = static_cast<NativeType*>(thisTypedArray->data) + offset;
 
         if (ar->isDenseArray() && ar->getDenseArrayCapacity() >= len) {
             JS_ASSERT(ar->getArrayLength() == len);
 
-            Value *src = ar->getDenseArrayElements();
+            const Value *src = ar->getDenseArrayElements();
 
             for (uintN i = 0; i < len; ++i)
                 *dest++ = nativeFromValue(cx, *src++);
         } else {
             // slow path
             Value v;
 
             for (uintN i = 0; i < len; ++i) {
@@ -1837,24 +1837,23 @@ js_IsArrayBuffer(JSObject *obj)
 {
     JS_ASSERT(obj);
     return obj->getClass() == &ArrayBuffer::fastClass;
 }
 
 JSUint32
 JS_GetArrayBufferByteLength(JSObject *obj)
 {
-    return *((JSUint32*) obj->slots);
+    return ArrayBuffer::getByteLength(obj);
 }
 
 uint8 *
 JS_GetArrayBufferData(JSObject *obj)
 {
-    uint64 *base = ((uint64*)obj->slots) + 1;
-    return (uint8*) base;
+    return ArrayBuffer::getDataOffset(obj);
 }
 
 JS_FRIEND_API(JSBool)
 js_IsTypedArray(JSObject *obj)
 {
     JS_ASSERT(obj);
     Class *clasp = obj->getClass();
     return clasp >= &TypedArray::fastClasses[0] &&
--- a/js/src/jstypedarrayinlines.h
+++ b/js/src/jstypedarrayinlines.h
@@ -43,18 +43,18 @@
 #include "jsapi.h"
 #include "jsvalue.h"
 #include "jsobj.h"
 
 namespace js {
 inline JSUint32
 ArrayBuffer::getByteLength(JSObject *obj)
 {
-    return *((JSUint32*) obj->slots);
+    return *((JSUint32*) obj->getSlotsPtr());
 }
 
 inline uint8 *
 ArrayBuffer::getDataOffset(JSObject *obj) {
-    uint64 *base = ((uint64*)obj->slots) + 1;
+    uint64 *base = ((uint64*)obj->getSlotsPtr()) + 1;
     return (uint8*) base;
 }
 }
 #endif /* jstypedarrayinlines_h */
--- a/js/src/jsvalue.h
+++ b/js/src/jsvalue.h
@@ -847,16 +847,24 @@ ObjectOrNullValue(JSObject *obj)
 static JS_ALWAYS_INLINE Value
 PrivateValue(void *ptr)
 {
     Value v;
     v.setPrivate(ptr);
     return v;
 }
 
+static JS_ALWAYS_INLINE Value
+PrivateUint32Value(uint32 ui)
+{
+    Value v;
+    v.setPrivateUint32(ui);
+    return v;
+}
+
 static JS_ALWAYS_INLINE void
 ClearValueRange(Value *vec, uintN len, bool useHoles)
 {
     if (useHoles) {
         for (uintN i = 0; i < len; i++)
             vec[i].setMagic(JS_ARRAY_HOLE);
     } else {
         for (uintN i = 0; i < len; i++)
--- a/js/src/methodjit/BaseAssembler.h
+++ b/js/src/methodjit/BaseAssembler.h
@@ -254,17 +254,17 @@ static const JSC::MacroAssembler::Regist
         return branchPtr(cond, Address(fun, offsetof(JSObject, clasp)),
                          ImmPtr(&js_FunctionClass));
     }
 
     /*
      * Finds and returns the address of a known object and slot.
      */
     Address objSlotRef(JSObject *obj, RegisterID reg, uint32 slot) {
-        move(ImmPtr(&obj->slots), reg);
+        move(ImmPtr((char *)obj + JSObject::offsetOfSlots()), reg);
         loadPtr(reg, reg);
         return Address(reg, slot * sizeof(Value));
     }
 
     /* Prepare for a call that might THROW. */
     void *getFallibleCallTarget(void *fun) {
 #ifdef JS_CPU_ARM
         /*
@@ -667,17 +667,17 @@ static const JSC::MacroAssembler::Regist
     FastArrayLoadFails fastArrayLoad(RegisterID objReg, const Int32Key &key,
                                      RegisterID typeReg, RegisterID dataReg) {
         JS_ASSERT(objReg != typeReg);
 
         FastArrayLoadFails fails;
         fails.rangeCheck = guardArrayCapacity(objReg, key);
 
         RegisterID dslotsReg = objReg;
-        loadPtr(Address(objReg, offsetof(JSObject, slots)), dslotsReg);
+        loadPtr(Address(objReg, JSObject::offsetOfSlots()), dslotsReg);
 
         // Load the slot out of the array.
         if (key.isConstant()) {
             Address slot(objReg, key.index() * sizeof(Value));
             fails.holeCheck = fastArrayLoadSlot(slot, typeReg, dataReg);
         } else {
             BaseIndex slot(objReg, key.reg(), JSVAL_SCALE);
             fails.holeCheck = fastArrayLoadSlot(slot, typeReg, dataReg);
@@ -702,17 +702,17 @@ static const JSC::MacroAssembler::Regist
         if (remat.inMemory())
             loadPayload(remat.address(), reg);
         else
             move(remat.reg(), reg);
     }
 
     void loadDynamicSlot(RegisterID objReg, uint32 slot,
                          RegisterID typeReg, RegisterID dataReg) {
-        loadPtr(Address(objReg, offsetof(JSObject, slots)), dataReg);
+        loadPtr(Address(objReg, JSObject::offsetOfSlots()), dataReg);
         loadValueAsComponents(Address(dataReg, slot * sizeof(Value)), typeReg, dataReg);
     }
 
     void loadObjProp(JSObject *obj, RegisterID objReg,
                      const js::Shape *shape,
                      RegisterID typeReg, RegisterID dataReg)
     {
         if (shape->isMethod())
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -4834,17 +4834,17 @@ mjit::Compiler::enterBlock(JSObject *obj
     uint32 n = js_GetEnterBlockStackDefs(cx, script, PC);
     INLINE_STUBCALL(stubs::EnterBlock);
     frame.enterBlock(n);
 
     uintN base = JSSLOT_FREE(&js_BlockClass);
     uintN count = OBJ_BLOCK_COUNT(cx, obj);
     uintN limit = base + count;
     for (uintN slot = base, i = 0; slot < limit; slot++, i++) {
-        const Value &v = obj->getSlotRef(slot);
+        const Value &v = obj->getSlot(slot);
         if (v.isBoolean() && v.toBoolean())
             frame.setClosedVar(oldFrameDepth + i);
     }
 }
 
 void
 mjit::Compiler::leaveBlock()
 {
--- a/js/src/methodjit/MonoIC.cpp
+++ b/js/src/methodjit/MonoIC.cpp
@@ -195,30 +195,30 @@ AttachSetGlobalNameStub(VMFrame &f, ic::
         masm.move(ImmPtr(obj), ic->objReg);
 
     JS_ASSERT(obj->branded());
 
     /*
      * Load obj->slots. If ic->objConst, then this clobbers objReg, because
      * ic->objReg == ic->shapeReg.
      */
-    masm.loadPtr(Address(ic->objReg, offsetof(JSObject, slots)), ic->shapeReg);
+    masm.loadPtr(Address(ic->objReg, JSObject::offsetOfSlots()), ic->shapeReg);
 
     /* Test if overwriting a function-tagged slot. */
     Address slot(ic->shapeReg, sizeof(Value) * shape->slot);
     Jump isNotObject = masm.testObject(Assembler::NotEqual, slot);
 
     /* Now, test if the object is a function object. */
     masm.loadPayload(slot, ic->shapeReg);
     Jump isFun = masm.testFunction(Assembler::Equal, ic->shapeReg);
 
     /* Restore shapeReg to obj->slots, since we clobbered it. */
     if (ic->objConst)
         masm.move(ImmPtr(obj), ic->objReg);
-    masm.loadPtr(Address(ic->objReg, offsetof(JSObject, slots)), ic->shapeReg);
+    masm.loadPtr(Address(ic->objReg, JSObject::offsetOfSlots()), ic->shapeReg);
 
     /* If the object test fails, shapeReg is still obj->slots. */
     isNotObject.linkTo(masm.label(), &masm);
     DataLabel32 store = masm.storeValueWithAddressOffsetPatch(ic->vr, slot);
 
     Jump done = masm.jump();
 
     JITScript *jit = f.jit();
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -232,17 +232,17 @@ class SetPropCompiler : public PICStubCo
             //
             // We've patched | mov dslots, [obj + DSLOTS_OFFSET]
             // To:           | lea fslots, [obj + DSLOTS_OFFSET]
             //
             // Because the offset is wrong, it's necessary to correct it
             // below.
             //
             int32 diff = int32(JSObject::getFixedSlotOffset(0)) -
-                         int32(offsetof(JSObject, slots));
+                         int32(JSObject::offsetOfSlots());
             JS_ASSERT(diff != 0);
             offset  = (int32(shape->slot) * sizeof(Value)) + diff;
         } else {
             offset = shape->slot * sizeof(Value);
         }
 
         repatcher.repatch(labels.getInlineShapeData(pic.fastPathStart, pic.shapeGuard),
                           obj->shape());
@@ -348,17 +348,17 @@ class SetPropCompiler : public PICStubCo
                 /* Check capacity. */
                 Address capacity(pic.objReg, offsetof(JSObject, capacity));
                 masm.load32(capacity, pic.shapeReg);
                 Jump overCapacity = masm.branch32(Assembler::LessThanOrEqual, pic.shapeReg,
                                                   Imm32(shape->slot));
                 if (!slowExits.append(overCapacity))
                     return error();
 
-                masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.shapeReg);
+                masm.loadPtr(Address(pic.objReg, JSObject::offsetOfSlots()), pic.shapeReg);
                 Address address(pic.shapeReg, shape->slot * sizeof(Value));
                 masm.storeValue(pic.u.vr, address);
             }
 
             uint32 newShape = obj->shape();
             JS_ASSERT(newShape != initialShape);
 
             /* Write the object's new shape. */
@@ -372,17 +372,17 @@ class SetPropCompiler : public PICStubCo
                 /* Use shapeReg to load, bitwise-or, and store flags. */
                 masm.load32(flags, pic.shapeReg);
                 masm.or32(Imm32(JSObject::METHOD_BARRIER), pic.shapeReg);
                 masm.store32(pic.shapeReg, flags);
             }
         } else if (shape->hasDefaultSetter()) {
             Address address(pic.objReg, JSObject::getFixedSlotOffset(shape->slot));
             if (!inlineSlot) {
-                masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.objReg);
+                masm.loadPtr(Address(pic.objReg, JSObject::offsetOfSlots()), pic.objReg);
                 address = Address(pic.objReg, shape->slot * sizeof(Value));
             }
 
             // If the scope is branded, or has a method barrier. It's now necessary
             // to guard that we're not overwriting a function-valued property.
             if (obj->brandedOrHasMethodBarrier()) {
                 masm.loadTypeTag(address, pic.shapeReg);
                 Jump skip = masm.testObject(Assembler::NotEqual, pic.shapeReg);
@@ -417,17 +417,17 @@ class SetPropCompiler : public PICStubCo
                 masm.storeValue(pic.u.vr, addr);
                 skipOver = masm.jump();
             }
 
             escapedFrame.linkTo(masm.label(), &masm);
             {
                 if (shape->setterOp() == SetCallVar)
                     slot += fun->nargs;
-                masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.objReg);
+                masm.loadPtr(Address(pic.objReg, JSObject::offsetOfSlots()), pic.objReg);
 
                 Address dslot(pic.objReg, (slot + JSObject::CALL_RESERVED_SLOTS) * sizeof(Value));
                 masm.storeValue(pic.u.vr, dslot);
             }
 
             pic.shapeRegHasBaseShape = false;
         }
 
@@ -1413,17 +1413,17 @@ class ScopeNameCompiler : public PICStub
             masm.loadPayload(addr, pic.objReg);
             masm.loadTypeTag(addr, pic.shapeReg);
             skipOver = masm.jump();
         }
 
         escapedFrame.linkTo(masm.label(), &masm);
 
         {
-            masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.objReg);
+            masm.loadPtr(Address(pic.objReg, JSObject::offsetOfSlots()), pic.objReg);
 
             if (kind == VAR)
                 slot += fun->nargs;
             Address dslot(pic.objReg, (slot + JSObject::CALL_RESERVED_SLOTS) * sizeof(Value));
 
             /* Safe because type is loaded first. */
             masm.loadValueAsComponents(dslot, pic.shapeReg, pic.objReg);
         }
@@ -2750,17 +2750,17 @@ SetElementIC::attachHoleStub(JSContext *
         skipUpdate = masm.branch32(Assembler::Above, arrayLength, keyReg);
         masm.add32(Imm32(1), keyReg);
         masm.store32(keyReg, arrayLength);
         masm.sub32(Imm32(1), keyReg);
     }
     skipUpdate.linkTo(masm.label(), &masm);
 
     // Store the value back.
-    masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
+    masm.loadPtr(Address(objReg, JSObject::offsetOfSlots()), objReg);
     if (hasConstantKey) {
         Address slot(objReg, keyValue * sizeof(Value));
         masm.storeValue(vr, slot);
     } else {
         BaseIndex slot(objReg, keyReg, Assembler::JSVAL_SCALE);
         masm.storeValue(vr, slot);
     }
 
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -439,26 +439,26 @@ stubs::GetElem(VMFrame &f)
     jsid id;
     if (rref.isInt32()) {
         int32_t i = rref.toInt32();
         if (obj->isDenseArray()) {
             jsuint idx = jsuint(i);
 
             if (idx < obj->getArrayLength() &&
                 idx < obj->getDenseArrayCapacity()) {
-                copyFrom = obj->addressOfDenseArrayElement(idx);
+                copyFrom = &obj->getDenseArrayElement(idx);
                 if (!copyFrom->isMagic())
                     goto end_getelem;
             }
         } else if (obj->isArguments()) {
             uint32 arg = uint32(i);
             ArgumentsObject *argsobj = obj->asArguments();
 
             if (arg < argsobj->initialLength()) {
-                copyFrom = argsobj->addressOfElement(arg);
+                copyFrom = &argsobj->element(arg);
                 if (!copyFrom->isMagic()) {
                     if (StackFrame *afp = (StackFrame *) argsobj->getPrivate())
                         copyFrom = &afp->canonicalActualArg(arg);
                     goto end_getelem;
                 }
             }
         }
         if (JS_LIKELY(INT_FITS_IN_JSID(i)))
@@ -1541,23 +1541,23 @@ NameIncDec(VMFrame &f, JSObject *obj, JS
     JSAtom *atom;
     JSObject *obj2;
     JSProperty *prop;
     PropertyCacheEntry *entry;
     JS_PROPERTY_CACHE(cx).test(cx, f.regs.pc, obj, obj2, entry, atom);
     if (!atom) {
         if (obj == obj2 && entry->vword.isSlot()) {
             uint32 slot = entry->vword.toSlot();
-            Value &rref = obj->nativeGetSlotRef(slot);
+            const Value &rval = obj->nativeGetSlot(slot);
             int32_t tmp;
-            if (JS_LIKELY(rref.isInt32() && CanIncDecWithoutOverflow(tmp = rref.toInt32()))) {
+            if (JS_LIKELY(rval.isInt32() && CanIncDecWithoutOverflow(tmp = rval.toInt32()))) {
                 int32_t inc = tmp + N;
                 if (!POST)
                     tmp = inc;
-                rref.getInt32Ref() = inc;
+                obj->nativeSetSlot(slot, Int32Value(inc));
                 f.regs.sp[0].setInt32(tmp);
                 return true;
             }
         }
         atom = origAtom;
     }
 
     jsid id = ATOM_TO_JSID(atom);
--- a/js/src/tracejit/Writer.h
+++ b/js/src/tracejit/Writer.h
@@ -524,17 +524,17 @@ class Writer
 
     nj::LIns *ldiDenseArrayCapacity(nj::LIns *array) const {
         return name(lir->insLoad(nj::LIR_ldi, array, offsetof(JSObject, capacity),
                                  ACCSET_OBJ_CAPACITY),
                     "capacity");
     }
 
     nj::LIns *ldpObjSlots(nj::LIns *obj) const {
-        return name(lir->insLoad(nj::LIR_ldp, obj, offsetof(JSObject, slots), ACCSET_OBJ_SLOTS),
+        return name(lir->insLoad(nj::LIR_ldp, obj, JSObject::offsetOfSlots(), ACCSET_OBJ_SLOTS),
                     "slots");
     }
 
     nj::LIns *ldiConstTypedArrayLength(nj::LIns *array) const {
         return name(lir->insLoad(nj::LIR_ldi, array, js::TypedArray::lengthOffset(), ACCSET_TARRAY,
                                  nj::LOAD_CONST),
                     "typedArrayLength");
     }
--- a/js/src/vm/ArgumentsObject-inl.h
+++ b/js/src/vm/ArgumentsObject-inl.h
@@ -60,17 +60,18 @@ ArgumentsObject::initialLength() const
     uint32 argc = uint32(getSlot(INITIAL_LENGTH_SLOT).toInt32()) >> PACKED_BITS_COUNT;
     JS_ASSERT(argc <= StackSpace::ARGS_LENGTH_MAX);
     return argc;
 }
 
 inline void
 ArgumentsObject::markLengthOverridden()
 {
-    getSlotRef(INITIAL_LENGTH_SLOT).getInt32Ref() |= LENGTH_OVERRIDDEN_BIT;
+    uint32 v = getSlot(INITIAL_LENGTH_SLOT).toInt32() | LENGTH_OVERRIDDEN_BIT;
+    setSlot(INITIAL_LENGTH_SLOT, Int32Value(v));
 }
 
 inline bool
 ArgumentsObject::hasOverriddenLength() const
 {
     const js::Value &v = getSlot(INITIAL_LENGTH_SLOT);
     return v.toInt32() & LENGTH_OVERRIDDEN_BIT;
 }
@@ -91,29 +92,22 @@ ArgumentsObject::data() const
 
 inline const js::Value &
 ArgumentsObject::element(uint32 i) const
 {
     JS_ASSERT(i < initialLength());
     return data()->slots[i];
 }
 
-inline js::Value *
+inline const js::Value *
 ArgumentsObject::elements() const
 {
     return data()->slots;
 }
 
-inline Value *
-ArgumentsObject::addressOfElement(uint32 i)
-{
-    JS_ASSERT(i < initialLength());
-    return &data()->slots[i];
-}
-
 inline void
 ArgumentsObject::setElement(uint32 i, const js::Value &v)
 {
     JS_ASSERT(i < initialLength());
     data()->slots[i] = v;
 }
 
 inline const js::Value &
--- a/js/src/vm/ArgumentsObject.h
+++ b/js/src/vm/ArgumentsObject.h
@@ -222,18 +222,17 @@ class ArgumentsObject : public ::JSObjec
      *
      * NB: Returning false does not indicate error!
      */
     inline bool getElements(uint32 start, uint32 count, js::Value *vp);
 
     inline js::ArgumentsData *data() const;
 
     inline const js::Value &element(uint32 i) const;
-    inline js::Value *elements() const;
-    inline js::Value *addressOfElement(uint32 i);
+    inline const js::Value *elements() const;
     inline void setElement(uint32 i, const js::Value &v);
 };
 
 /*
  * Non-strict arguments have a private: the function's stack frame until the
  * function returns, when it is replaced with null.  When an arguments object
  * is created on-trace its private is JS_ARGUMENTS_OBJECT_ON_TRACE, and when
  * the trace exits its private is replaced with the stack frame or null, as
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -191,18 +191,18 @@ GlobalObject::isRuntimeCodeGenEnabled(JS
     Value &v = getSlotRef(RUNTIME_CODEGEN_ENABLED);
     if (v.isUndefined()) {
         JSSecurityCallbacks *callbacks = JS_GetSecurityCallbacks(cx);
 
         /*
          * If there are callbacks, make sure that the CSP callback is installed
          * and that it permits runtime code generation, then cache the result.
          */
-        v.setBoolean((!callbacks || !callbacks->contentSecurityPolicyAllows) ||
-                     callbacks->contentSecurityPolicyAllows(cx));
+        v = BooleanValue((!callbacks || !callbacks->contentSecurityPolicyAllows) ||
+                         callbacks->contentSecurityPolicyAllows(cx));
     }
     return !v.isFalse();
 }
 
 JSFunction *
 GlobalObject::createConstructor(JSContext *cx, Native ctor, Class *clasp, JSAtom *name,
                                 uintN length)
 {
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -124,21 +124,21 @@ class GlobalObject : public ::JSObject {
      * prototype objects with particular internal structure (e.g. reserved
      * slots guaranteed to contain values of particular types) must immediately
      * complete the minimal initialization to make the returned object safe to
      * touch.
      */
     JSObject *createBlankPrototype(JSContext *cx, js::Class *clasp);
 
     void setThrowTypeError(JSFunction *fun) {
-        Value &v = getSlotRef(THROWTYPEERROR);
         // Our bootstrapping code is currently too convoluted to correctly and
         // confidently assert this.
         // JS_ASSERT(v.isUndefined());
-        v.setObject(*fun);
+        // JS_ASSERT(getSlot(THROWTYPEERROR).isUndefined());
+        setSlot(THROWTYPEERROR, ObjectValue(*fun));
     }
 
     JSObject *getThrowTypeError() const {
         return &getSlot(THROWTYPEERROR).toObject();
     }
 
     Value getRegExpStatics() const {
         return getSlot(REGEXP_STATICS);
@@ -152,21 +152,21 @@ class GlobalObject : public ::JSObject {
 
     bool isRuntimeCodeGenEnabled(JSContext *cx);
 
     const Value &getOriginalEval() const {
         return getSlot(EVAL);
     }
 
     void setOriginalEval(JSObject *evalobj) {
-        Value &v = getSlotRef(EVAL);
         // Our bootstrapping code is currently too convoluted to correctly and
         // confidently assert this.
         // JS_ASSERT(v.isUndefined());
-        v.setObject(*evalobj);
+        // JS_ASSERT(getSlot(EVAL).isUndefined());
+        setSlot(EVAL, ObjectValue(*evalobj));
     }
 
     bool getFunctionNamespace(JSContext *cx, Value *vp);
 
     bool initStandardClasses(JSContext *cx);
 };
 
 /*
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -595,19 +595,20 @@ ArgumentsObject::getElements(uint32 star
     uint32 length = initialLength();
     if (start > length || start + count > length)
         return false;
 
     StackFrame *fp = reinterpret_cast<StackFrame *>(getPrivate());
 
     /* If there's no stack frame for this, argument values are in elements(). */
     if (!fp) {
-        Value *srcbeg = elements() + start;
-        Value *srcend = srcbeg + count;
-        for (Value *dst = vp, *src = srcbeg; src < srcend; ++dst, ++src) {
+        const Value *srcbeg = elements() + start;
+        const Value *srcend = srcbeg + count;
+        const Value *src = srcbeg;
+        for (Value *dst = vp; src < srcend; ++dst, ++src) {
             if (src->isMagic(JS_ARGS_HOLE))
                 return false;
             *dst = *src;
         }
         return true;
     }
 
     /* If we're on trace, there's no canonical location for elements: fail. */