Make JSObject::doSomethingToThisObject methods static, bug 782646. r=terrence
authorBrian Hackett <bhackett1024@gmail.com>
Tue, 21 Aug 2012 13:13:28 -0600
changeset 104936 bf1a005f1e61d7e3861b644b5db1953d487792a0
parent 104935 987f760ee458f2587ba1fc0697cad8c0c5ebe9cb
child 104937 a8d115b3b7e11865bae4b7502d76c9f038a13f66
push id45
push usershu@rfrn.org
push dateThu, 23 Aug 2012 00:57:43 +0000
reviewersterrence
bugs782646
milestone17.0a1
Make JSObject::doSomethingToThisObject methods static, bug 782646. r=terrence
js/src/builtin/Eval.cpp
js/src/builtin/MapObject.cpp
js/src/builtin/ParallelArray.cpp
js/src/builtin/RegExp.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsarray.h
js/src/jsbool.cpp
js/src/jsclone.cpp
js/src/jsdate.cpp
js/src/jsexn.cpp
js/src/jsfriendapi.cpp
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsgc.cpp
js/src/jsinfer.cpp
js/src/jsinferinlines.h
js/src/jsinterp.cpp
js/src/jsinterpinlines.h
js/src/jsiter.cpp
js/src/jsmath.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/json.cpp
js/src/jsproxy.cpp
js/src/jsreflect.cpp
js/src/jsscope.cpp
js/src/jsstr.cpp
js/src/jstypedarray.cpp
js/src/jstypedarrayinlines.h
js/src/jsxml.cpp
js/src/methodjit/Compiler.cpp
js/src/methodjit/MonoIC.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/shell/js.cpp
js/src/vm/Debugger.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/ScopeObject.cpp
--- a/js/src/builtin/Eval.cpp
+++ b/js/src/builtin/Eval.cpp
@@ -192,17 +192,17 @@ EvalKernel(JSContext *cx, const CallArgs
         if (!ComputeThis(cx, caller))
             return false;
         thisv = caller->thisValue();
     } else {
         JS_ASSERT(args.callee().global() == *scopeobj);
         staticLevel = 0;
 
         // Use the global as 'this', modulo outerization.
-        JSObject *thisobj = scopeobj->thisObject(cx);
+        JSObject *thisobj = JSObject::thisObject(cx, scopeobj);
         if (!thisobj)
             return false;
         thisv = ObjectValue(*thisobj);
     }
 
     Rooted<JSLinearString*> linearStr(cx, str->ensureLinear(cx));
     if (!linearStr)
         return false;
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -972,26 +972,26 @@ MapObject::construct(JSContext *cx, unsi
     if (args.hasDefined(0)) {
         ForOfIterator iter(cx, args[0]);
         while (iter.next()) {
             RootedObject pairobj(cx, js_ValueToNonNullObject(cx, iter.value()));
             if (!pairobj)
                 return false;
 
             RootedValue key(cx);
-            if (!pairobj->getElement(cx, 0, &key))
+            if (!JSObject::getElement(cx, pairobj, pairobj, 0, &key))
                 return false;
             HashableValue hkey;
             if (!hkey.setValue(cx, key))
                 return false;
 
             HashableValue::AutoRooter hkeyRoot(cx, &hkey);
 
             RootedValue val(cx);
-            if (!pairobj->getElement(cx, 1, &val))
+            if (!JSObject::getElement(cx, pairobj, pairobj, 1, &val))
                 return false;
 
             RelocatableValue rval(val);
             if (!map->put(hkey, rval)) {
                 js_ReportOutOfMemory(cx);
                 return false;
             }
         }
--- a/js/src/builtin/ParallelArray.cpp
+++ b/js/src/builtin/ParallelArray.cpp
@@ -72,17 +72,17 @@ MaybeGetParallelArrayObjectAndLength(JSC
                                      MutableHandle<ParallelArrayObject *> pa,
                                      IndexInfo *iv, uint32_t *length)
 {
     if (ParallelArrayObject::is(obj)) {
         pa.set(ParallelArrayObject::as(obj));
         if (!pa->isOneDimensional() && !iv->initialize(cx, pa, 1))
             return false;
         *length = pa->outermostDimension();
-    } else if (!js_GetLengthProperty(cx, obj, length)) {
+    } else if (!GetLengthProperty(cx, obj, length)) {
         return false;
     }
 
     return true;
 }
 
 // Store the i-th element of the array-like object obj into vp.
 //
@@ -115,17 +115,17 @@ GetElementFromArrayLikeObject(JSContext 
     }
 
     if (obj->isArguments()) {
         if (obj->asArguments().maybeGetElement(static_cast<uint32_t>(i), vp))
             return true;
     }
 
     bool present;
-    if (!obj->getElementIfPresent(cx, obj, i, vp, &present))
+    if (!JSObject::getElementIfPresent(cx, obj, obj, i, vp, &present))
         return false;
     if (!present)
         vp.setUndefined();
 
     return true;
 }
 
 // Copy an array like object obj into an IndexVector, indices, using
@@ -658,17 +658,17 @@ ParallelArrayObject::DebugOptions::init(
 
     RootedObject obj(cx, &v.toObject());
     RootedId id(cx);
     RootedValue propv(cx);
     JSString *propStr;
     JSBool match = false;
 
     id = AtomToId(Atomize(cx, "mode", strlen("mode")));
-    if (!obj->getGeneric(cx, id, &propv))
+    if (!JSObject::getGeneric(cx, obj, obj, id, &propv))
         return false;
 
     propStr = ToString(cx, propv);
     if (!JS_StringEqualsAscii(cx, propStr, "par", &match))
         return false;
     if (match) {
         mode = &parallel;
     } else {
@@ -676,17 +676,17 @@ ParallelArrayObject::DebugOptions::init(
             return false;
         if (match)
             mode = &sequential;
         else
             return false;
     }
 
     id = AtomToId(Atomize(cx, "expect", strlen("expect")));
-    if (!obj->getGeneric(cx, id, &propv))
+    if (!JSObject::getGeneric(cx, obj, obj, id, &propv))
         return false;
 
     propStr = ToString(cx, propv);
     if (!JS_StringEqualsAscii(cx, propStr, "fail", &match))
         return false;
     if (match) {
         expect = ExecutionFailed;
     } else {
@@ -1001,17 +1001,17 @@ ParallelArrayObject::construct(JSContext
             return false;
         }
 
         RootedObject source(cx, &(args[0].toObject()));
 
         // When using an array value we can only make one dimensional arrays.
         IndexVector dims(cx);
         uint32_t length;
-        if (!dims.resize(1) || !js_GetLengthProperty(cx, source, &length))
+        if (!dims.resize(1) || !GetLengthProperty(cx, source, &length))
             return false;
         dims[0] = length;
 
         RootedObject buffer(cx);
 
         // If the source is already a dense array, just copy it over
         // wholesale. Else copy it pointwise.
         if (source->isDenseArray()) {
@@ -1020,17 +1020,17 @@ ParallelArrayObject::construct(JSContext
                 return false;
         } else {
             buffer = NewDenseArrayWithType(cx, length);
             if (!buffer)
                 return false;
 
             RootedValue elem(cx);
             for (uint32_t i = 0; i < length; i++) {
-                if (!source->getElement(cx, i, &elem))
+                if (!JSObject::getElement(cx, source, source, i, &elem))
                     return false;
                 buffer->setDenseArrayElementWithType(cx, i, elem);
             }
         }
 
         return create(cx, buffer, 0, dims, args.rval());
     }
 
@@ -1220,17 +1220,17 @@ ParallelArrayObject::scatter(JSContext *
     }
 
     RootedParallelArrayObject obj(cx, as(&args.thisv().toObject()));
     uint32_t outer = obj->outermostDimension();
 
     // Get the scatter vector.
     RootedObject targets(cx, &args[0].toObject());
     uint32_t targetsLength;
-    if (!js_GetLengthProperty(cx, targets, &targetsLength))
+    if (!GetLengthProperty(cx, targets, &targetsLength))
         return false;
 
     // Don't iterate more than the length of the source array.
     if (targetsLength > outer)
         targetsLength = outer;
 
     // The default value is optional and defaults to undefined.
     Value defaultValue;
@@ -1404,34 +1404,34 @@ ParallelArrayObject::get(JSContext *cx, 
 
     RootedParallelArrayObject obj(cx, as(&args.thisv().toObject()));
     RootedObject indicesObj(cx, &(args[0].toObject()));
 
     if (obj->isOneDimensional()) {
         uint32_t length;
         if (is(indicesObj))
             length = as(indicesObj)->outermostDimension();
-        else if (!js_GetLengthProperty(cx, indicesObj, &length))
+        else if (!GetLengthProperty(cx, indicesObj, &length))
             return false;
 
         // If we're one dimensional, the index vector must also be one
         // dimensional.
         if (length != 1) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PAR_ARRAY_BAD_ARG,
                                  ".prototype.get");
             return false;
         }
 
         RootedValue elem(cx);
         uint32_t index;
         if (is(indicesObj)) {
             if (!as(indicesObj)->getParallelArrayElement(cx, 0, &elem))
                 return false;
         } else {
-            if (!indicesObj->getElement(cx, 0, &elem))
+            if (!JSObject::getElement(cx, indicesObj, indicesObj, 0, &elem))
                 return false;
         }
 
         if (!ToUint32(cx, elem, &index))
             return false;
 
         return obj->getElementFromOnlyDimension(cx, index, args.rval());
     }
@@ -1609,19 +1609,19 @@ ParallelArrayObject::lookupGeneric(JSCon
 {
     if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) ||
         as(obj)->inOutermostDimensionRange(cx, id)) {
         MarkNonNativePropertyFound(obj, propp);
         objp.set(obj);
         return true;
     }
 
-    if (JSObject *proto = obj->getProto()) {
-        return proto->lookupGeneric(cx, id, objp, propp);
-    }
+    RootedObject proto(cx, obj->getProto());
+    if (proto)
+        return JSObject::lookupGeneric(cx, proto, id, objp, propp);
 
     objp.set(NULL);
     propp.set(NULL);
     return true;
 }
 
 JSBool
 ParallelArrayObject::lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
@@ -1636,18 +1636,19 @@ ParallelArrayObject::lookupElement(JSCon
                                    MutableHandleObject objp, MutableHandleShape propp)
 {
     if (as(obj)->inOutermostDimensionRange(index)) {
         MarkNonNativePropertyFound(obj, propp);
         objp.set(obj);
         return true;
     }
 
-    if (JSObject *proto = obj->getProto())
-        return proto->lookupElement(cx, index, objp, propp);
+    RootedObject proto(cx, obj->getProto());
+    if (proto)
+        return JSObject::lookupElement(cx, proto, index, objp, propp);
 
     objp.set(NULL);
     propp.set(NULL);
     return true;
 }
 
 JSBool
 ParallelArrayObject::lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
@@ -1717,36 +1718,38 @@ JSBool
 ParallelArrayObject::getProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
                                  HandlePropertyName name, MutableHandleValue vp)
 {
     if (name == cx->runtime->atomState.lengthAtom) {
         vp.setNumber(as(obj)->outermostDimension());
         return true;
     }
 
-    if (JSObject *proto = obj->getProto())
-        return proto->getProperty(cx, receiver, name, vp);
+    RootedObject proto(cx, obj->getProto());
+    if (proto)
+        return JSObject::getProperty(cx, proto, receiver, name, vp);
 
     vp.setUndefined();
     return true;
 }
 
 JSBool
 ParallelArrayObject::getElement(JSContext *cx, HandleObject obj, HandleObject receiver,
                                 uint32_t index, MutableHandleValue vp)
 {
     RootedParallelArrayObject source(cx, as(obj));
     if (source->inOutermostDimensionRange(index)) {
         if (source->isOneDimensional())
             return source->getElementFromOnlyDimension(cx, index, vp);
         return source->getParallelArrayElement(cx, index, vp);
     }
 
-    if (JSObject *proto = obj->getProto())
-        return proto->getElement(cx, receiver, index, vp);
+    RootedObject proto(cx, obj->getProto());
+    if (proto)
+        return JSObject::getElement(cx, proto, receiver, index, vp);
 
     vp.setUndefined();
     return true;
 }
 
 JSBool
 ParallelArrayObject::getSpecial(JSContext *cx, HandleObject obj, HandleObject receiver,
                                 HandleSpecialId sid, MutableHandleValue vp)
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -214,42 +214,42 @@ CompileRegExpObject(JSContext *cx, RegEx
      * "RegExp", return a new object with the same source/flags.
      */
     if (IsObjectWithClass(sourceValue, ESClass_RegExp, cx)) {
         /*
          * Beware, sourceObj may be a (transparent) proxy to a RegExp, so only
          * use generic (proxyable) operations on sourceObj that do not assume
          * sourceObj.isRegExp().
          */
-        JSObject &sourceObj = sourceValue.toObject();
+        RootedObject sourceObj(cx, &sourceValue.toObject());
 
         if (args.hasDefined(1)) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEWREGEXP_FLAGGED);
             return false;
         }
 
         /*
          * Only extract the 'flags' out of sourceObj; do not reuse the
          * RegExpShared since it may be from a different compartment.
          */
         RegExpFlag flags;
         {
             RegExpGuard g;
-            if (!RegExpToShared(cx, sourceObj, &g))
+            if (!RegExpToShared(cx, *sourceObj, &g))
                 return false;
 
             flags = g->getFlags();
         }
 
         /*
          * 'toSource' is a permanent read-only property, so this is equivalent
          * to executing RegExpObject::getSource on the unwrapped object.
          */
         RootedValue v(cx);
-        if (!sourceObj.getProperty(cx, cx->runtime->atomState.sourceAtom, &v))
+        if (!JSObject::getProperty(cx, sourceObj, sourceObj, cx->runtime->atomState.sourceAtom, &v))
             return false;
 
         Rooted<JSAtom*> sourceAtom(cx, &v.toString()->asAtom());
         RegExpObject *reobj = builder.build(sourceAtom, flags);
         if (!reobj)
             return false;
 
         args.rval().setObject(*reobj);
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -2656,17 +2656,17 @@ frontend::EmitFunctionScript(JSContext *
         bce->parent &&
         bce->parent->checkSingletonContext();
 
     /* Initialize fun->script() so that the debugger has a valid fun->script(). */
     RootedFunction fun(cx, bce->script->function());
     JS_ASSERT(fun->isInterpreted());
     JS_ASSERT(!fun->script());
     fun->setScript(bce->script);
-    if (!fun->setTypeForScriptedFunction(cx, singleton))
+    if (!JSFunction::setTypeForScriptedFunction(cx, fun, singleton))
         return false;
 
     bce->tellDebuggerAboutCompiledScript(cx);
 
     return true;
 }
 
 static bool
@@ -3733,17 +3733,17 @@ ParseNode::getConstantValue(JSContext *c
 
         unsigned idx = 0;
         RootedId id(cx);
         RootedValue value(cx);
         for (ParseNode *pn = pn_head; pn; idx++, pn = pn->pn_next) {
             if (!pn->getConstantValue(cx, strictChecks, value.address()))
                 return false;
             id = INT_TO_JSID(idx);
-            if (!obj->defineGeneric(cx, id, value, NULL, NULL, JSPROP_ENUMERATE))
+            if (!JSObject::defineGeneric(cx, obj, id, value, NULL, NULL, JSPROP_ENUMERATE))
                 return false;
         }
         JS_ASSERT(idx == pn_count);
 
         types::FixArrayType(cx, obj);
         vp->setObject(*obj);
         return true;
       }
@@ -3763,17 +3763,17 @@ ParseNode::getConstantValue(JSContext *c
             ParseNode *pnid = pn->pn_left;
             if (pnid->isKind(PNK_NUMBER)) {
                 Value idvalue = NumberValue(pnid->pn_dval);
                 RootedId id(cx);
                 if (idvalue.isInt32() && INT_FITS_IN_JSID(idvalue.toInt32()))
                     id = INT_TO_JSID(idvalue.toInt32());
                 else if (!InternNonIntElementId(cx, obj, idvalue, id.address()))
                     return false;
-                if (!obj->defineGeneric(cx, id, value, NULL, NULL, JSPROP_ENUMERATE))
+                if (!JSObject::defineGeneric(cx, obj, id, value, NULL, NULL, JSPROP_ENUMERATE))
                     return false;
             } else {
                 JS_ASSERT(pnid->isKind(PNK_NAME) || pnid->isKind(PNK_STRING));
                 JS_ASSERT(pnid->pn_atom != cx->runtime->atomState.protoAtom);
                 RootedId id(cx, AtomToId(pnid->pn_atom));
                 if (!DefineNativeProperty(cx, obj, id, value, NULL, NULL,
                                           JSPROP_ENUMERATE, 0, 0)) {
                     return false;
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1983,19 +1983,19 @@ JS_ResolveStandardClass(JSContext *cx, J
 
     idstr = JSID_TO_STRING(id);
 
     /* Check whether we're resolving 'undefined', and define it if so. */
     atom = rt->atomState.typeAtoms[JSTYPE_VOID];
     if (idstr == atom) {
         *resolved = true;
         RootedValue undefinedValue(cx, UndefinedValue());
-        return obj->defineProperty(cx, atom->asPropertyName(), undefinedValue,
-                                   JS_PropertyStub, JS_StrictPropertyStub,
-                                   JSPROP_PERMANENT | JSPROP_READONLY);
+        return JSObject::defineProperty(cx, obj, atom->asPropertyName(), undefinedValue,
+                                        JS_PropertyStub, JS_StrictPropertyStub,
+                                        JSPROP_PERMANENT | JSPROP_READONLY);
     }
 
     /* Try for class constructors/prototypes named by well-known atoms. */
     stdnm = NULL;
     for (i = 0; standard_class_atoms[i].init; i++) {
         JS_ASSERT(standard_class_atoms[i].clasp);
         atom = OFFSET_TO_NAME(rt, standard_class_atoms[i].atomOffset);
         if (idstr == atom) {
@@ -2076,19 +2076,19 @@ JS_EnumerateStandardClasses(JSContext *c
     /*
      * Check whether we need to bind 'undefined' and define it if so.
      * Since ES5 15.1.1.3 undefined can't be deleted.
      */
     RootedPropertyName undefinedName(cx, cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
     RootedId undefinedId(cx, NameToId(undefinedName));
     RootedValue undefinedValue(cx, UndefinedValue());
     if (!obj->nativeContains(cx, undefinedId) &&
-        !obj->defineProperty(cx, undefinedName, undefinedValue,
-                             JS_PropertyStub, JS_StrictPropertyStub,
-                             JSPROP_PERMANENT | JSPROP_READONLY)) {
+        !JSObject::defineProperty(cx, obj, undefinedName, undefinedValue,
+                                  JS_PropertyStub, JS_StrictPropertyStub,
+                                  JSPROP_PERMANENT | JSPROP_READONLY)) {
         return false;
     }
 
     /* Initialize any classes that have not been initialized yet. */
     for (unsigned i = 0; standard_class_atoms[i].init; i++) {
         const JSStdName &stdnm = standard_class_atoms[i];
         if (!js::IsStandardClassResolved(obj, stdnm.clasp)
 #if JS_HAS_XML_SUPPORT
@@ -3219,17 +3219,17 @@ JS_DefaultValue(JSContext *cx, JSObject 
 {
     RootedObject obj(cx, objArg);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     JS_ASSERT(obj != NULL);
     JS_ASSERT(hint == JSTYPE_VOID || hint == JSTYPE_STRING || hint == JSTYPE_NUMBER);
 
     RootedValue value(cx);
-    if (!obj->defaultValue(cx, hint, &value))
+    if (!JSObject::defaultValue(cx, obj, hint, &value))
         return false;
 
     *vp = value;
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_PropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp)
@@ -3390,17 +3390,17 @@ JS_GetConstructor(JSContext *cx, JSObjec
     RootedValue cval(cx);
 
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, proto);
     {
         JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
 
-        if (!proto->getProperty(cx, cx->runtime->atomState.constructorAtom, &cval))
+        if (!JSObject::getProperty(cx, proto, proto, cx->runtime->atomState.constructorAtom, &cval))
             return NULL;
     }
     if (!IsFunctionObject(cval)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR,
                              proto->getClass()->name);
         return NULL;
     }
     return &cval.toObject();
@@ -3537,32 +3537,32 @@ JS_GetObjectRuntime(JSRawObject obj)
 JS_PUBLIC_API(JSBool)
 JS_FreezeObject(JSContext *cx, JSObject *objArg)
 {
     RootedObject obj(cx, objArg);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
 
-    return obj->freeze(cx);
+    return JSObject::freeze(cx, obj);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DeepFreezeObject(JSContext *cx, JSObject *objArg)
 {
     RootedObject obj(cx, objArg);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
 
     /* Assume that non-extensible objects are already deep-frozen, to avoid divergence. */
     if (!obj->isExtensible())
         return true;
 
-    if (!obj->freeze(cx))
+    if (!JSObject::freeze(cx, obj))
         return false;
 
     /* Walk slots in obj and if any value is a non-null object, seal it. */
     for (uint32_t i = 0, n = obj->slotSpan(); i < n; ++i) {
         const Value &v = obj->getSlot(i);
         if (v.isPrimitive())
             continue;
         RootedObject obj(cx, &v.toObject());
@@ -3577,17 +3577,17 @@ static JSBool
 LookupPropertyById(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
                    MutableHandleObject objp, MutableHandleShape propp)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
 
     JSAutoResolveFlags rf(cx, flags);
-    return obj->lookupGeneric(cx, id, objp, propp);
+    return JSObject::lookupGeneric(cx, obj, id, objp, propp);
 }
 
 #define AUTO_NAMELEN(s,n)   (((n) == (size_t)-1) ? js_strlen(s) : (n))
 
 static JSBool
 LookupResult(JSContext *cx, HandleObject obj, HandleObject obj2, jsid id,
              HandleShape shape, Value *vp)
 {
@@ -3670,17 +3670,17 @@ JS_LookupPropertyWithFlagsById(JSContext
     RootedId id(cx, id_);
     RootedShape prop(cx);
 
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
     if (!(obj->isNative()
           ? LookupPropertyWithFlags(cx, obj, id, flags, &objp, &prop)
-          : obj->lookupGeneric(cx, id, &objp, &prop)))
+          : JSObject::lookupGeneric(cx, obj, id, &objp, &prop)))
         return false;
 
     if (!LookupResult(cx, obj, objp, id, prop, vp))
         return false;
 
     *objpArg = objp;
     return true;
 }
@@ -3874,17 +3874,17 @@ DefinePropertyById(JSContext *cx, Handle
                             ? JS_FUNC_TO_DATA_PTR(JSObject *, setter)
                             : NULL);
 
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
     if (flags != 0 && obj->isNative()) {
         return !!DefineNativeProperty(cx, obj, id, value, getter, setter,
                                       attrs, flags, tinyid);
     }
-    return obj->defineGeneric(cx, id, value, getter, setter, attrs);
+    return JSObject::defineGeneric(cx, obj, id, value, getter, setter, attrs);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DefinePropertyById(JSContext *cx, JSObject *objArg, jsid idArg, jsval value_,
                       JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs)
 {
     RootedObject obj(cx, objArg);
     RootedId id(cx, idArg);
@@ -4089,17 +4089,17 @@ GetPropertyDescriptorById(JSContext *cx,
             desc->value.setUndefined();
     } else {
         if (obj2->isProxy()) {
             JSAutoResolveFlags rf(cx, flags);
             return own
                    ? Proxy::getOwnPropertyDescriptor(cx, obj2, id, false, desc)
                    : Proxy::getPropertyDescriptor(cx, obj2, id, false, desc);
         }
-        if (!obj2->getGenericAttributes(cx, id, &desc->attrs))
+        if (!JSObject::getGenericAttributes(cx, obj2, id, &desc->attrs))
             return false;
         desc->getter = NULL;
         desc->setter = NULL;
         desc->value.setUndefined();
     }
     return true;
 }
 
@@ -4198,18 +4198,18 @@ SetPropertyAttributesById(JSContext *cx,
 
     if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &shape))
         return false;
     if (!shape || obj != obj2) {
         *foundp = false;
         return true;
     }
     JSBool ok = obj->isNative()
-                ? obj->changePropertyAttributes(cx, shape, attrs)
-                : obj->setGenericAttributes(cx, id, &attrs);
+                ? JSObject::changePropertyAttributes(cx, obj, shape, attrs)
+                : JSObject::setGenericAttributes(cx, obj, id, &attrs);
     if (ok)
         *foundp = true;
     return ok;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetPropertyAttributes(JSContext *cx, JSObject *objArg, const char *name,
                          unsigned attrs, JSBool *foundp)
@@ -4245,17 +4245,17 @@ JS_ForwardGetPropertyTo(JSContext *cx, J
 
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
     assertSameCompartment(cx, onBehalfOf);
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
 
     RootedValue value(cx);
-    if (!obj->getGeneric(cx, onBehalfOf, id, &value))
+    if (!JSObject::getGeneric(cx, obj, onBehalfOf, id, &value))
         return false;
 
     *vp = value;
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetPropertyByIdDefault(JSContext *cx, JSObject *objArg, jsid idArg, jsval defArg, jsval *vp)
@@ -4284,17 +4284,17 @@ JS_ForwardGetElementTo(JSContext *cx, JS
     RootedObject obj(cx, objArg);
     RootedObject onBehalfOf(cx, onBehalfOfArg);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
 
     RootedValue value(cx);
-    if (!obj->getElement(cx, onBehalfOf, index, &value))
+    if (!JSObject::getElement(cx, obj, onBehalfOf, index, &value))
         return false;
 
     *vp = value;
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetElementIfPresent(JSContext *cx, JSObject *objArg, uint32_t index, JSObject *onBehalfOfArg, jsval *vp, JSBool* present)
@@ -4303,17 +4303,17 @@ JS_GetElementIfPresent(JSContext *cx, JS
     RootedObject onBehalfOf(cx, onBehalfOfArg);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
 
     RootedValue value(cx);
     bool isPresent;
-    if (!obj->getElementIfPresent(cx, onBehalfOf, index, &value, &isPresent))
+    if (!JSObject::getElementIfPresent(cx, obj, onBehalfOf, index, &value, &isPresent))
         return false;
 
     *vp = value;
     *present = isPresent;
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
@@ -4373,34 +4373,34 @@ JS_SetPropertyById(JSContext *cx, JSObje
     RootedObject obj(cx, objArg);
     RootedId id(cx, idArg);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
 
     RootedValue value(cx, *vp);
-    if (!obj->setGeneric(cx, obj, id, &value, false))
+    if (!JSObject::setGeneric(cx, obj, obj, id, &value, false))
         return false;
 
     *vp = value;
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetElement(JSContext *cx, JSObject *objArg, uint32_t index, jsval *vp)
 {
     RootedObject obj(cx, objArg);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, *vp);
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
 
     RootedValue value(cx, *vp);
-    if (!obj->setElement(cx, obj, index, &value, false))
+    if (!JSObject::setElement(cx, obj, obj, index, &value, false))
         return false;
 
     *vp = value;
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetProperty(JSContext *cx, JSObject *objArg, const char *name, jsval *vp)
@@ -4426,20 +4426,20 @@ JS_DeletePropertyById2(JSContext *cx, JS
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
 
     RootedValue value(cx);
 
     if (JSID_IS_SPECIAL(id)) {
         Rooted<SpecialId> sid(cx, JSID_TO_SPECIALID(id));
-        if (!obj->deleteSpecial(cx, sid, &value, false))
+        if (!JSObject::deleteSpecial(cx, obj, sid, &value, false))
             return false;
     } else {
-        if (!obj->deleteByValue(cx, IdToValue(id), &value, false))
+        if (!JSObject::deleteByValue(cx, obj, IdToValue(id), &value, false))
             return false;
     }
 
     *rval = value;
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
@@ -4447,17 +4447,17 @@ JS_DeleteElement2(JSContext *cx, JSObjec
 {
     RootedObject obj(cx, objArg);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
 
     RootedValue value(cx);
-    if (!obj->deleteElement(cx, index, &value, false))
+    if (!JSObject::deleteElement(cx, obj, index, &value, false))
         return false;
 
     *rval = value;
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DeleteProperty2(JSContext *cx, JSObject *objArg, const char *name, jsval *rval)
@@ -4467,17 +4467,17 @@ JS_DeleteProperty2(JSContext *cx, JSObje
     assertSameCompartment(cx, obj);
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
 
     JSAtom *atom = Atomize(cx, name, strlen(name));
     if (!atom)
         return false;
 
     RootedValue value(cx);
-    if (!obj->deleteByValue(cx, StringValue(atom), &value, false))
+    if (!JSObject::deleteByValue(cx, obj, StringValue(atom), &value, false))
         return false;
 
     *rval = value;
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DeleteUCProperty2(JSContext *cx, JSObject *objArg, const jschar *name, size_t namelen, jsval *rval)
@@ -4487,17 +4487,17 @@ JS_DeleteUCProperty2(JSContext *cx, JSOb
     assertSameCompartment(cx, obj);
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
 
     JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
     if (!atom)
         return false;
 
     RootedValue value(cx);
-    if (!obj->deleteByValue(cx, StringValue(atom), &value, false))
+    if (!JSObject::deleteByValue(cx, obj, StringValue(atom), &value, false))
         return false;
 
     *rval = value;
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DeletePropertyById(JSContext *cx, JSObject *objArg, jsid idArg)
@@ -4754,27 +4754,27 @@ JS_IsArrayObject(JSContext *cx, JSObject
 
 JS_PUBLIC_API(JSBool)
 JS_GetArrayLength(JSContext *cx, JSObject *objArg, uint32_t *lengthp)
 {
     RootedObject obj(cx, objArg);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
-    return js_GetLengthProperty(cx, obj, lengthp);
+    return GetLengthProperty(cx, obj, lengthp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetArrayLength(JSContext *cx, JSObject *objArg, uint32_t length)
 {
     RootedObject obj(cx, objArg);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
-    return js_SetLengthProperty(cx, obj, length);
+    return SetLengthProperty(cx, obj, length);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_CheckAccess(JSContext *cx, JSObject *objArg, jsid idArg, JSAccessMode mode,
                jsval *vp, unsigned *attrsp)
 {
     RootedObject obj(cx, objArg);
     RootedId id(cx, idArg);
@@ -5501,17 +5501,17 @@ JS::CompileFunction(JSContext *cx, Handl
         return NULL;
 
     if (!frontend::CompileFunctionBody(cx, fun, options, formals, chars, length))
         return NULL;
 
     if (obj && funAtom) {
         Rooted<jsid> id(cx, AtomToId(funAtom));
         RootedValue value(cx, ObjectValue(*fun));
-        if (!obj->defineGeneric(cx, id, value, NULL, NULL, JSPROP_ENUMERATE))
+        if (!JSObject::defineGeneric(cx, obj, id, value, NULL, NULL, JSPROP_ENUMERATE))
             return NULL;
     }
 
     return fun;
 }
 
 JS_PUBLIC_API(JSFunction *)
 JS::CompileFunction(JSContext *cx, HandleObject obj, CompileOptions options,
@@ -7221,17 +7221,17 @@ AutoGCRooter::AutoGCRooter(JSContext *cx
 {
     JS_ASSERT(this != *stackTop);
     *stackTop = this;
 }
 
 AutoEnumStateRooter::~AutoEnumStateRooter()
 {
     if (!stateValue.isNull())
-        MOZ_ALWAYS_TRUE(obj->enumerate(context, JSENUMERATE_DESTROY, &stateValue, 0));
+        MOZ_ALWAYS_TRUE(JSObject::enumerate(context, obj, JSENUMERATE_DESTROY, &stateValue, 0));
 }
 
 #ifdef DEBUG
 JS_PUBLIC_API(void)
 AssertArgumentsAreSane(JSContext *cx, const JS::Value &v)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1216,33 +1216,33 @@ class AutoArrayRooter : private AutoGCRo
 };
 
 /* The auto-root for enumeration object and its state. */
 class AutoEnumStateRooter : private AutoGCRooter
 {
   public:
     AutoEnumStateRooter(JSContext *cx, JSObject *obj
                         JS_GUARD_OBJECT_NOTIFIER_PARAM)
-      : AutoGCRooter(cx, ENUMERATOR), obj(obj), stateValue(), context(cx)
+      : AutoGCRooter(cx, ENUMERATOR), obj(cx, obj), stateValue(), context(cx)
     {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
         JS_ASSERT(obj);
     }
 
     ~AutoEnumStateRooter();
 
     friend void AutoGCRooter::trace(JSTracer *trc);
 
     const Value &state() const { return stateValue; }
     Value *addr() { return &stateValue; }
 
   protected:
     void trace(JSTracer *trc);
 
-    JSObject *obj;
+    RootedObject obj;
 
   private:
     Value stateValue;
     JSContext *context;
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 template<class T>
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -111,46 +111,46 @@
 #include "vm/ObjectImpl-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace mozilla;
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
+namespace js {
+
 JSBool
-js_GetLengthProperty(JSContext *cx, JSObject *obj, uint32_t *lengthp)
+GetLengthProperty(JSContext *cx, HandleObject obj, uint32_t *lengthp)
 {
     if (obj->isArray()) {
         *lengthp = obj->getArrayLength();
         return true;
     }
 
     if (obj->isArguments()) {
         ArgumentsObject &argsobj = obj->asArguments();
         if (!argsobj.hasOverriddenLength()) {
             *lengthp = argsobj.initialLength();
             return true;
         }
     }
 
     RootedValue value(cx);
-    if (!obj->getProperty(cx, cx->runtime->atomState.lengthAtom, &value))
+    if (!JSObject::getProperty(cx, obj, obj, cx->runtime->atomState.lengthAtom, &value))
         return false;
 
     if (value.isInt32()) {
         *lengthp = uint32_t(value.toInt32()); /* uint32_t cast does ToUint32_t */
         return true;
     }
 
     return ToUint32(cx, value, (uint32_t *)lengthp);
 }
 
-namespace js {
-
 /*
  * Determine if the id represents an array index or an XML property index.
  *
  * An id is an array index according to ECMA by (15.4):
  *
  * "Array objects give special treatment to a certain class of property names.
  * A property name P (in the form of a string value) is an array index if and
  * only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal
@@ -278,35 +278,35 @@ DoGetElement(JSContext *cx, HandleObject
 {
     RootedId id(cx);
 
     if (!DoubleIndexToId(cx, index, id.address()))
         return false;
 
     RootedObject obj2(cx);
     RootedShape prop(cx);
-    if (!obj->lookupGeneric(cx, id, &obj2, &prop))
+    if (!JSObject::lookupGeneric(cx, obj, id, &obj2, &prop))
         return false;
 
     if (!prop) {
         vp.setUndefined();
         *hole = true;
     } else {
-        if (!obj->getGeneric(cx, id, vp))
+        if (!JSObject::getGeneric(cx, obj, obj, id, vp))
             return false;
         *hole = false;
     }
     return true;
 }
 
 static inline bool
 DoGetElement(JSContext *cx, HandleObject obj, uint32_t index, JSBool *hole, MutableHandleValue vp)
 {
     bool present;
-    if (!obj->getElementIfPresent(cx, obj, index, vp, &present))
+    if (!JSObject::getElementIfPresent(cx, obj, obj, index, vp, &present))
         return false;
 
     *hole = !present;
     if (*hole)
         vp.setUndefined();
 
     return true;
 }
@@ -348,17 +348,17 @@ GetElement(JSContext *cx, HandleObject o
 }
 
 namespace js {
 
 static bool
 GetElementsSlow(JSContext *cx, HandleObject aobj, uint32_t length, Value *vp)
 {
     for (uint32_t i = 0; i < length; i++) {
-        if (!aobj->getElement(cx, i, MutableHandleValue::fromMarkedLocation(&vp[i])))
+        if (!JSObject::getElement(cx, aobj, aobj, i, MutableHandleValue::fromMarkedLocation(&vp[i])))
             return false;
     }
 
     return true;
 }
 
 bool
 GetElements(JSContext *cx, HandleObject aobj, uint32_t length, Value *vp)
@@ -418,17 +418,17 @@ SetArrayElement(JSContext *cx, HandleObj
             return JS_FALSE;
     }
 
     RootedId id(cx);
     if (!DoubleIndexToId(cx, index, id.address()))
         return false;
 
     RootedValue tmp(cx, v);
-    return obj->setGeneric(cx, obj, id, &tmp, true);
+    return JSObject::setGeneric(cx, obj, obj, id, &tmp, true);
 }
 
 /*
  * Delete the element |index| from |obj|. If |strict|, do a strict
  * deletion: throw if the property is not configurable.
  *
  * - Return 1 if the deletion succeeds (that is, ES5's [[Delete]] would
  *   return true)
@@ -455,20 +455,20 @@ DeleteArrayElement(JSContext *cx, Handle
                     return -1;
             }
         }
         return 1;
     }
 
     RootedValue v(cx);
     if (index <= UINT32_MAX) {
-        if (!obj->deleteElement(cx, uint32_t(index), &v, strict))
+        if (!JSObject::deleteElement(cx, obj, uint32_t(index), &v, strict))
             return -1;
     } else {
-        if (!obj->deleteByValue(cx, DoubleValue(index), &v, strict))
+        if (!JSObject::deleteByValue(cx, obj, DoubleValue(index), &v, strict))
             return -1;
     }
 
     return v.isTrue() ? 1 : 0;
 }
 
 /*
  * When hole is true, delete the property at the given index. Otherwise set
@@ -481,22 +481,22 @@ SetOrDeleteArrayElement(JSContext *cx, H
     if (hole) {
         JS_ASSERT(v.isUndefined());
         return DeleteArrayElement(cx, obj, index, true) >= 0;
     }
     return SetArrayElement(cx, obj, index, v);
 }
 
 JSBool
-js_SetLengthProperty(JSContext *cx, HandleObject obj, double length)
+js::SetLengthProperty(JSContext *cx, HandleObject obj, double length)
 {
     RootedValue v(cx, NumberValue(length));
 
     /* We don't support read-only array length yet. */
-    return obj->setProperty(cx, obj, cx->runtime->atomState.lengthAtom, &v, false);
+    return JSObject::setProperty(cx, obj, obj, cx->runtime->atomState.lengthAtom, &v, false);
 }
 
 /*
  * Since SpiderMonkey supports cross-class prototype-based delegation, we have
  * to be careful about the length getter and setter being called on an object
  * not of Array class. For the getter, we search obj's prototype chain for the
  * array that caused this getter to be invoked. In the setter case to overcome
  * the JSPROP_SHARED attribute, we must define a shadowing length property.
@@ -513,18 +513,18 @@ array_length_getter(JSContext *cx, Handl
     } while ((obj = obj->getProto()) != NULL);
     return JS_TRUE;
 }
 
 static JSBool
 array_length_setter(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, MutableHandleValue vp)
 {
     if (!obj->isArray()) {
-        return obj->defineProperty(cx, cx->runtime->atomState.lengthAtom, vp,
-                                   NULL, NULL, JSPROP_ENUMERATE);
+        return JSObject::defineProperty(cx, obj, cx->runtime->atomState.lengthAtom, vp,
+                                        NULL, NULL, JSPROP_ENUMERATE);
     }
 
     uint32_t newlen;
     if (!ToUint32(cx, vp, &newlen))
         return false;
 
     double d;
     if (!ToNumber(cx, vp, &d))
@@ -588,17 +588,17 @@ array_length_setter(JSContext *cx, Handl
             jsid nid;
             if (!JS_CHECK_OPERATION_LIMIT(cx) || !JS_NextProperty(cx, iter, &nid))
                 return false;
             if (JSID_IS_VOID(nid))
                 break;
             uint32_t index;
             RootedValue junk(cx);
             if (js_IdIsIndex(nid, &index) && index - newlen < gap &&
-                !obj->deleteElement(cx, index, &junk, false)) {
+                !JSObject::deleteElement(cx, obj, index, &junk, false)) {
                 return false;
             }
         }
     }
 
     obj->setArrayLength(cx, newlen);
     return true;
 }
@@ -635,23 +635,23 @@ array_lookupGeneric(JSContext *cx, Handl
         return baseops::LookupProperty(cx, obj, id, objp, propp);
 
     if (IsDenseArrayId(cx, obj, id)) {
         MarkNonNativePropertyFound(obj, propp);
         objp.set(obj);
         return JS_TRUE;
     }
 
-    JSObject *proto = obj->getProto();
+    RootedObject proto(cx, obj->getProto());
     if (!proto) {
         objp.set(NULL);
         propp.set(NULL);
         return JS_TRUE;
     }
-    return proto->lookupGeneric(cx, id, objp, propp);
+    return JSObject::lookupGeneric(cx, proto, id, objp, propp);
 }
 
 static JSBool
 array_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
                      MutableHandleObject objp, MutableHandleShape propp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return array_lookupGeneric(cx, obj, id, objp, propp);
@@ -665,18 +665,19 @@ array_lookupElement(JSContext *cx, Handl
         return baseops::LookupElement(cx, obj, index, objp, propp);
 
     if (IsDenseArrayIndex(obj, index)) {
         MarkNonNativePropertyFound(obj, propp);
         objp.set(obj);
         return true;
     }
 
-    if (JSObject *proto = obj->getProto())
-        return proto->lookupElement(cx, index, objp, propp);
+    RootedObject proto(cx, obj->getProto());
+    if (proto)
+        return JSObject::lookupElement(cx, proto, index, objp, propp);
 
     objp.set(NULL);
     propp.set(NULL);
     return true;
 }
 
 static JSBool
 array_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
@@ -710,23 +711,23 @@ array_getProperty(JSContext *cx, HandleO
         return true;
     }
 
     if (!obj->isDenseArray()) {
         Rooted<jsid> id(cx, NameToId(name));
         return baseops::GetProperty(cx, obj, receiver, id, vp);
     }
 
-    JSObject *proto = obj->getProto();
+    RootedObject proto(cx, obj->getProto());
     if (!proto) {
         vp.setUndefined();
         return true;
     }
 
-    return proto->getProperty(cx, receiver, name, vp);
+    return JSObject::getProperty(cx, proto, receiver, name, vp);
 }
 
 static JSBool
 array_getElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index,
                  MutableHandleValue vp)
 {
     if (!obj->isDenseArray())
         return baseops::GetElement(cx, obj, receiver, index, vp);
@@ -737,23 +738,23 @@ array_getElement(JSContext *cx, HandleOb
             /* Type information for dense array elements must be correct. */
             JS_ASSERT_IF(!obj->hasSingletonType(),
                          js::types::TypeHasProperty(cx, obj->type(), JSID_VOID, vp));
 
             return true;
         }
     }
 
-    JSObject *proto = obj->getProto();
+    RootedObject proto(cx, obj->getProto());
     if (!proto) {
         vp.setUndefined();
         return true;
     }
 
-    return proto->getElement(cx, receiver, index, vp);
+    return JSObject::getElement(cx, proto, receiver, index, vp);
 }
 
 static JSBool
 array_getSpecial(JSContext *cx, HandleObject obj, HandleObject receiver, HandleSpecialId sid,
                  MutableHandleValue vp)
 {
     if (obj->isDenseArray() && !obj->getProto()) {
         vp.setUndefined();
@@ -1422,17 +1423,17 @@ array_toSource_impl(JSContext *cx, CallA
             return false;
         goto make_string;
     }
 
     if (!sb.append('['))
         return false;
 
     uint32_t length;
-    if (!js_GetLengthProperty(cx, obj, &length))
+    if (!GetLengthProperty(cx, obj, &length))
         return false;
 
     for (uint32_t index = 0; index < length; index++) {
         JSBool hole;
         if (!JS_CHECK_OPERATION_LIMIT(cx) ||
             !GetElement(cx, obj, index, &hole, &elt)) {
             return false;
         }
@@ -1545,17 +1546,17 @@ array_join_sub(JSContext *cx, CallArgs &
 
     if (detector.foundCycle()) {
         args.rval().setString(cx->runtime->atomState.emptyAtom);
         return true;
     }
 
     // Steps 2 and 3
     uint32_t length;
-    if (!js_GetLengthProperty(cx, obj, &length))
+    if (!GetLengthProperty(cx, obj, &length))
         return false;
 
 
     // Steps 4 and 5
     RootedString sepstr(cx, NULL);
     if (!locale && args.hasDefined(0)) {
         sepstr = ToString(cx, args[0]);
         if (!sepstr)
@@ -1657,17 +1658,17 @@ array_toString(JSContext *cx, unsigned a
     JS_CHECK_RECURSION(cx, return false);
 
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     RootedValue join(cx, args.calleev());
-    if (!obj->getProperty(cx, cx->runtime->atomState.joinAtom, &join))
+    if (!JSObject::getProperty(cx, obj, obj, cx->runtime->atomState.joinAtom, &join))
         return false;
 
     if (!js_IsCallable(join)) {
         JSString *str = obj_toStringHelper(cx, obj);
         if (!str)
             return false;
         args.rval().setString(str);
         return true;
@@ -1790,17 +1791,17 @@ InitArrayElements(JSContext *cx, HandleO
 
     JS_ASSERT(start == MAX_ARRAY_INDEX + 1);
     RootedValue value(cx);
     RootedId id(cx);
     Value idval = DoubleValue(MAX_ARRAY_INDEX + 1);
     do {
         value = *vector++;
         if (!ValueToId(cx, idval, id.address()) ||
-            !obj->setGeneric(cx, obj, id, &value, true)) {
+            !JSObject::setGeneric(cx, obj, obj, id, &value, true)) {
             return false;
         }
         idval.getDoubleRef() += 1;
     } while (vector != end);
 
     return true;
 }
 
@@ -1808,17 +1809,17 @@ static JSBool
 array_reverse(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     uint32_t len;
-    if (!js_GetLengthProperty(cx, obj, &len))
+    if (!GetLengthProperty(cx, obj, &len))
         return false;
 
     do {
         if (!obj->isDenseArray())
             break;
         if (js_PrototypeHasIndexedProperties(cx, obj))
             break;
 
@@ -2118,17 +2119,17 @@ js::array_sort(JSContext *cx, unsigned a
         fval.setNull();
     }
 
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     uint32_t len;
-    if (!js_GetLengthProperty(cx, obj, &len))
+    if (!GetLengthProperty(cx, obj, &len))
         return false;
     if (len == 0) {
         args.rval().setObject(*obj);
         return true;
     }
 
     /*
      * We need a temporary array of 2 * len Value to hold the array elements
@@ -2284,25 +2285,25 @@ js::array_sort(JSContext *cx, unsigned a
 /*
  * Perl-inspired push, pop, shift, unshift, and splice methods.
  */
 static bool
 array_push_slowly(JSContext *cx, HandleObject obj, CallArgs &args)
 {
     uint32_t length;
 
-    if (!js_GetLengthProperty(cx, obj, &length))
+    if (!GetLengthProperty(cx, obj, &length))
         return false;
     if (!InitArrayElements(cx, obj, length, args.length(), args.array(), UpdateTypes))
         return false;
 
     /* Per ECMA-262, return the new array length. */
     double newlength = length + double(args.length());
     args.rval().setNumber(newlength);
-    return js_SetLengthProperty(cx, obj, newlength);
+    return SetLengthProperty(cx, obj, newlength);
 }
 
 static bool
 array_push1_dense(JSContext* cx, HandleObject obj, CallArgs &args)
 {
     JS_ASSERT(args.length() == 1);
 
     uint32_t length = obj->getArrayLength();
@@ -2368,36 +2369,36 @@ js::array_push(JSContext *cx, unsigned a
 
     return array_push1_dense(cx, obj, args);
 }
 
 static JSBool
 array_pop_slowly(JSContext *cx, HandleObject obj, CallArgs &args)
 {
     uint32_t index;
-    if (!js_GetLengthProperty(cx, obj, &index))
+    if (!GetLengthProperty(cx, obj, &index))
         return false;
 
     if (index == 0) {
         args.rval().setUndefined();
-        return js_SetLengthProperty(cx, obj, index);
+        return SetLengthProperty(cx, obj, index);
     }
 
     index--;
 
     JSBool hole;
     RootedValue elt(cx);
     if (!GetElement(cx, obj, index, &hole, &elt))
         return false;
 
     if (!hole && DeleteArrayElement(cx, obj, index, true) < 0)
         return false;
 
     args.rval().set(elt);
-    return js_SetLengthProperty(cx, obj, index);
+    return SetLengthProperty(cx, obj, index);
 }
 
 static JSBool
 array_pop_dense(JSContext *cx, HandleObject obj, CallArgs &args)
 {
     uint32_t index = obj->getArrayLength();
     if (index == 0) {
         args.rval().setUndefined();
@@ -2421,17 +2422,17 @@ array_pop_dense(JSContext *cx, HandleObj
     if (obj->isDenseArray()) {
         if (obj->getDenseArrayInitializedLength() > index)
             obj->setDenseArrayInitializedLength(index);
 
         obj->setArrayLength(cx, index);
         return true;
     }
 
-    return js_SetLengthProperty(cx, obj, index);
+    return SetLengthProperty(cx, obj, index);
 }
 
 JSBool
 js::array_pop(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
@@ -2462,17 +2463,17 @@ JSBool
 js::array_shift(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return JS_FALSE;
 
     uint32_t length;
-    if (!js_GetLengthProperty(cx, obj, &length))
+    if (!GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
 
     if (length == 0) {
         args.rval().setUndefined();
     } else {
         length--;
 
         if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
@@ -2502,29 +2503,29 @@ js::array_shift(JSContext *cx, unsigned 
                 return JS_FALSE;
             }
         }
 
         /* Delete the only or last element when it exists. */
         if (!hole && DeleteArrayElement(cx, obj, length, true) < 0)
             return JS_FALSE;
     }
-    return js_SetLengthProperty(cx, obj, length);
+    return SetLengthProperty(cx, obj, length);
 }
 
 static JSBool
 array_unshift(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     uint32_t length;
-    if (!js_GetLengthProperty(cx, obj, &length))
+    if (!GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
 
     double newlen = length;
     if (args.length() > 0) {
         /* Slide up the array to make room for all args at the bottom. */
         if (length > 0) {
             bool optimized = false;
             do {
@@ -2562,17 +2563,17 @@ array_unshift(JSContext *cx, unsigned ar
         }
 
         /* Copy from args to the bottom of the array. */
         if (!InitArrayElements(cx, obj, 0, args.length(), args.array(), UpdateTypes))
             return JS_FALSE;
 
         newlen += args.length();
     }
-    if (!js_SetLengthProperty(cx, obj, newlen))
+    if (!SetLengthProperty(cx, obj, newlen))
         return JS_FALSE;
 
     /* Follow Perl by returning the new array length. */
     args.rval().setNumber(newlen);
     return JS_TRUE;
 }
 
 static inline void
@@ -2637,17 +2638,17 @@ array_splice(JSContext *cx, unsigned arg
 
     /* Step 1. */
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Steps 3-4. */
     uint32_t len;
-    if (!js_GetLengthProperty(cx, obj, &len))
+    if (!GetLengthProperty(cx, obj, &len))
         return false;
 
     /* Step 5. */
     double relativeStart;
     if (!ToInteger(cx, argc >= 1 ? args[0] : UndefinedValue(), &relativeStart))
         return false;
 
     /* Step 6. */
@@ -2688,17 +2689,17 @@ array_splice(JSContext *cx, unsigned arg
             return false;
         TryReuseArrayType(obj, arr);
 
         RootedValue fromValue(cx);
         for (uint32_t k = 0; k < actualDeleteCount; k++) {
             JSBool hole;
             if (!JS_CHECK_OPERATION_LIMIT(cx) ||
                 !GetElement(cx, obj, actualStart + k, &hole, &fromValue) ||
-                (!hole && !arr->defineElement(cx, k, fromValue)))
+                (!hole && !JSObject::defineElement(cx, arr, k, fromValue)))
             {
                 return false;
             }
         }
     }
 
     /* Step 11. */
     uint32_t itemCount = (argc >= 2) ? (argc - 2) : 0;
@@ -2804,17 +2805,17 @@ array_splice(JSContext *cx, unsigned arg
     /* Steps 14-15. */
     for (uint32_t k = actualStart, i = 0; i < itemCount; i++, k++) {
         if (!SetArrayElement(cx, obj, k, HandleValue::fromMarkedLocation(&items[i])))
             return false;
     }
 
     /* Step 16. */
     double finalLength = double(len) - actualDeleteCount + itemCount;
-    if (!js_SetLengthProperty(cx, obj, finalLength))
+    if (!SetLengthProperty(cx, obj, finalLength))
         return false;
 
     /* Step 17. */
     args.rval().setObject(*arr);
     return true;
 }
 
 #ifdef JS_METHODJIT
@@ -2893,17 +2894,17 @@ js::array_concat(JSContext *cx, unsigned
     for (unsigned i = 0; i <= argc; i++) {
         if (!JS_CHECK_OPERATION_LIMIT(cx))
             return false;
         HandleValue v = HandleValue::fromMarkedLocation(&p[i]);
         if (v.isObject()) {
             RootedObject obj(cx, &v.toObject());
             if (ObjectClassIs(*obj, ESClass_Array, cx)) {
                 uint32_t alength;
-                if (!js_GetLengthProperty(cx, obj, &alength))
+                if (!GetLengthProperty(cx, obj, &alength))
                     return false;
                 RootedValue tmp(cx);
                 for (uint32_t slot = 0; slot < alength; slot++) {
                     JSBool hole;
                     if (!JS_CHECK_OPERATION_LIMIT(cx) || !GetElement(cx, obj, slot, &hole, &tmp))
                         return false;
 
                     /*
@@ -2918,32 +2919,32 @@ js::array_concat(JSContext *cx, unsigned
             }
         }
 
         if (!SetArrayElement(cx, nobj, length, v))
             return false;
         length++;
     }
 
-    return js_SetLengthProperty(cx, nobj, length);
+    return SetLengthProperty(cx, nobj, length);
 }
 
 static JSBool
 array_slice(JSContext *cx, unsigned argc, Value *vp)
 {
     uint32_t length, begin, end, slot;
     JSBool hole;
 
     CallArgs args = CallArgsFromVp(argc, vp);
 
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
-    if (!js_GetLengthProperty(cx, obj, &length))
+    if (!GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
     begin = 0;
     end = length;
 
     if (args.length() > 0) {
         double d;
         if (!ToInteger(cx, args[0], &d))
             return false;
@@ -3016,17 +3017,17 @@ array_indexOfHelper(JSContext *cx, Index
     int direction;
     JSBool hole;
 
     RootedValue tosearch(cx), elt(cx);
 
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
-    if (!js_GetLengthProperty(cx, obj, &length))
+    if (!GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
     if (length == 0)
         goto not_found;
 
     if (args.length() <= 1) {
         i = (mode == LastIndexOf) ? length - 1 : 0;
         tosearch = (args.length() != 0) ? args[0] : UndefinedValue();
     } else {
@@ -3141,17 +3142,17 @@ array_readonlyCommon(JSContext *cx, Call
 {
     /* Step 1. */
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Step 2-3. */
     uint32_t len;
-    if (!js_GetLengthProperty(cx, obj, &len))
+    if (!GetLengthProperty(cx, obj, &len))
         return false;
 
     /* Step 4. */
     if (args.length() == 0) {
         js_ReportMissingArg(cx, args.calleev(), 0);
         return false;
     }
     RootedObject callable(cx, ValueToCallable(cx, &args[0]));
@@ -3233,17 +3234,17 @@ array_map(JSContext *cx, unsigned argc, 
 
     /* Step 1. */
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Step 2-3. */
     uint32_t len;
-    if (!js_GetLengthProperty(cx, obj, &len))
+    if (!GetLengthProperty(cx, obj, &len))
         return false;
 
     /* Step 4. */
     if (args.length() == 0) {
         js_ReportMissingArg(cx, args.calleev(), 0);
         return false;
     }
     RootedObject callable(cx, ValueToCallable(cx, &args[0]));
@@ -3310,17 +3311,17 @@ array_filter(JSContext *cx, unsigned arg
 
     /* Step 1. */
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Step 2-3. */
     uint32_t len;
-    if (!js_GetLengthProperty(cx, obj, &len))
+    if (!GetLengthProperty(cx, obj, &len))
         return false;
 
     /* Step 4. */
     if (args.length() == 0) {
         js_ReportMissingArg(cx, args.calleev(), 0);
         return false;
     }
     RootedObject callable(cx, ValueToCallable(cx, &args[0]));
@@ -3418,17 +3419,17 @@ array_reduceCommon(JSContext *cx, CallAr
 {
     /* Step 1. */
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Step 2-3. */
     uint32_t len;
-    if (!js_GetLengthProperty(cx, obj, &len))
+    if (!GetLengthProperty(cx, obj, &len))
         return false;
 
     /* Step 4. */
     if (args.length() == 0) {
         js_ReportMissingArg(cx, args.calleev(), 0);
         return false;
     }
     RootedObject callable(cx, ValueToCallable(cx, &args[0]));
--- a/js/src/jsarray.h
+++ b/js/src/jsarray.h
@@ -66,25 +66,21 @@ NewDenseUnallocatedArray(JSContext *cx, 
 /* Create a dense array with a copy of vp. */
 extern JSObject *
 NewDenseCopiedArray(JSContext *cx, uint32_t length, const Value *vp, RawObject proto = NULL);
 
 /* Create a sparse array. */
 extern JSObject *
 NewSlowEmptyArray(JSContext *cx);
 
-} /* namespace js */
+extern JSBool
+GetLengthProperty(JSContext *cx, HandleObject obj, uint32_t *lengthp);
 
 extern JSBool
-js_GetLengthProperty(JSContext *cx, JSObject *obj, uint32_t *lengthp);
-
-extern JSBool
-js_SetLengthProperty(JSContext *cx, js::HandleObject obj, double length);
-
-namespace js {
+SetLengthProperty(JSContext *cx, HandleObject obj, double length);
 
 extern JSBool
 array_defineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue value,
                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
 
 extern JSBool
 array_deleteElement(JSContext *cx, HandleObject obj, uint32_t index,
                     MutableHandleValue rval, JSBool strict);
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -165,18 +165,18 @@ js_InitBooleanClass(JSContext *cx, JSObj
         return NULL;
 
     Rooted<PropertyName*> valueOfName(cx, cx->runtime->atomState.valueOfAtom);
     Rooted<JSFunction*> valueOf(cx,
                                 js_NewFunction(cx, NULL, bool_valueOf, 0, 0, global, valueOfName));
     if (!valueOf)
         return NULL;
     RootedValue value(cx, ObjectValue(*valueOf));
-    if (!booleanProto->defineProperty(cx, valueOfName, value,
-                                      JS_PropertyStub, JS_StrictPropertyStub, 0))
+    if (!JSObject::defineProperty(cx, booleanProto, valueOfName, value,
+                                  JS_PropertyStub, JS_StrictPropertyStub, 0))
     {
         return NULL;
     }
 
     global->setBooleanValueOf(valueOf);
 
     if (!DefineConstructorAndPrototype(cx, global, JSProto_Boolean, ctor, booleanProto))
         return NULL;
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -577,17 +577,17 @@ JSStructuredCloneWriter::write(const Val
                 if (!js_HasOwnProperty(context(), obj->getOps()->lookupGeneric, obj, id,
                                        &obj2, &prop)) {
                     return false;
                 }
 
                 if (prop) {
                     RootedValue val(context());
                     if (!writeId(id) ||
-                        !obj->getGeneric(context(), id, &val) ||
+                        !JSObject::getGeneric(context(), obj, obj, id, &val) ||
                         !startWrite(val))
                         return false;
                 }
             }
         } else {
             out.writePair(SCTAG_NULL, 0);
             objs.popBack();
             counts.popBack();
@@ -917,17 +917,17 @@ JSStructuredCloneReader::read(Value *vp)
         RootedId id(context());
         if (!readId(id.address()))
             return false;
 
         if (JSID_IS_VOID(id)) {
             objs.popBack();
         } else {
             RootedValue v(context());
-            if (!startRead(v.address()) || !obj->defineGeneric(context(), id, v))
+            if (!startRead(v.address()) || !JSObject::defineGeneric(context(), obj, id, v))
                 return false;
         }
     }
 
     allObjs.clear();
 
     return true;
 }
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -2604,17 +2604,17 @@ date_toJSON(JSContext *cx, unsigned argc
     /* Step 3. */
     if (tv.isDouble() && !MOZ_DOUBLE_IS_FINITE(tv.toDouble())) {
         args.rval().setNull();
         return true;
     }
 
     /* Step 4. */
     RootedValue toISO(cx);
-    if (!obj->getProperty(cx, cx->runtime->atomState.toISOStringAtom, &toISO))
+    if (!JSObject::getProperty(cx, obj, obj, cx->runtime->atomState.toISOStringAtom, &toISO))
         return false;
 
     /* Step 5. */
     if (!js_IsCallable(toISO)) {
         JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
                                      JSMSG_BAD_TOISOSTRING_PROP);
         return false;
     }
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -529,18 +529,19 @@ Exception(JSContext *cx, unsigned argc, 
 
     /*
      * ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when
      * called as functions, without operator new.  But as we do not give
      * each constructor a distinct JSClass, whose .name member is used by
      * NewNativeClassInstance to find the class prototype, we must get the
      * class prototype ourselves.
      */
+    RootedObject callee(cx, &args.callee());
     RootedValue protov(cx);
-    if (!args.callee().getProperty(cx, cx->runtime->atomState.classPrototypeAtom, &protov))
+    if (!JSObject::getProperty(cx, callee, callee, cx->runtime->atomState.classPrototypeAtom, &protov))
         return false;
 
     if (!protov.isObject()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PROTOTYPE, "Error");
         return false;
     }
 
     JSObject *errProto = &protov.toObject();
@@ -613,32 +614,32 @@ exn_toString(JSContext *cx, unsigned arg
         return false;
     }
 
     /* Step 1. */
     RootedObject obj(cx, &args.thisv().toObject());
 
     /* Step 3. */
     RootedValue nameVal(cx);
-    if (!obj->getProperty(cx, cx->runtime->atomState.nameAtom, &nameVal))
+    if (!JSObject::getProperty(cx, obj, obj, cx->runtime->atomState.nameAtom, &nameVal))
         return false;
 
     /* Step 4. */
     RootedString name(cx);
     if (nameVal.isUndefined()) {
         name = CLASS_NAME(cx, Error);
     } else {
         name = ToString(cx, nameVal);
         if (!name)
             return false;
     }
 
     /* Step 5. */
     RootedValue msgVal(cx);
-    if (!obj->getProperty(cx, cx->runtime->atomState.messageAtom, &msgVal))
+    if (!JSObject::getProperty(cx, obj, obj, cx->runtime->atomState.messageAtom, &msgVal))
         return false;
 
     /* Step 6. */
     JSString *message;
     if (msgVal.isUndefined()) {
         message = cx->runtime->emptyString;
     } else {
         message = ToString(cx, msgVal);
@@ -687,41 +688,41 @@ exn_toSource(JSContext *cx, unsigned arg
     CallArgs args = CallArgsFromVp(argc, vp);
 
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     RootedValue nameVal(cx);
     RootedString name(cx);
-    if (!obj->getProperty(cx, cx->runtime->atomState.nameAtom, &nameVal) ||
+    if (!JSObject::getProperty(cx, obj, obj, cx->runtime->atomState.nameAtom, &nameVal) ||
         !(name = ToString(cx, nameVal)))
     {
         return false;
     }
 
     RootedValue messageVal(cx);
     RootedString message(cx);
-    if (!obj->getProperty(cx, cx->runtime->atomState.messageAtom, &messageVal) ||
+    if (!JSObject::getProperty(cx, obj, obj, cx->runtime->atomState.messageAtom, &messageVal) ||
         !(message = js_ValueToSource(cx, messageVal)))
     {
         return false;
     }
 
     RootedValue filenameVal(cx);
     RootedString filename(cx);
-    if (!obj->getProperty(cx, cx->runtime->atomState.fileNameAtom, &filenameVal) ||
+    if (!JSObject::getProperty(cx, obj, obj, cx->runtime->atomState.fileNameAtom, &filenameVal) ||
         !(filename = js_ValueToSource(cx, filenameVal)))
     {
         return false;
     }
 
     RootedValue linenoVal(cx);
     uint32_t lineno;
-    if (!obj->getProperty(cx, cx->runtime->atomState.lineNumberAtom, &linenoVal) ||
+    if (!JSObject::getProperty(cx, obj, obj, cx->runtime->atomState.lineNumberAtom, &linenoVal) ||
         !ToUint32(cx, linenoVal, &lineno))
     {
         return false;
     }
 
     StringBuffer sb(cx);
     if (!sb.append("(new ") || !sb.append(name) || !sb.append("("))
         return false;
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -100,18 +100,18 @@ JS_SplicePrototype(JSContext *cx, JSObje
     return obj->splicePrototype(cx, proto);
 }
 
 JS_FRIEND_API(JSObject *)
 JS_NewObjectWithUniqueType(JSContext *cx, JSClass *clasp, JSObject *protoArg, JSObject *parentArg)
 {
     RootedObject proto(cx, protoArg);
     RootedObject parent(cx, parentArg);
-    JSObject *obj = JS_NewObject(cx, clasp, proto, parent);
-    if (!obj || !obj->setSingletonType(cx))
+    RootedObject obj(cx, JS_NewObject(cx, clasp, proto, parent));
+    if (!obj || !JSObject::setSingletonType(cx, obj))
         return NULL;
     return obj;
 }
 
 JS_FRIEND_API(void)
 js::PrepareCompartmentForGC(JSCompartment *comp)
 {
     comp->scheduleGC();
@@ -435,23 +435,23 @@ js::SetFunctionNativeReserved(RawObject 
 
 JS_FRIEND_API(void)
 js::SetReservedSlotWithBarrier(RawObject obj, size_t slot, const js::Value &value)
 {
     obj->setSlot(slot, value);
 }
 
 JS_FRIEND_API(bool)
-js::GetGeneric(JSContext *cx, JSObject *obj, JSObject *receiver_, jsid id_,
+js::GetGeneric(JSContext *cx, JSObject *objArg, JSObject *receiverArg, jsid idArg,
                Value *vp)
 {
-    RootedObject receiver(cx, receiver_);
-    RootedId id(cx, id_);
+    RootedObject obj(cx, objArg), receiver(cx, receiverArg);
+    RootedId id(cx, idArg);
     RootedValue value(cx);
-    if (!obj->getGeneric(cx, receiver, id, &value))
+    if (!JSObject::getGeneric(cx, obj, receiver, id, &value))
         return false;
     *vp = value;
     return true;
 }
 
 void
 js::SetPreserveWrapperCallback(JSRuntime *rt, PreserveWrapperCallback callback)
 {
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -182,32 +182,32 @@ fun_enumerate(JSContext *cx, HandleObjec
 {
     JS_ASSERT(obj->isFunction());
 
     RootedId id(cx);
     bool found;
 
     if (!obj->isBoundFunction()) {
         id = NameToId(cx->runtime->atomState.classPrototypeAtom);
-        if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED))
+        if (!JSObject::hasProperty(cx, obj, id, &found, JSRESOLVE_QUALIFIED))
             return false;
     }
 
     id = NameToId(cx->runtime->atomState.lengthAtom);
-    if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED))
+    if (!JSObject::hasProperty(cx, obj, id, &found, JSRESOLVE_QUALIFIED))
         return false;
 
     id = NameToId(cx->runtime->atomState.nameAtom);
-    if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED))
+    if (!JSObject::hasProperty(cx, obj, id, &found, JSRESOLVE_QUALIFIED))
         return false;
 
     for (unsigned i = 0; i < ArrayLength(poisonPillProps); i++) {
         const uint16_t offset = poisonPillProps[i];
         id = NameToId(OFFSET_TO_NAME(cx->runtime, offset));
-        if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED))
+        if (!JSObject::hasProperty(cx, obj, id, &found, JSRESOLVE_QUALIFIED))
             return false;
     }
 
     return true;
 }
 
 static JSObject *
 ResolveInterpretedFunctionPrototype(JSContext *cx, HandleObject obj)
@@ -229,32 +229,32 @@ ResolveInterpretedFunctionPrototype(JSCo
     /*
      * Make the prototype object an instance of Object with the same parent
      * as the function object itself.
      */
     JSObject *objProto = obj->global().getOrCreateObjectPrototype(cx);
     if (!objProto)
         return NULL;
     RootedObject proto(cx, NewObjectWithGivenProto(cx, &ObjectClass, objProto, NULL));
-    if (!proto || !proto->setSingletonType(cx))
+    if (!proto || !JSObject::setSingletonType(cx, proto))
         return NULL;
 
     /*
      * Per ES5 15.3.5.2 a user-defined function's .prototype property is
      * initially non-configurable, non-enumerable, and writable.  Per ES5 13.2
      * the prototype's .constructor property is configurable, non-enumerable,
      * and writable.
      */
     RootedValue protoVal(cx, ObjectValue(*proto));
     RootedValue objVal(cx, ObjectValue(*obj));
-    if (!obj->defineProperty(cx, cx->runtime->atomState.classPrototypeAtom,
-                             protoVal, JS_PropertyStub, JS_StrictPropertyStub,
-                             JSPROP_PERMANENT) ||
-        !proto->defineProperty(cx, cx->runtime->atomState.constructorAtom,
-                               objVal, JS_PropertyStub, JS_StrictPropertyStub, 0))
+    if (!JSObject::defineProperty(cx, obj, cx->runtime->atomState.classPrototypeAtom,
+                                  protoVal, JS_PropertyStub, JS_StrictPropertyStub,
+                                  JSPROP_PERMANENT) ||
+        !JSObject::defineProperty(cx, proto, cx->runtime->atomState.constructorAtom,
+                                  objVal, JS_PropertyStub, JS_StrictPropertyStub, 0))
     {
        return NULL;
     }
 
     return proto;
 }
 
 static JSBool
@@ -392,17 +392,17 @@ js::XDRInterpretedFunction(XDRState<mode
         return false;
 
     if (mode == XDR_DECODE) {
         fun->nargs = flagsword >> 16;
         fun->flags = uint16_t(flagsword);
         fun->atom.init(atom);
         fun->initScript(script);
         script->setFunction(fun);
-        if (!fun->setTypeForScriptedFunction(cx))
+        if (!JSFunction::setTypeForScriptedFunction(cx, fun))
             return false;
         JS_ASSERT(fun->nargs == fun->script()->bindings.numArgs());
         js_CallNewScriptHook(cx, fun->script(), fun);
         objp.set(fun);
     }
 
     return true;
 }
@@ -432,17 +432,17 @@ js::CloneInterpretedFunction(JSContext *
     if (!clonedScript)
         return NULL;
 
     clone->nargs = srcFun->nargs;
     clone->flags = srcFun->flags;
     clone->atom.init(srcFun->atom);
     clone->initScript(clonedScript);
     clonedScript->setFunction(clone);
-    if (!clone->setTypeForScriptedFunction(cx))
+    if (!JSFunction::setTypeForScriptedFunction(cx, clone))
         return NULL;
 
     js_CallNewScriptHook(cx, clone->script(), clone);
     return clone;
 }
 
 /*
  * [[HasInstance]] internal method for Function objects: fetch the .prototype
@@ -456,17 +456,17 @@ fun_hasInstance(JSContext *cx, HandleObj
 
     while (obj->isFunction()) {
         if (!obj->isBoundFunction())
             break;
         obj = obj->toFunction()->getBoundFunctionTarget();
     }
 
     RootedValue pval(cx);
-    if (!obj->getProperty(cx, cx->runtime->atomState.classPrototypeAtom, &pval))
+    if (!JSObject::getProperty(cx, obj, obj, cx->runtime->atomState.classPrototypeAtom, &pval))
         return JS_FALSE;
 
     if (pval.isPrimitive()) {
         /*
          * Throw a runtime error if instanceof is called on a function that
          * has a non-object as its .prototype value.
          */
         RootedValue val(cx, ObjectValue(*obj));
@@ -872,17 +872,17 @@ js_fun_apply(JSContext *cx, unsigned arg
         }
 
         /*
          * Steps 4-5 (note erratum removing steps originally numbered 5 and 7 in
          * original version of ES5).
          */
         RootedObject aobj(cx, &vp[3].toObject());
         uint32_t length;
-        if (!js_GetLengthProperty(cx, aobj, &length))
+        if (!GetLengthProperty(cx, aobj, &length))
             return false;
 
         /* Step 6. */
         if (length > StackSpace::ARGS_LENGTH_MAX) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TOO_MANY_FUN_APPLY_ARGS);
             return false;
         }
 
@@ -1389,17 +1389,17 @@ js_NewFunction(JSContext *cx, JSObject *
         fun->initNative(native, NULL);
     }
     if (kind == JSFunction::ExtendedFinalizeKind) {
         fun->flags |= JSFUN_EXTENDED;
         fun->initializeExtended();
     }
     fun->atom.init(atom);
 
-    if (native && !fun->setSingletonType(cx))
+    if (native && !JSObject::setSingletonType(cx, fun))
         return NULL;
 
     return fun;
 }
 
 JSFunction * JS_FASTCALL
 js_CloneFunctionObject(JSContext *cx, HandleFunction fun, HandleObject parent,
                        HandleObject proto, gc::AllocKind kind)
@@ -1434,17 +1434,17 @@ js_CloneFunctionObject(JSContext *cx, Ha
          * its prototype is correct, and (b) its type is not a singleton. The
          * first case will hold in all compileAndGo code, and the second case
          * will have been caught by CloneFunctionObject coming from function
          * definitions or read barriers, so will not get here.
          */
         if (fun->getProto() == proto && !fun->hasSingletonType())
             clone->setType(fun->type());
     } else {
-        if (!clone->setSingletonType(cx))
+        if (!JSObject::setSingletonType(cx, clone))
             return NULL;
 
         /*
          * Across compartments we have to clone the script for interpreted
          * functions. Cross-compartment cloning only happens via JSAPI
          * (JS_CloneFunctionObject) which dynamically ensures that 'script' has
          * no enclosing lexical scope (only the global scope).
          */
@@ -1516,17 +1516,17 @@ js_DefineFunction(JSContext *cx, HandleO
         JS_ASSERT(attrs & JSFUN_INTERPRETED);
         fun = cx->runtime->getSelfHostedFunction(cx, selfHostedName);
         fun->atom = JSID_TO_ATOM(id);
     }
     if (!fun)
         return NULL;
 
     RootedValue funVal(cx, ObjectValue(*fun));
-    if (!obj->defineGeneric(cx, id, funVal, gop, sop, attrs & ~JSFUN_FLAGS_MASK))
+    if (!JSObject::defineGeneric(cx, obj, id, funVal, gop, sop, attrs & ~JSFUN_FLAGS_MASK))
         return NULL;
 
     return fun;
 }
 
 void
 js::ReportIncompatibleMethod(JSContext *cx, CallReceiver call, Class *clasp)
 {
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -182,17 +182,18 @@ struct JSFunction : public JSObject
 
   public:
     /* Accessors for data stored in extended functions. */
     inline void initializeExtended();
     inline void setExtendedSlot(size_t which, const js::Value &val);
     inline const js::Value &getExtendedSlot(size_t which) const;
 
     /* Constructs a new type for the function if necessary. */
-    bool setTypeForScriptedFunction(JSContext *cx, bool singleton = false);
+    static bool setTypeForScriptedFunction(JSContext *cx, js::HandleFunction fun,
+                                           bool singleton = false);
 
   private:
     static void staticAsserts() {
         MOZ_STATIC_ASSERT(sizeof(JSFunction) == sizeof(js::shadow::Function),
                           "shadow interface must match actual interface");
     }
     /*
      * These member functions are inherited from JSObject, but should never be applied to
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2234,17 +2234,16 @@ AutoIdArray::trace(JSTracer *trc)
 {
     JS_ASSERT(tag == IDARRAY);
     gc::MarkIdRange(trc, idArray->length, idArray->vector, "JSAutoIdArray.idArray");
 }
 
 void
 AutoEnumStateRooter::trace(JSTracer *trc)
 {
-    gc::MarkObjectRoot(trc, &obj, "JS::AutoEnumStateRooter.obj");
 }
 
 inline void
 AutoGCRooter::trace(JSTracer *trc)
 {
     switch (tag) {
       case JSVAL:
         MarkValueRoot(trc, &static_cast<AutoValueRooter *>(this)->val, "JS::AutoValueRooter.val");
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -5042,43 +5042,41 @@ JSScript::makeAnalysis(JSContext *cx)
     if (self->types->analysis->OOM()) {
         self->types->analysis = NULL;
         return false;
     }
 
     return true;
 }
 
-bool
-JSFunction::setTypeForScriptedFunction(JSContext *cx, bool singleton)
+/* static */ bool
+JSFunction::setTypeForScriptedFunction(JSContext *cx, HandleFunction fun, bool singleton)
 {
-    JS_ASSERT(script());
-    JS_ASSERT(script()->function() == this);
+    JS_ASSERT(fun->script());
+    JS_ASSERT(fun->script()->function() == fun);
 
     if (!cx->typeInferenceEnabled())
         return true;
 
     if (singleton) {
-        if (!setSingletonType(cx))
+        if (!setSingletonType(cx, fun))
             return false;
-    } else if (UseNewTypeForClone(this)) {
+    } else if (UseNewTypeForClone(fun)) {
         /*
          * Leave the default unknown-properties type for the function, it
          * should not be used by scripts or appear in type sets.
          */
     } else {
-        RootedFunction self(cx, this);
-
-        TypeObject *type = cx->compartment->types.newTypeObject(cx, script(),
-                                                                JSProto_Function, getProto());
+        TypeObject *type = cx->compartment->types.newTypeObject(cx, fun->script(),
+                                                                JSProto_Function, fun->getProto());
         if (!type)
             return false;
 
-        self->setType(type);
-        type->interpretedFunction = self;
+        fun->setType(type);
+        type->interpretedFunction = fun;
     }
 
     return true;
 }
 
 #ifdef DEBUG
 
 /* static */ void
@@ -5188,35 +5186,35 @@ JSObject::splicePrototype(JSContext *cx,
             if (prop && prop->types.hasPropagatedProperty())
                 type->getFromPrototypes(cx, prop->id, &prop->types, true);
         }
     }
 
     return true;
 }
 
-void
+TypeObject *
 JSObject::makeLazyType(JSContext *cx)
 {
     JS_ASSERT(hasLazyType());
 
     RootedObject self(cx, this);
     JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(getClass());
     TypeObject *type = cx->compartment->types.newTypeObject(cx, NULL, key, getProto());
     AssertRootingUnnecessary safe(cx);
     if (!type) {
         if (cx->typeInferenceEnabled())
             cx->compartment->types.setPendingNukeTypes(cx);
-        return;
+        return self->type_;
     }
 
     if (!cx->typeInferenceEnabled()) {
         /* This can only happen if types were previously nuked. */
         self->type_ = type;
-        return;
+        return type;
     }
 
     AutoEnterTypeInference enter(cx);
 
     /* Fill in the type according to the state of this object. */
 
     type->singleton = self;
 
@@ -5249,16 +5247,18 @@ JSObject::makeLazyType(JSContext *cx)
 
     if (self->isSlowArray())
         type->flags |= OBJECT_FLAG_NON_DENSE_ARRAY | OBJECT_FLAG_NON_PACKED_ARRAY;
 
     if (IsTypedArrayProto(self))
         type->flags |= OBJECT_FLAG_NON_TYPED_ARRAY;
 
     self->type_ = type;
+
+    return type;
 }
 
 /* static */ inline HashNumber
 TypeObjectEntry::hash(JSObject *proto)
 {
     return PointerHasher<JSObject *, 3>::hash(proto);
 }
 
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -704,17 +704,17 @@ SetInitializerObjectType(JSContext *cx, 
 {
     if (!cx->typeInferenceEnabled())
         return true;
 
     JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
     JS_ASSERT(key != JSProto_Null);
 
     if (UseNewTypeForInitializer(cx, script, pc, key)) {
-        if (!obj->setSingletonType(cx))
+        if (!JSObject::setSingletonType(cx, obj))
             return false;
 
         /*
          * Inference does not account for types of run-once initializer
          * objects, as these may not be created until after the script
          * has been analyzed.
          */
         TypeScript::Monitor(cx, script, pc, ObjectValue(*obj));
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -74,19 +74,19 @@
 #endif
 
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
 /* Some objects (e.g., With) delegate 'this' to another object. */
 static inline JSObject *
-CallThisObjectHook(JSContext *cx, JSObject *obj, Value *argv)
+CallThisObjectHook(JSContext *cx, HandleObject obj, Value *argv)
 {
-    JSObject *thisp = obj->thisObject(cx);
+    JSObject *thisp = JSObject::thisObject(cx, obj);
     if (!thisp)
         return NULL;
     argv[-1].setObject(*thisp);
     return thisp;
 }
 
 /*
  * ECMA requires "the global object", but in embeddings such as the browser,
@@ -114,17 +114,18 @@ js::BoxNonStrictThis(JSContext *cx, cons
     JS_ASSERT(!thisv.isMagic());
 
 #ifdef DEBUG
     JSFunction *fun = call.callee().isFunction() ? call.callee().toFunction() : NULL;
     JS_ASSERT_IF(fun && fun->isInterpreted(), !fun->inStrictMode());
 #endif
 
     if (thisv.isNullOrUndefined()) {
-        JSObject *thisp = call.callee().global().thisObject(cx);
+        Rooted<GlobalObject*> global(cx, &call.callee().global());
+        JSObject *thisp = JSObject::thisObject(cx, global);
         if (!thisp)
             return false;
         call.setThis(ObjectValue(*thisp));
         return true;
     }
 
     if (!thisv.isObject()) {
         if (!js_PrimitiveToObject(cx, &thisv))
@@ -380,17 +381,18 @@ js::Invoke(JSContext *cx, const Value &t
     PodCopy(args.array(), argv, argc);
 
     if (args.thisv().isObject()) {
         /*
          * We must call the thisObject hook in case we are not called from the
          * interpreter, where a prior bytecode has computed an appropriate
          * |this| already.
          */
-        JSObject *thisp = args.thisv().toObject().thisObject(cx);
+        RootedObject thisObj(cx, &args.thisv().toObject());
+        JSObject *thisp = JSObject::thisObject(cx, thisObj);
         if (!thisp)
              return false;
         args.setThis(ObjectValue(*thisp));
     }
 
     if (!Invoke(cx, args))
         return false;
 
@@ -516,17 +518,17 @@ js::Execute(JSContext *cx, HandleScript 
 
     /* The VAROBJFIX option makes varObj == globalObj in global code. */
     if (!cx->hasRunOption(JSOPTION_VAROBJFIX)) {
         if (!scopeChain->setVarObj(cx))
             return false;
     }
 
     /* Use the scope chain as 'this', modulo outerization. */
-    JSObject *thisObj = scopeChain->thisObject(cx);
+    JSObject *thisObj = JSObject::thisObject(cx, scopeChain);
     if (!thisObj)
         return false;
     Value thisv = ObjectValue(*thisObj);
 
     return ExecuteKernel(cx, script, *scopeChain, thisv, EXECUTE_GLOBAL,
                          NULL /* evalInFrame */, rval);
 }
 
@@ -699,18 +701,20 @@ js::TypeOfValue(JSContext *cx, const Val
     if (v.isNumber())
         return JSTYPE_NUMBER;
     if (v.isString())
         return JSTYPE_STRING;
     if (v.isNull())
         return JSTYPE_OBJECT;
     if (v.isUndefined())
         return JSTYPE_VOID;
-    if (v.isObject())
-        return v.toObject().typeOf(cx);
+    if (v.isObject()) {
+        RootedObject obj(cx, &v.toObject());
+        return JSObject::typeOf(cx, obj);
+    }
     JS_ASSERT(v.isBoolean());
     return JSTYPE_BOOLEAN;
 }
 
 /*
  * Enter the new with scope using an object at sp[-1] and associate the depth
  * of the with block with sp + stackIndex.
  */
@@ -1682,17 +1686,17 @@ BEGIN_CASE(JSOP_IN)
         goto error;
     }
     RootedObject &obj = rootObject0;
     obj = &rref.toObject();
     RootedId &id = rootId0;
     FETCH_ELEMENT_ID(obj, -2, id);
     RootedObject &obj2 = rootObject1;
     RootedShape &prop = rootShape0;
-    if (!obj->lookupGeneric(cx, id, &obj2, &prop))
+    if (!JSObject::lookupGeneric(cx, obj, id, &obj2, &prop))
         goto error;
     bool cond = prop != NULL;
     TRY_BRANCH_AFTER_COND(cond, 2);
     regs.sp--;
     regs.sp[-1].setBoolean(cond);
 }
 END_CASE(JSOP_IN)
 
@@ -1780,38 +1784,39 @@ END_CASE(JSOP_PICK)
 BEGIN_CASE(JSOP_SETCONST)
 {
     RootedPropertyName &name = rootName0;
     name = script->getName(regs.pc);
 
     RootedValue &rval = rootValue0;
     rval = regs.sp[-1];
 
-    JSObject &obj = regs.fp()->varObj();
-    if (!obj.defineProperty(cx, name, rval,
-                            JS_PropertyStub, JS_StrictPropertyStub,
-                            JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) {
+    RootedObject &obj = rootObject0;
+    obj = &regs.fp()->varObj();
+    if (!JSObject::defineProperty(cx, obj, name, rval,
+                                  JS_PropertyStub, JS_StrictPropertyStub,
+                                  JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) {
         goto error;
     }
 }
 END_CASE(JSOP_SETCONST);
 
 #if JS_HAS_DESTRUCTURING
 BEGIN_CASE(JSOP_ENUMCONSTELEM)
 {
     RootedValue &rval = rootValue0;
     rval = regs.sp[-3];
 
-    JSObject *obj;
+    RootedObject &obj = rootObject0;
     FETCH_OBJECT(cx, -2, obj);
     RootedId &id = rootId0;
     FETCH_ELEMENT_ID(obj, -1, id);
-    if (!obj->defineGeneric(cx, id, rval,
-                            JS_PropertyStub, JS_StrictPropertyStub,
-                            JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) {
+    if (!JSObject::defineGeneric(cx, obj, id, rval,
+                                 JS_PropertyStub, JS_StrictPropertyStub,
+                                 JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) {
         goto error;
     }
     regs.sp -= 3;
 }
 END_CASE(JSOP_ENUMCONSTELEM)
 #endif
 
 BEGIN_CASE(JSOP_BINDGNAME)
@@ -2133,47 +2138,47 @@ BEGIN_CASE(JSOP_DELNAME)
 
     /* Strict mode code should never contain JSOP_DELNAME opcodes. */
     JS_ASSERT(!script->strictModeCode);
 
     /* ECMA says to return true if name is undefined or inherited. */
     PUSH_BOOLEAN(true);
     if (prop) {
         MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-1]);
-        if (!scope->deleteProperty(cx, name, res, false))
+        if (!JSObject::deleteProperty(cx, scope, name, res, false))
             goto error;
     }
 }
 END_CASE(JSOP_DELNAME)
 
 BEGIN_CASE(JSOP_DELPROP)
 {
     RootedPropertyName &name = rootName0;
     name = script->getName(regs.pc);
 
-    JSObject *obj;
+    RootedObject &obj = rootObject0;
     FETCH_OBJECT(cx, -1, obj);
 
     MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-1]);
-    if (!obj->deleteProperty(cx, name, res, script->strictModeCode))
+    if (!JSObject::deleteProperty(cx, obj, name, res, script->strictModeCode))
         goto error;
 }
 END_CASE(JSOP_DELPROP)
 
 BEGIN_CASE(JSOP_DELELEM)
 {
     /* Fetch the left part and resolve it to a non-null object. */
-    JSObject *obj;
+    RootedObject &obj = rootObject0;
     FETCH_OBJECT(cx, -2, obj);
 
     RootedValue &propval = rootValue0;
     propval = regs.sp[-1];
 
     MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-2]);
-    if (!obj->deleteByValue(cx, propval, res, script->strictModeCode))
+    if (!JSObject::deleteByValue(cx, obj, propval, res, script->strictModeCode))
         goto error;
 
     regs.sp--;
 }
 END_CASE(JSOP_DELELEM)
 
 BEGIN_CASE(JSOP_TOID)
 {
@@ -2356,17 +2361,17 @@ BEGIN_CASE(JSOP_ENUMELEM)
     RootedObject &obj = rootObject0;
     RootedValue &rval = rootValue0;
 
     /* Funky: the value to set is under the [obj, id] pair. */
     FETCH_OBJECT(cx, -2, obj);
     RootedId &id = rootId0;
     FETCH_ELEMENT_ID(obj, -1, id);
     rval = regs.sp[-3];
-    if (!obj->setGeneric(cx, obj, id, &rval, script->strictModeCode))
+    if (!JSObject::setGeneric(cx, obj, obj, id, &rval, script->strictModeCode))
         goto error;
     regs.sp -= 3;
 }
 END_CASE(JSOP_ENUMELEM)
 
 BEGIN_CASE(JSOP_EVAL)
 {
     CallArgs args = CallArgsFromSp(GET_ARGC(regs.pc), regs.sp);
@@ -2864,39 +2869,39 @@ BEGIN_CASE(JSOP_DEFFUN)
     RootedObject &parent = rootObject0;
     parent = &regs.fp()->varObj();
 
     /* ES5 10.5 (NB: with subsequent errata). */
     RootedPropertyName &name = rootName0;
     name = fun->atom->asPropertyName();
     RootedShape &shape = rootShape0;
     RootedObject &pobj = rootObject1;
-    if (!parent->lookupProperty(cx, name, &pobj, &shape))
+    if (!JSObject::lookupProperty(cx, parent, name, &pobj, &shape))
         goto error;
 
     RootedValue &rval = rootValue0;
     rval = ObjectValue(*fun);
 
     do {
         /* Steps 5d, 5f. */
         if (!shape || pobj != parent) {
-            if (!parent->defineProperty(cx, name, rval,
-                                        JS_PropertyStub, JS_StrictPropertyStub, attrs))
+            if (!JSObject::defineProperty(cx, parent, name, rval,
+                                          JS_PropertyStub, JS_StrictPropertyStub, attrs))
             {
                 goto error;
             }
             break;
         }
 
         /* Step 5e. */
         JS_ASSERT(parent->isNative());
         if (parent->isGlobal()) {
             if (shape->configurable()) {
-                if (!parent->defineProperty(cx, name, rval,
-                                            JS_PropertyStub, JS_StrictPropertyStub, attrs))
+                if (!JSObject::defineProperty(cx, parent, name, rval,
+                                              JS_PropertyStub, JS_StrictPropertyStub, attrs))
                 {
                     goto error;
                 }
                 break;
             }
 
             if (shape->isAccessorDescriptor() || !shape->writable() || !shape->enumerable()) {
                 JSAutoByteString bytes;
@@ -2911,17 +2916,17 @@ BEGIN_CASE(JSOP_DEFFUN)
         /*
          * Non-global properties, and global properties which we aren't simply
          * redefining, must be set.  First, this preserves their attributes.
          * Second, this will produce warnings and/or errors as necessary if the
          * specified Call object property is not writable (const).
          */
 
         /* Step 5f. */
-        if (!parent->setProperty(cx, parent, name, &rval, script->strictModeCode))
+        if (!JSObject::setProperty(cx, parent, parent, name, &rval, script->strictModeCode))
             goto error;
     } while (false);
 }
 END_CASE(JSOP_DEFFUN)
 
 BEGIN_CASE(JSOP_LAMBDA)
 {
     /* Load the specified function object literal. */
@@ -3016,17 +3021,17 @@ BEGIN_CASE(JSOP_SETTER)
     } else {
         getter = JS_PropertyStub;
         setter = CastAsStrictPropertyOp(&rval.toObject());
         attrs = JSPROP_SETTER;
     }
     attrs |= JSPROP_ENUMERATE | JSPROP_SHARED;
 
     scratch.setUndefined();
-    if (!obj->defineGeneric(cx, id, scratch, getter, setter, attrs))
+    if (!JSObject::defineGeneric(cx, obj, id, scratch, getter, setter, attrs))
         goto error;
 
     regs.sp += i;
     if (js_CodeSpec[op2].ndefs > js_CodeSpec[op2].nuses) {
         JS_ASSERT(js_CodeSpec[op2].ndefs == js_CodeSpec[op2].nuses + 1);
         regs.sp[-1] = rval;
         assertSameCompartment(cx, regs.sp[-1]);
     }
@@ -3145,21 +3150,22 @@ BEGIN_CASE(JSOP_INITELEM)
      * obj must be an array, so if the current op is the last element
      * initialiser, set the array length to one greater than id.
      */
     if (rref.isMagic(JS_ARRAY_HOLE)) {
         JS_ASSERT(obj->isArray());
         JS_ASSERT(JSID_IS_INT(id));
         JS_ASSERT(uint32_t(JSID_TO_INT(id)) < StackSpace::ARGS_LENGTH_MAX);
         if (JSOp(regs.pc[JSOP_INITELEM_LENGTH]) == JSOP_ENDINIT &&
-            !js_SetLengthProperty(cx, obj, (uint32_t) (JSID_TO_INT(id) + 1))) {
+            !SetLengthProperty(cx, obj, (uint32_t) (JSID_TO_INT(id) + 1)))
+        {
             goto error;
         }
     } else {
-        if (!obj->defineGeneric(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE))
+        if (!JSObject::defineGeneric(cx, obj, id, rref, NULL, NULL, JSPROP_ENUMERATE))
             goto error;
     }
     if (op == JSOP_INITELEM_INC) {
         JS_ASSERT(obj->isArray());
         if (JSID_TO_INT(id) == INT32_MAX) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_SPREAD_TOO_LARGE);
             goto error;
@@ -3181,17 +3187,17 @@ BEGIN_CASE(JSOP_SPREAD)
     RootedValue &iterVal = rootValue0;
     while (iter.next()) {
         if (count == INT32_MAX) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_SPREAD_TOO_LARGE);
             goto error;
         }
         iterVal = iter.value();
-        if (!arr->defineElement(cx, count++, iterVal, NULL, NULL, JSPROP_ENUMERATE))
+        if (!JSObject::defineElement(cx, arr, count++, iterVal, NULL, NULL, JSPROP_ENUMERATE))
             goto error;
     }
     if (!iter.close())
         goto error;
     regs.sp[-2].setInt32(count);
     regs.sp--;
 }
 END_CASE(JSOP_SPREAD)
@@ -3426,17 +3432,17 @@ BEGIN_CASE(JSOP_SETXMLNAME)
 {
     JS_ASSERT(!script->strictModeCode);
 
     Rooted<JSObject*> obj(cx, &regs.sp[-3].toObject());
     RootedValue &rval = rootValue0;
     rval = regs.sp[-1];
     RootedId &id = rootId0;
     FETCH_ELEMENT_ID(obj, -2, id);
-    if (!obj->setGeneric(cx, obj, id, &rval, script->strictModeCode))
+    if (!JSObject::setGeneric(cx, obj, obj, id, &rval, script->strictModeCode))
         goto error;
     rval = regs.sp[-1];
     regs.sp -= 2;
     regs.sp[-1] = rval;
 }
 END_CASE(JSOP_SETXMLNAME)
 
 BEGIN_CASE(JSOP_CALLXMLNAME)
@@ -3445,17 +3451,17 @@ BEGIN_CASE(JSOP_XMLNAME)
     JS_ASSERT(!script->strictModeCode);
 
     Value lval = regs.sp[-1];
     RootedObject &obj = rootObject0;
     RootedId &id = rootId0;
     if (!js_FindXMLProperty(cx, lval, &obj, id.address()))
         goto error;
     RootedValue &rval = rootValue0;
-    if (!obj->getGeneric(cx, id, &rval))
+    if (!JSObject::getGeneric(cx, obj, obj, id, &rval))
         goto error;
     regs.sp[-1] = rval;
     if (op == JSOP_CALLXMLNAME) {
         Value v;
         if (!ComputeImplicitThis(cx, obj, &v))
             goto error;
         PUSH_COPY(v);
     }
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -50,31 +50,31 @@ namespace js {
  * in the interpreter and JITs will leave undefined as |this|. If funval is a
  * function not in strict mode, JSOP_THIS code replaces undefined with funval's
  * global.
  *
  * We set *vp to undefined early to reduce code size and bias this code for the
  * common and future-friendly cases.
  */
 inline bool
-ComputeImplicitThis(JSContext *cx, JSObject *obj, Value *vp)
+ComputeImplicitThis(JSContext *cx, HandleObject obj, Value *vp)
 {
     vp->setUndefined();
 
     if (obj->isGlobal())
         return true;
 
     if (IsCacheableNonGlobalScope(obj))
         return true;
 
-    obj = obj->thisObject(cx);
-    if (!obj)
+    RawObject nobj = JSObject::thisObject(cx, obj);
+    if (!nobj)
         return false;
 
-    vp->setObject(*obj);
+    vp->setObject(*nobj);
     return true;
 }
 
 inline bool
 ComputeThis(JSContext *cx, StackFrame *fp)
 {
     Value &thisv = fp->thisValue();
     if (thisv.isObject())
@@ -196,17 +196,17 @@ GetPropertyGenericMaybeCallXML(JSContext
      * Various XML properties behave differently when accessed in a
      * call vs. normal context, and getGeneric will not work right.
      */
 #if JS_HAS_XML_SUPPORT
     if (op == JSOP_CALLPROP && obj->isXML())
         return js_GetXMLMethod(cx, obj, id, vp);
 #endif
 
-    return obj->getGeneric(cx, id, vp);
+    return JSObject::getGeneric(cx, obj, obj, id, vp);
 }
 
 inline bool
 GetPropertyOperation(JSContext *cx, jsbytecode *pc, MutableHandleValue lval, MutableHandleValue vp)
 {
     JS_ASSERT(vp.address() != lval.address());
 
     JSOp op = JSOp(*pc);
@@ -340,17 +340,17 @@ SetPropertyOperation(JSContext *cx, jsby
     bool strict = cx->stack.currentScript()->strictModeCode;
     RootedValue rref(cx, rval);
 
     RootedId id(cx, NameToId(name));
     if (JS_LIKELY(!obj->getOps()->setProperty)) {
         if (!baseops::SetPropertyHelper(cx, obj, obj, id, DNP_CACHE_RESULT, &rref, strict))
             return false;
     } else {
-        if (!obj->setGeneric(cx, obj, id, &rref, strict))
+        if (!JSObject::setGeneric(cx, obj, obj, id, &rref, strict))
             return false;
     }
 
     return true;
 }
 
 inline bool
 IntrinsicNameOperation(JSContext *cx, JSScript *script, jsbytecode *pc, Value *vp)
@@ -402,17 +402,17 @@ NameOperation(JSContext *cx, JSScript *s
             js_ReportIsNotDefined(cx, printable.ptr());
         return false;
     }
 
     /* Take the slow path if the property was not found on a native object. */
     if (!scope->isNative() || !pobj->isNative()) {
         RootedId id(cx, NameToId(name));
         RootedValue value(cx);
-        if (!scope->getGeneric(cx, id, &value))
+        if (!JSObject::getGeneric(cx, scope, scope, id, &value))
             return false;
         *vp = value;
     } else {
         RootedObject normalized(cx, scope);
         if (normalized->getClass() == &WithClass && !shape->hasDefaultGetter())
             normalized = &normalized->asWith().object();
         if (!NativeGet(cx, normalized, pobj, shape, 0, vp))
             return false;
@@ -438,44 +438,44 @@ SetNameOperation(JSContext *cx, jsbyteco
      * directly and pass DNP_UNQUALIFIED.
      */
     if (scope->isGlobal()) {
         JS_ASSERT(!scope->getOps()->setProperty);
         RootedId id(cx, NameToId(name));
         return baseops::SetPropertyHelper(cx, scope, scope, id, DNP_UNQUALIFIED, &valCopy, strict);
     }
 
-    return scope->setProperty(cx, scope, name, &valCopy, strict);
+    return JSObject::setProperty(cx, scope, scope, name, &valCopy, strict);
 }
 
 inline bool
 DefVarOrConstOperation(JSContext *cx, HandleObject varobj, HandlePropertyName dn, unsigned attrs)
 {
     JS_ASSERT(varobj->isVarObj());
     JS_ASSERT(!varobj->getOps()->defineProperty || varobj->isDebugScope());
 
     RootedShape prop(cx);
     RootedObject obj2(cx);
-    if (!varobj->lookupProperty(cx, dn, &obj2, &prop))
+    if (!JSObject::lookupProperty(cx, varobj, dn, &obj2, &prop))
         return false;
 
     /* Steps 8c, 8d. */
     if (!prop || (obj2 != varobj && varobj->isGlobal())) {
         RootedValue value(cx, UndefinedValue());
-        if (!varobj->defineProperty(cx, dn, value, JS_PropertyStub,
-                                    JS_StrictPropertyStub, attrs)) {
+        if (!JSObject::defineProperty(cx, varobj, dn, value, JS_PropertyStub,
+                                      JS_StrictPropertyStub, attrs)) {
             return false;
         }
     } else {
         /*
          * Extension: ordinarily we'd be done here -- but for |const|.  If we
          * see a redeclaration that's |const|, we consider it a conflict.
          */
         unsigned oldAttrs;
-        if (!varobj->getPropertyAttributes(cx, dn, &oldAttrs))
+        if (!JSObject::getPropertyAttributes(cx, varobj, dn, &oldAttrs))
             return false;
         if (attrs & JSPROP_READONLY) {
             JSAutoByteString bytes;
             if (js_AtomToPrintableString(cx, dn, &bytes)) {
                 JS_ALWAYS_FALSE(JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
                                                              js_GetErrorMessage,
                                                              NULL, JSMSG_REDECLARED_VAR,
                                                              (oldAttrs & JSPROP_READONLY)
@@ -680,42 +680,42 @@ GetObjectElementOperation(JSContext *cx,
                     res.set(obj->getDenseArrayElement(index));
                     if (!res.isMagic())
                         break;
                 }
             } else if (obj->isArguments()) {
                 if (obj->asArguments().maybeGetElement(index, res))
                     break;
             }
-            if (!obj->getElement(cx, index, res))
+            if (!JSObject::getElement(cx, obj, obj, index, res))
                 return false;
         } while(0);
     } else {
         JSScript *script;
         jsbytecode *pc;
         types::TypeScript::GetPcScript(cx, &script, &pc);
 
         if (script->hasAnalysis())
             script->analysis()->getCode(pc).getStringElement = true;
 
         SpecialId special;
         res.set(rref);
         if (ValueIsSpecial(obj, res, &special, cx)) {
-            if (!obj->getSpecial(cx, obj, special, res))
+            if (!JSObject::getSpecial(cx, obj, obj, special, res))
                 return false;
         } else {
             JSAtom *name = ToAtom(cx, res);
             if (!name)
                 return false;
 
             if (name->isIndex(&index)) {
-                if (!obj->getElement(cx, index, res))
+                if (!JSObject::getElement(cx, obj, obj, index, res))
                     return false;
             } else {
-                if (!obj->getProperty(cx, name->asPropertyName(), res))
+                if (!JSObject::getProperty(cx, obj, obj, name->asPropertyName(), res))
                     return false;
             }
         }
     }
 
     assertSameCompartment(cx, res);
     return true;
 }
@@ -795,17 +795,17 @@ SetObjectElementOperation(JSContext *cx,
 
                 if (script->hasAnalysis())
                     script->analysis()->getCode(pc).arrayWriteHole = true;
             }
         }
     } while (0);
 
     RootedValue tmp(cx, value);
-    return obj->setGeneric(cx, obj, id, &tmp, strict);
+    return JSObject::setGeneric(cx, obj, obj, id, &tmp, strict);
 }
 
 #define RELATIONAL_OP(OP)                                                     \
     JS_BEGIN_MACRO                                                            \
         RootedValue lvalRoot(cx, lhs), rvalRoot(cx, rhs);                     \
         Value &lval = lvalRoot.get();                                         \
         Value &rval = rvalRoot.get();                                         \
         /* Optimize for two int-tagged operands (typical loop control). */    \
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -245,25 +245,25 @@ Snapshot(JSContext *cx, RawObject obj_, 
                     if (!Enumerate(cx, obj, pobj, proxyProps[n], true, flags, ht, props))
                         return false;
                 }
                 /* Proxy objects enumerate the prototype on their own, so we are done here. */
                 break;
             }
             Value state;
             JSIterateOp op = (flags & JSITER_HIDDEN) ? JSENUMERATE_INIT_ALL : JSENUMERATE_INIT;
-            if (!pobj->enumerate(cx, op, &state, NULL))
+            if (!JSObject::enumerate(cx, pobj, op, &state, NULL))
                 return false;
             if (state.isMagic(JS_NATIVE_ENUMERATE)) {
                 if (!EnumerateNativeProperties(cx, obj, pobj, flags, ht, props))
                     return false;
             } else {
                 while (true) {
                     jsid id;
-                    if (!pobj->enumerate(cx, JSENUMERATE_NEXT, &state, &id))
+                    if (!JSObject::enumerate(cx, pobj, JSENUMERATE_NEXT, &state, &id))
                         return false;
                     if (state.isNull())
                         break;
                     if (!Enumerate(cx, obj, pobj, id, true, flags, ht, props))
                         return false;
                 }
             }
         }
@@ -567,17 +567,17 @@ UpdateNativeIterator(NativeIterator *ni,
 }
 
 bool
 GetIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleValue vp)
 {
     if (flags == JSITER_FOR_OF) {
         // for-of loop. The iterator is simply |obj.iterator()|.
         RootedValue method(cx);
-        if (!obj->getProperty(cx, obj, cx->runtime->atomState.iteratorAtom, &method))
+        if (!JSObject::getProperty(cx, obj, obj, cx->runtime->atomState.iteratorAtom, &method))
             return false;
 
         // Throw if obj.iterator isn't callable. js::Invoke is about to check
         // for this kind of error anyway, but it would throw an inscrutable
         // error message about |method| rather than this nice one about |obj|.
         if (!method.isObject() || !method.toObject().isCallable()) {
             RootedValue val(cx, ObjectOrNullValue(obj));
             char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, val, NullPtr());
@@ -885,17 +885,17 @@ ElementIteratorObject::next_impl(JSConte
 
     // Get target.length.
     if (target.isString()) {
         length = uint32_t(target.toString()->length());
     } else {
         obj = ToObjectFromStack(cx, target);
         if (!obj)
             goto close;
-        if (!js_GetLengthProperty(cx, obj, &length))
+        if (!GetLengthProperty(cx, obj, &length))
             goto close;
     }
 
     // Check target.length.
     i = uint32_t(iterobj->getReservedSlot(IndexSlot).toInt32());
     if (i >= length) {
         js_ThrowStopIteration(cx);
         goto close;
@@ -904,17 +904,17 @@ ElementIteratorObject::next_impl(JSConte
     // Get target[i].
     JS_ASSERT(i + 1 > i);
     if (target.isString()) {
         JSString *c = cx->runtime->staticStrings.getUnitStringForElement(cx, target.toString(), i);
         if (!c)
             goto close;
         args.rval().setString(c);
     } else {
-        if (!obj->getElement(cx, obj, i, args.rval()))
+        if (!JSObject::getElement(cx, obj, obj, i, args.rval()))
             goto close;
     }
 
     // On success, bump the index.
     iterobj->setReservedSlot(IndexSlot, Int32Value(int32_t(i + 1)));
     return true;
 
   close:
@@ -1074,29 +1074,28 @@ SuppressDeletedPropertyHelper(JSContext 
             HeapPtr<JSFlatString> *props_end = ni->end();
             for (HeapPtr<JSFlatString> *idp = props_cursor; idp < props_end; ++idp) {
                 if (predicate(*idp)) {
                     /*
                      * Check whether another property along the prototype chain
                      * became visible as a result of this deletion.
                      */
                     if (obj->getProto()) {
-                        JSObject *proto = obj->getProto();
-                        RootedObject obj2(cx);
+                        RootedObject proto(cx, obj->getProto()), obj2(cx);
                         RootedShape prop(cx);
                         RootedId id(cx);
                         if (!ValueToId(cx, StringValue(*idp), id.address()))
                             return false;
-                        if (!proto->lookupGeneric(cx, id, &obj2, &prop))
+                        if (!JSObject::lookupGeneric(cx, proto, id, &obj2, &prop))
                             return false;
                         if (prop) {
                             unsigned attrs;
                             if (obj2->isNative())
                                 attrs = prop->attributes();
-                            else if (!obj2->getGenericAttributes(cx, id, &attrs))
+                            else if (!JSObject::getGenericAttributes(cx, obj2, id, &attrs))
                                 return false;
 
                             if (attrs & JSPROP_ENUMERATE)
                                 continue;
                         }
                     }
 
                     /*
@@ -1212,17 +1211,18 @@ js_IteratorMore(JSContext *cx, HandleObj
 
     /* Fetch and cache the next value from the iterator. */
     if (ni) {
         JS_ASSERT(!ni->isKeyIter());
         RootedId id(cx);
         if (!ValueToId(cx, StringValue(*ni->current()), id.address()))
             return false;
         ni->incCursor();
-        if (!ni->obj->getGeneric(cx, id, rval))
+        RootedObject obj(cx, ni->obj);
+        if (!JSObject::getGeneric(cx, obj, obj, id, rval))
             return false;
         if ((ni->flags & JSITER_KEYVALUE) && !NewKeyValuePair(cx, id, rval, rval))
             return false;
     } else {
         /* Call the iterator object's .next method. */
         if (!GetMethod(cx, iterobj, cx->runtime->atomState.nextAtom, 0, rval))
             return false;
         if (!Invoke(cx, ObjectValue(*iterobj), rval, 0, NULL, rval.address())) {
@@ -1783,17 +1783,17 @@ GlobalObject::initIteratorClasses(JSCont
         if (!proto || !DefinePropertiesAndBrand(cx, proto, NULL, generator_methods))
             return false;
         global->setReservedSlot(GENERATOR_PROTO, ObjectValue(*proto));
     }
 #endif
 
     if (global->getPrototype(JSProto_StopIteration).isUndefined()) {
         proto = global->createBlankPrototype(cx, &StopIterationClass);
-        if (!proto || !proto->freeze(cx))
+        if (!proto || !JSObject::freeze(cx, proto))
             return false;
 
         /* This should use a non-JSProtoKey'd slot, but this is easier for now. */
         if (!DefineConstructorAndPrototype(cx, global, JSProto_StopIteration, proto, proto))
             return false;
 
         MarkStandardClassInitializedNoProto(global, &StopIterationClass);
     }
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -659,17 +659,17 @@ static JSFunctionSpec math_static_method
     JS_FS_END
 };
 
 JSObject *
 js_InitMathClass(JSContext *cx, JSObject *obj_)
 {
     RootedObject obj(cx, obj_);
     RootedObject Math(cx, NewObjectWithClassProto(cx, &MathClass, NULL, obj));
-    if (!Math || !Math->setSingletonType(cx))
+    if (!Math || !JSObject::setSingletonType(cx, Math))
         return NULL;
 
     if (!JS_DefineProperty(cx, obj, js_Math_str, OBJECT_TO_JSVAL(Math),
                            JS_PropertyStub, JS_StrictPropertyStub, 0)) {
         return NULL;
     }
 
     if (!JS_DefineFunctions(cx, Math, math_static_methods))
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -122,17 +122,17 @@ MarkSharpObjects(JSContext *cx, HandleOb
             return false;
 
         bool ok = true;
         RootedId id(cx);
         for (int i = 0, length = ida->length; i < length; i++) {
             id = ida->vector[i];
             RootedObject obj2(cx);
             RootedShape prop(cx);
-            ok = obj->lookupGeneric(cx, id, &obj2, &prop);
+            ok = JSObject::lookupGeneric(cx, obj, id, &obj2, &prop);
             if (!ok)
                 break;
             if (!prop)
                 continue;
             bool hasGetter, hasSetter;
             RootedValue value(cx), setter(cx);
             if (obj2->isNative()) {
                 Shape *shape = (Shape *) prop;
@@ -150,17 +150,17 @@ MarkSharpObjects(JSContext *cx, HandleOb
                 if (hasGetter && value.isObject()) {
                     Rooted<JSObject*> vobj(cx, &value.toObject());
                     ok = MarkSharpObjects(cx, vobj, NULL, NULL);
                     if (!ok)
                         break;
                 }
                 value = setter;
             } else if (!hasGetter) {
-                ok = obj->getGeneric(cx, id, &value);
+                ok = JSObject::getGeneric(cx, obj, obj, id, &value);
                 if (!ok)
                     break;
             }
             if (value.isObject()) {
                 Rooted<JSObject*> vobj(cx, &value.toObject());
                 if (!MarkSharpObjects(cx, vobj, NULL, NULL)) {
                     ok = false;
                     break;
@@ -404,17 +404,17 @@ obj_toSource(JSContext *cx, unsigned arg
     RootedId id(cx);
     for (int i = 0; i < ida->length; i++) {
         /* Get strings for id and value and GC-root them via vp. */
         id = ida->vector[i];
         Rooted<JSLinearString*> idstr(cx);
 
         RootedObject obj2(cx);
         RootedShape prop(cx);
-        if (!obj->lookupGeneric(cx, id, &obj2, &prop))
+        if (!JSObject::lookupGeneric(cx, obj, id, &obj2, &prop))
             return false;
 
         /*
          * Convert id to a value and then to a string.  Decide early whether we
          * prefer get/set or old getter/setter syntax.
          */
         JSString *s = ToString(cx, IdToValue(id));
         if (!s || !(idstr = s->ensureLinear(cx)))
@@ -437,17 +437,18 @@ obj_toSource(JSContext *cx, unsigned arg
                     val[valcnt] = shape->setterValue();
                     gsop[valcnt] = cx->runtime->atomState.setAtom;
                     valcnt++;
                 }
             }
             if (doGet) {
                 valcnt = 1;
                 gsop[0] = NULL;
-                if (!obj->getGeneric(cx, id, MutableHandleValue::fromMarkedLocation(&val[0])))
+                MutableHandleValue vp = MutableHandleValue::fromMarkedLocation(&val[0]);
+                if (!JSObject::getGeneric(cx, obj, obj, id, vp))
                     return false;
             }
         }
 
         /*
          * If id is a string that's not an identifier, or if it's a negative
          * integer, then it must be quoted.
          */
@@ -857,17 +858,17 @@ obj_propertyIsEnumerable(JSContext *cx, 
     return js_PropertyIsEnumerable(cx, obj, id, args.rval().address());
 }
 
 JSBool
 js_PropertyIsEnumerable(JSContext *cx, HandleObject obj, HandleId id, Value *vp)
 {
     RootedObject pobj(cx);
     RootedShape prop(cx);
-    if (!obj->lookupGeneric(cx, id, &pobj, &prop))
+    if (!JSObject::lookupGeneric(cx, obj, id, &pobj, &prop))
         return false;
 
     if (!prop) {
         vp->setBoolean(false);
         return true;
     }
 
     /*
@@ -875,17 +876,17 @@ js_PropertyIsEnumerable(JSContext *cx, H
      * of propertyIsEnumerable's name was a mistake.
      */
     if (pobj != obj) {
         vp->setBoolean(false);
         return true;
     }
 
     unsigned attrs;
-    if (!pobj->getGenericAttributes(cx, id, &attrs))
+    if (!JSObject::getGenericAttributes(cx, pobj, id, &attrs))
         return false;
 
     vp->setBoolean((attrs & JSPROP_ENUMERATE) != 0);
     return true;
 }
 
 #if OLD_GETTER_SETTER_METHODS
 
@@ -913,27 +914,27 @@ DefineAccessor(JSContext *cx, unsigned a
     RootedObject descObj(cx, NewBuiltinClassInstance(cx, &ObjectClass));
     if (!descObj)
         return false;
 
     JSAtomState &state = cx->runtime->atomState;
     RootedValue trueVal(cx, BooleanValue(true));
 
     /* enumerable: true */
-    if (!descObj->defineProperty(cx, state.enumerableAtom, trueVal))
+    if (!JSObject::defineProperty(cx, descObj, state.enumerableAtom, trueVal))
         return false;
 
     /* configurable: true */
-    if (!descObj->defineProperty(cx, state.configurableAtom, trueVal))
+    if (!JSObject::defineProperty(cx, descObj, state.configurableAtom, trueVal))
         return false;
 
     /* enumerable: true */
     PropertyName *acc = (Type == Getter) ? state.getAtom : state.setAtom;
     RootedValue accessorVal(cx, args[1]);
-    if (!descObj->defineProperty(cx, acc, accessorVal))
+    if (!JSObject::defineProperty(cx, descObj, acc, accessorVal))
         return false;
 
     RootedObject thisObj(cx, &args.thisv().toObject());
 
     JSBool dummy;
     if (!js_DefineOwnProperty(cx, thisObj, id, ObjectValue(*descObj), &dummy)) {
         return false;
     }
@@ -972,17 +973,17 @@ obj_lookupGetter(JSContext *cx, unsigned
         if (!Proxy::getPropertyDescriptor(cx, obj, id, false, &desc))
             return JS_FALSE;
         if (desc.obj && (desc.attrs & JSPROP_GETTER) && desc.getter)
             args.rval().set(CastAsObjectJsval(desc.getter));
         return JS_TRUE;
     }
     RootedObject pobj(cx);
     RootedShape shape(cx);
-    if (!obj->lookupGeneric(cx, id, &pobj, &shape))
+    if (!JSObject::lookupGeneric(cx, obj, id, &pobj, &shape))
         return JS_FALSE;
     args.rval().setUndefined();
     if (shape) {
         if (pobj->isNative()) {
             if (shape->hasGetterValue())
                 args.rval().set(shape->getterValue());
         }
     }
@@ -1008,17 +1009,17 @@ obj_lookupSetter(JSContext *cx, unsigned
         if (!Proxy::getPropertyDescriptor(cx, obj, id, false, &desc))
             return JS_FALSE;
         if (desc.obj && (desc.attrs & JSPROP_SETTER) && desc.setter)
             args.rval().set(CastAsObjectJsval(desc.setter));
         return JS_TRUE;
     }
     RootedObject pobj(cx);
     RootedShape shape(cx);
-    if (!obj->lookupGeneric(cx, id, &pobj, &shape))
+    if (!JSObject::lookupGeneric(cx, obj, id, &pobj, &shape))
         return JS_FALSE;
     args.rval().setUndefined();
     if (shape) {
         if (pobj->isNative()) {
             if (shape->hasSetterValue())
                 args.rval().set(shape->setterValue());
         }
     }
@@ -1128,27 +1129,27 @@ PropDesc::makeObject(JSContext *cx)
     if (!obj)
         return false;
 
     const JSAtomState &atomState = cx->runtime->atomState;
     RootedValue configurableVal(cx, BooleanValue((attrs & JSPROP_PERMANENT) == 0));
     RootedValue enumerableVal(cx, BooleanValue((attrs & JSPROP_ENUMERATE) != 0));
     RootedValue writableVal(cx, BooleanValue((attrs & JSPROP_READONLY) == 0));
     if ((hasConfigurable() &&
-         !obj->defineProperty(cx, atomState.configurableAtom, configurableVal)) ||
+         !JSObject::defineProperty(cx, obj, atomState.configurableAtom, configurableVal)) ||
         (hasEnumerable() &&
-         !obj->defineProperty(cx, atomState.enumerableAtom, enumerableVal)) ||
+         !JSObject::defineProperty(cx, obj, atomState.enumerableAtom, enumerableVal)) ||
         (hasGet() &&
-         !obj->defineProperty(cx, atomState.getAtom, getterValue())) ||
+         !JSObject::defineProperty(cx, obj, atomState.getAtom, getterValue())) ||
         (hasSet() &&
-         !obj->defineProperty(cx, atomState.setAtom, setterValue())) ||
+         !JSObject::defineProperty(cx, obj, atomState.setAtom, setterValue())) ||
         (hasValue() &&
-         !obj->defineProperty(cx, atomState.valueAtom, value())) ||
+         !JSObject::defineProperty(cx, obj, atomState.valueAtom, value())) ||
         (hasWritable() &&
-         !obj->defineProperty(cx, atomState.writableAtom, writableVal)))
+         !JSObject::defineProperty(cx, obj, atomState.writableAtom, writableVal)))
     {
         return false;
     }
 
     pd_.setObject(*obj);
     return true;
 }
 
@@ -1173,22 +1174,22 @@ GetOwnPropertyDescriptor(JSContext *cx, 
         if (desc->attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
             doGet = false;
             if (desc->attrs & JSPROP_GETTER)
                 desc->getter = CastAsPropertyOp(shape->getterObject());
             if (desc->attrs & JSPROP_SETTER)
                 desc->setter = CastAsStrictPropertyOp(shape->setterObject());
         }
     } else {
-        if (!pobj->getGenericAttributes(cx, id, &desc->attrs))
+        if (!JSObject::getGenericAttributes(cx, pobj, id, &desc->attrs))
             return false;
     }
 
     RootedValue value(cx);
-    if (doGet && !obj->getGeneric(cx, id, &value))
+    if (doGet && !JSObject::getGeneric(cx, obj, obj, id, &value))
         return false;
 
     desc->value = value;
     desc->obj = obj;
     return true;
 }
 
 bool
@@ -1273,30 +1274,30 @@ obj_keys(JSContext *cx, unsigned argc, V
     vp->setObject(*aobj);
 
     return true;
 }
 
 static bool
 HasProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp, bool *foundp)
 {
-    if (!obj->hasProperty(cx, id, foundp, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING))
+    if (!JSObject::hasProperty(cx, obj, id, foundp, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING))
         return false;
     if (!*foundp) {
         vp.setUndefined();
         return true;
     }
 
     /*
      * We must go through the method read barrier in case id is 'get' or 'set'.
      * There is no obvious way to defer cloning a joined function object whose
      * identity will be used by DefinePropertyOnObject, e.g., or reflected via
      * js::GetOwnPropertyDescriptor, as the getter or setter callable object.
      */
-    return !!obj->getGeneric(cx, id, vp);
+    return !!JSObject::getGeneric(cx, obj, obj, id, vp);
 }
 
 bool
 PropDesc::initialize(JSContext *cx, const Value &origval, bool checkAccessors)
 {
     RootedValue v(cx, origval);
 
     /* 8.10.5 step 1 */
@@ -1905,18 +1906,22 @@ ReadPropertyDescriptors(JSContext *cx, H
     if (!GetPropertyNames(cx, props, JSITER_OWNONLY, ids))
         return false;
 
     RootedId id(cx);
     for (size_t i = 0, len = ids->length(); i < len; i++) {
         id = (*ids)[i];
         PropDesc* desc = descs->append();
         RootedValue v(cx);
-        if (!desc || !props->getGeneric(cx, id, &v) || !desc->initialize(cx, v, checkAccessors))
+        if (!desc ||
+            !JSObject::getGeneric(cx, props, props, id, &v) ||
+            !desc->initialize(cx, v, checkAccessors))
+        {
             return false;
+        }
     }
     return true;
 }
 
 } /* namespace js */
 
 static bool
 DefineProperties(JSContext *cx, HandleObject obj, HandleObject props)
@@ -2092,88 +2097,87 @@ obj_preventExtensions(JSContext *cx, uns
 JSObject::getSealedOrFrozenAttributes(unsigned attrs, ImmutabilityType it)
 {
     /* Make all attributes permanent; if freezing, make data attributes read-only. */
     if (it == FREEZE && !(attrs & (JSPROP_GETTER | JSPROP_SETTER)))
         return JSPROP_PERMANENT | JSPROP_READONLY;
     return JSPROP_PERMANENT;
 }
 
-bool
-JSObject::sealOrFreeze(JSContext *cx, ImmutabilityType it)
-{
-    RootedObject self(cx, this);
-    assertSameCompartment(cx, this);
+/* static */ bool
+JSObject::sealOrFreeze(JSContext *cx, HandleObject obj, ImmutabilityType it)
+{
+    assertSameCompartment(cx, obj);
     JS_ASSERT(it == SEAL || it == FREEZE);
 
-    if (isExtensible() && !preventExtensions(cx))
+    if (obj->isExtensible() && !obj->preventExtensions(cx))
         return false;
 
     AutoIdVector props(cx);
-    if (!GetPropertyNames(cx, self, JSITER_HIDDEN | JSITER_OWNONLY, &props))
+    if (!GetPropertyNames(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY, &props))
         return false;
 
     /* preventExtensions must slowify dense arrays, so we can assign to holes without checks. */
-    JS_ASSERT(!self->isDenseArray());
-
-    if (self->isNative() && !self->inDictionaryMode()) {
+    JS_ASSERT(!obj->isDenseArray());
+
+    if (obj->isNative() && !obj->inDictionaryMode()) {
         /*
          * Seal/freeze non-dictionary objects by constructing a new shape
          * hierarchy mirroring the original one, which can be shared if many
          * objects with the same structure are sealed/frozen. If we use the
          * generic path below then any non-empty object will be converted to
          * dictionary mode.
          */
-        Shape *last = EmptyShape::getInitialShape(cx, self->getClass(),
-                                                  self->getProto(),
-                                                  self->getParent(),
-                                                  self->getAllocKind(),
-                                                  self->lastProperty()->getObjectFlags());
+        Shape *last = EmptyShape::getInitialShape(cx, obj->getClass(),
+                                                  obj->getProto(),
+                                                  obj->getParent(),
+                                                  obj->getAllocKind(),
+                                                  obj->lastProperty()->getObjectFlags());
         if (!last)
             return false;
 
         /* Get an in order list of the shapes in this object. */
         AutoShapeVector shapes(cx);
-        for (Shape::Range r = self->lastProperty()->all(); !r.empty(); r.popFront()) {
+        for (Shape::Range r = obj->lastProperty()->all(); !r.empty(); r.popFront()) {
             if (!shapes.append(&r.front()))
                 return false;
         }
         Reverse(shapes.begin(), shapes.end());
 
         for (size_t i = 0; i < shapes.length(); i++) {
             StackShape child(shapes[i]);
             child.attrs |= getSealedOrFrozenAttributes(child.attrs, it);
 
             if (!JSID_IS_EMPTY(child.propid))
-                MarkTypePropertyConfigured(cx, self, child.propid);
-
-            last = cx->propertyTree().getChild(cx, last, self->numFixedSlots(), child);
+                MarkTypePropertyConfigured(cx, obj, child.propid);
+
+            last = cx->propertyTree().getChild(cx, last, obj->numFixedSlots(), child);
             if (!last)
                 return false;
         }
 
-        JS_ASSERT(self->lastProperty()->slotSpan() == last->slotSpan());
-        JS_ALWAYS_TRUE(self->setLastProperty(cx, last));
+        JS_ASSERT(obj->lastProperty()->slotSpan() == last->slotSpan());
+        JS_ALWAYS_TRUE(obj->setLastProperty(cx, last));
     } else {
         RootedId id(cx);
         for (size_t i = 0; i < props.length(); i++) {
             id = props[i];
 
             unsigned attrs;
-            if (!self->getGenericAttributes(cx, id, &attrs))
+            if (!getGenericAttributes(cx, obj, id, &attrs))
                 return false;
 
             unsigned new_attrs = getSealedOrFrozenAttributes(attrs, it);
 
             /* If we already have the attributes we need, skip the setAttributes call. */
             if ((attrs | new_attrs) == attrs)
                 continue;
 
             attrs |= new_attrs;
-            if (!self->setGenericAttributes(cx, id, &attrs))
+            if (!setGenericAttributes(cx, obj, id, &attrs))
                 return false;
         }
     }
 
     return true;
 }
 
 /* static */ bool
@@ -2188,17 +2192,17 @@ JSObject::isSealedOrFrozen(JSContext *cx
     if (!GetPropertyNames(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY, &props))
         return false;
 
     RootedId id(cx);
     for (size_t i = 0, len = props.length(); i < len; i++) {
         id = props[i];
 
         unsigned attrs;
-        if (!obj->getGenericAttributes(cx, id, &attrs))
+        if (!getGenericAttributes(cx, obj, id, &attrs))
             return false;
 
         /*
          * If the property is configurable, this object is neither sealed nor
          * frozen. If the property is a writable data property, this object is
          * not frozen.
          */
         if (!(attrs & JSPROP_PERMANENT) ||
@@ -2218,17 +2222,17 @@ static JSBool
 obj_freeze(JSContext *cx, unsigned argc, Value *vp)
 {
     RootedObject obj(cx);
     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.freeze", &obj))
         return false;
 
     vp->setObject(*obj);
 
-    return obj->freeze(cx);
+    return JSObject::freeze(cx, obj);
 }
 
 static JSBool
 obj_isFrozen(JSContext *cx, unsigned argc, Value *vp)
 {
     RootedObject obj(cx);
     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.preventExtensions", &obj))
         return false;
@@ -2244,17 +2248,17 @@ static JSBool
 obj_seal(JSContext *cx, unsigned argc, Value *vp)
 {
     RootedObject obj(cx);
     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.seal", &obj))
         return false;
 
     vp->setObject(*obj);
 
-    return obj->seal(cx);
+    return JSObject::seal(cx, obj);
 }
 
 static JSBool
 obj_isSealed(JSContext *cx, unsigned argc, Value *vp)
 {
     RootedObject obj(cx);
     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.isSealed", &obj))
         return false;
@@ -2539,17 +2543,17 @@ js::NewReshapedObject(JSContext *cx, Han
 
     return res;
 }
 
 JSObject*
 js_CreateThis(JSContext *cx, Class *newclasp, HandleObject callee)
 {
     RootedValue protov(cx);
-    if (!callee->getProperty(cx, cx->runtime->atomState.classPrototypeAtom, &protov))
+    if (!JSObject::getProperty(cx, callee, callee, cx->runtime->atomState.classPrototypeAtom, &protov))
         return NULL;
 
     JSObject *proto = protov.isObjectOrNull() ? protov.toObjectOrNull() : NULL;
     JSObject *parent = callee->getParent();
     gc::AllocKind kind = NewObjectGCKind(cx, newclasp);
     return NewObjectWithClassProto(cx, newclasp, proto, parent, kind);
 }
 
@@ -2593,34 +2597,34 @@ js_CreateThisForFunctionWithProto(JSCont
 
     return res;
 }
 
 JSObject *
 js_CreateThisForFunction(JSContext *cx, HandleObject callee, bool newType)
 {
     RootedValue protov(cx);
-    if (!callee->getProperty(cx, cx->runtime->atomState.classPrototypeAtom, &protov))
+    if (!JSObject::getProperty(cx, callee, callee, cx->runtime->atomState.classPrototypeAtom, &protov))
         return NULL;
     JSObject *proto;
     if (protov.isObject())
         proto = &protov.toObject();
     else
         proto = NULL;
     JSObject *obj = js_CreateThisForFunctionWithProto(cx, callee, proto);
 
     if (obj && newType) {
         RootedObject nobj(cx, obj);
 
         /*
          * Reshape the object and give it a (lazily instantiated) singleton
          * type before passing it as the 'this' value for the call.
          */
         nobj->clear(cx);
-        if (!nobj->setSingletonType(cx))
+        if (!JSObject::setSingletonType(cx, nobj))
             return NULL;
 
         JSScript *calleeScript = callee->toFunction()->script();
         TypeScript::SetThis(cx, calleeScript, types::Type::ObjectType(nobj));
 
         return nobj;
     }
 
@@ -2700,72 +2704,73 @@ js_InferFlags(JSContext *cx, unsigned de
     } else if (cs->length >= 0) {
         pc += cs->length;
         if (pc < script->code + script->length && Detecting(cx, pc))
             flags |= JSRESOLVE_DETECTING;
     }
     return flags;
 }
 
-JSBool
-JSObject::nonNativeSetProperty(JSContext *cx, HandleId id, MutableHandleValue vp, JSBool strict)
-{
-    RootedObject self(cx, this);
-    if (JS_UNLIKELY(watched())) {
+/* static */ JSBool
+JSObject::nonNativeSetProperty(JSContext *cx, HandleObject obj,
+                               HandleId id, MutableHandleValue vp, JSBool strict)
+{
+    if (JS_UNLIKELY(obj->watched())) {
         WatchpointMap *wpmap = cx->compartment->watchpointMap;
-        if (wpmap && !wpmap->triggerWatchpoint(cx, self, id, vp))
+        if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, vp))
             return false;
     }
-    return self->getOps()->setGeneric(cx, self, id, vp, strict);
-}
-
-JSBool
-JSObject::nonNativeSetElement(JSContext *cx, uint32_t index, MutableHandleValue vp, JSBool strict)
-{
-    RootedObject self(cx, this);
-    if (JS_UNLIKELY(watched())) {
+    return obj->getOps()->setGeneric(cx, obj, id, vp, strict);
+}
+
+/* static */ JSBool
+JSObject::nonNativeSetElement(JSContext *cx, HandleObject obj,
+                              uint32_t index, MutableHandleValue vp, JSBool strict)
+{
+    if (JS_UNLIKELY(obj->watched())) {
         RootedId id(cx);
         if (!IndexToId(cx, index, id.address()))
             return false;
 
         WatchpointMap *wpmap = cx->compartment->watchpointMap;
-        if (wpmap && !wpmap->triggerWatchpoint(cx, self, id, vp))
+        if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, vp))
             return false;
     }
-    return self->getOps()->setElement(cx, self, index, vp, strict);
-}
-
-bool
-JSObject::deleteByValue(JSContext *cx, const Value &property, MutableHandleValue rval, bool strict)
+    return obj->getOps()->setElement(cx, obj, index, vp, strict);
+}
+
+/* static */ bool
+JSObject::deleteByValue(JSContext *cx, HandleObject obj,
+                        const Value &property, MutableHandleValue rval, bool strict)
 {
     uint32_t index;
     if (IsDefinitelyIndex(property, &index))
-        return deleteElement(cx, index, rval, strict);
+        return deleteElement(cx, obj, index, rval, strict);
 
     RootedValue propval(cx, property);
     Rooted<SpecialId> sid(cx);
-    if (ValueIsSpecial(this, &propval, sid.address(), cx))
-        return deleteSpecial(cx, sid, rval, strict);
-
-    RootedObject self(cx, this);
+    if (ValueIsSpecial(obj, &propval, sid.address(), cx))
+        return deleteSpecial(cx, obj, sid, rval, strict);
 
     JSAtom *name = ToAtom(cx, propval);
     if (!name)
         return false;
 
     if (name->isIndex(&index))
-        return self->deleteElement(cx, index, rval, false);
+        return deleteElement(cx, obj, index, rval, false);
 
     Rooted<PropertyName*> propname(cx, name->asPropertyName());
-    return self->deleteProperty(cx, propname, rval, false);
+    return deleteProperty(cx, obj, propname, rval, false);
 }
 
 JS_FRIEND_API(bool)
-JS_CopyPropertiesFrom(JSContext *cx, JSObject *target, JSObject *obj)
-{
+JS_CopyPropertiesFrom(JSContext *cx, JSObject *targetArg, JSObject *obj)
+{
+    RootedObject target(cx, targetArg);
+
     // If we're not native, then we cannot copy properties.
     JS_ASSERT(target->isNative() == obj->isNative());
     if (!target->isNative())
         return true;
 
     AutoShapeVector shapes(cx);
     for (Shape::Range r(obj->lastProperty()); !r.empty(); r.popFront()) {
         if (!shapes.append(&r.front()))
@@ -2782,17 +2787,17 @@ JS_CopyPropertiesFrom(JSContext *cx, JSO
         if ((attrs & JSPROP_GETTER) && !cx->compartment->wrap(cx, &getter))
             return false;
         if ((attrs & JSPROP_SETTER) && !cx->compartment->wrap(cx, &setter))
             return false;
         RootedValue v(cx, shape->hasSlot() ? obj->getSlot(shape->slot()) : UndefinedValue());
         if (!cx->compartment->wrap(cx, v.address()))
             return false;
         Rooted<jsid> id(cx, shape->propid());
-        if (!target->defineGeneric(cx, id, v, getter, setter, attrs))
+        if (!JSObject::defineGeneric(cx, target, id, v, getter, setter, attrs))
             return false;
     }
     return true;
 }
 
 static bool
 CopySlots(JSContext *cx, JSObject *from, JSObject *to)
 {
@@ -3179,17 +3184,17 @@ JSObject::swap(JSContext *cx, JSObject *
 
     TradeGuts(cx, this, otherClone, reservedThis);
     TradeGuts(cx, other, thisClone, reservedOther);
 
     return true;
 }
 
 static bool
-DefineStandardSlot(JSContext *cx, JSObject *obj, JSProtoKey key, JSAtom *atom,
+DefineStandardSlot(JSContext *cx, HandleObject obj, JSProtoKey key, JSAtom *atom,
                    HandleValue v, uint32_t attrs, bool &named)
 {
     RootedId id(cx, AtomToId(atom));
 
     if (key != JSProto_Null) {
         /*
          * Initializing an actual standard class on a global object. If the
          * property is not yet present, force it into a new one bound to a
@@ -3206,17 +3211,18 @@ DefineStandardSlot(JSContext *cx, JSObje
                 return false;
             AddTypePropertyId(cx, obj, id, v);
 
             named = true;
             return true;
         }
     }
 
-    named = obj->defineGeneric(cx, id, v, JS_PropertyStub, JS_StrictPropertyStub, attrs);
+    named = JSObject::defineGeneric(cx, obj, id,
+                                    v, JS_PropertyStub, JS_StrictPropertyStub, attrs);
     return named;
 }
 
 namespace js {
 
 static void
 SetClassObject(JSObject *obj, JSProtoKey key, JSObject *cobj, JSObject *proto)
 {
@@ -3275,17 +3281,17 @@ DefineConstructorAndPrototype(JSContext 
      * 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.)
      */
     RootedObject proto(cx, NewObjectWithClassProto(cx, clasp, protoProto, obj));
     if (!proto)
         return NULL;
 
-    if (!proto->setSingletonType(cx))
+    if (!JSObject::setSingletonType(cx, proto))
         return NULL;
 
     if (clasp == &ArrayClass && !JSObject::makeDenseArraySlow(cx, proto))
         return NULL;
 
     /* After this point, control must exit via label bad or out. */
     RootedObject ctor(cx);
     bool named = false;
@@ -3351,34 +3357,34 @@ DefineConstructorAndPrototype(JSContext 
     if (!DefinePropertiesAndBrand(cx, proto, ps, fs) ||
         (ctor != proto && !DefinePropertiesAndBrand(cx, ctor, static_ps, static_fs)))
     {
         goto bad;
     }
 
     if (clasp->flags & (JSCLASS_FREEZE_PROTO|JSCLASS_FREEZE_CTOR)) {
         JS_ASSERT_IF(ctor == proto, !(clasp->flags & JSCLASS_FREEZE_CTOR));
-        if (proto && (clasp->flags & JSCLASS_FREEZE_PROTO) && !proto->freeze(cx))
+        if (proto && (clasp->flags & JSCLASS_FREEZE_PROTO) && !JSObject::freeze(cx, proto))
             goto bad;
-        if (ctor && (clasp->flags & JSCLASS_FREEZE_CTOR) && !ctor->freeze(cx))
+        if (ctor && (clasp->flags & JSCLASS_FREEZE_CTOR) && !JSObject::freeze(cx, ctor))
             goto bad;
     }
 
     /* If this is a standard class, cache its prototype. */
     if (!cached && key != JSProto_Null)
         SetClassObject(obj, key, ctor, proto);
 
     if (ctorp)
         *ctorp = ctor;
     return proto;
 
 bad:
     if (named) {
         RootedValue rval(cx);
-        obj->deleteByValue(cx, StringValue(atom), &rval, false);
+        JSObject::deleteByValue(cx, obj, StringValue(atom), &rval, false);
     }
     if (cached)
         ClearClassObject(cx, obj, key);
     return NULL;
 }
 
 /*
  * Lazy standard classes need a way to indicate if they have been initialized.
@@ -4168,24 +4174,24 @@ DefineNativeProperty(JSContext *cx, Hand
          */
         RootedObject pobj(cx);
         RootedShape prop(cx);
         if (!baseops::LookupProperty(cx, obj, id, &pobj, &prop))
             return NULL;
         if (prop && pobj == obj) {
             shape = prop;
             if (shape->isAccessorDescriptor()) {
-                shape = obj->changeProperty(cx, shape, attrs,
-                                            JSPROP_GETTER | JSPROP_SETTER,
-                                            (attrs & JSPROP_GETTER)
-                                            ? getter
-                                            : shape->getter(),
-                                            (attrs & JSPROP_SETTER)
-                                            ? setter
-                                            : shape->setter());
+                shape = JSObject::changeProperty(cx, obj, shape, attrs,
+                                                 JSPROP_GETTER | JSPROP_SETTER,
+                                                 (attrs & JSPROP_GETTER)
+                                                 ? getter
+                                                 : shape->getter(),
+                                                 (attrs & JSPROP_SETTER)
+                                                 ? setter
+                                                 : shape->setter());
                 if (!shape)
                     return NULL;
             } else {
                 shape = NULL;
             }
         }
     }
 
@@ -4298,17 +4304,17 @@ CallResolveOp(JSContext *cx, HandleObjec
          * compatibility.
          */
         if (!obj2)
             return true;
 
         if (!obj2->isNative()) {
             /* Whoops, newresolve handed back a foreign obj2. */
             JS_ASSERT(obj2 != obj);
-            return obj2->lookupGeneric(cx, id, objp, propp);
+            return JSObject::lookupGeneric(cx, obj2, id, objp, propp);
         }
 
         objp.set(obj2);
     } else {
         if (!resolve(cx, obj, id))
             return false;
 
         objp.set(obj);
@@ -4352,17 +4358,17 @@ LookupPropertyWithFlagsInline(JSContext 
                 return true;
             }
         }
 
         RootedObject proto(cx, current->getProto());
         if (!proto)
             break;
         if (!proto->isNative()) {
-            if (!proto->lookupGeneric(cx, id, objp, propp))
+            if (!JSObject::lookupGeneric(cx, proto, id, objp, propp))
                 return false;
 #ifdef DEBUG
             /*
              * Non-native objects must have either non-native lookup results,
              * or else native results from the non-native's prototype chain.
              *
              * See StackFrame::getValidCalleeObject, where we depend on this
              * fact to force a prototype-delegated joined method accessed via
@@ -4412,17 +4418,17 @@ js::LookupPropertyWithFlags(JSContext *c
 
 bool
 js::LookupName(JSContext *cx, HandlePropertyName name, HandleObject scopeChain,
                MutableHandleObject objp, MutableHandleObject pobjp, MutableHandleShape propp)
 {
     RootedId id(cx, NameToId(name));
 
     for (RootedObject scope(cx, scopeChain); scope; scope = scope->enclosingScope()) {
-        if (!scope->lookupGeneric(cx, id, pobjp, propp))
+        if (!JSObject::lookupGeneric(cx, scope, id, pobjp, propp))
             return false;
         if (propp) {
             objp.set(scope);
             return true;
         }
     }
 
     objp.set(NULL);
@@ -4437,17 +4443,17 @@ js::LookupNameForSet(JSContext *cx, Hand
 {
     RootedId id(cx, NameToId(name));
 
     RootedObject pobj(cx);
     RootedShape prop(cx);
 
     RootedObject scope(cx, scopeChain);
     for (; !scope->isGlobal(); scope = scope->enclosingScope()) {
-        if (!scope->lookupGeneric(cx, id, &pobj, &prop))
+        if (!JSObject::lookupGeneric(cx, scope, id, &pobj, &prop))
             return false;
         if (prop)
             break;
     }
 
     objp.set(scope);
     return true;
 }
@@ -4620,17 +4626,17 @@ js_GetPropertyHelperInline(JSContext *cx
             }
         }
         return JS_TRUE;
     }
 
     if (!obj2->isNative()) {
         return obj2->isProxy()
                ? Proxy::get(cx, obj2, receiver, id, vp)
-               : obj2->getGeneric(cx, id, vp);
+               : JSObject::getGeneric(cx, obj2, obj2, id, vp);
     }
 
     if (getHow & JSGET_CACHE_RESULT)
         JS_PROPERTY_CACHE(cx).fill(cx, obj, obj2, shape);
 
     /* This call site is hot -- use the always-inlined variant of js_NativeGet(). */
     if (!js_NativeGetInline(cx, receiver, obj, obj2, shape, getHow, vp.address()))
         return JS_FALSE;
@@ -4958,17 +4964,17 @@ baseops::GetAttributes(JSContext *cx, Ha
     RootedShape shape(cx);
     if (!baseops::LookupProperty(cx, obj, id, &nobj, &shape))
         return false;
     if (!shape) {
         *attrsp = 0;
         return true;
     }
     if (!nobj->isNative())
-        return nobj->getGenericAttributes(cx, id, attrsp);
+        return JSObject::getGenericAttributes(cx, nobj, id, attrsp);
 
     *attrsp = shape->attributes();
     return true;
 }
 
 JSBool
 baseops::GetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp)
 {
@@ -4976,48 +4982,48 @@ baseops::GetElementAttributes(JSContext 
     RootedShape shape(cx);
     if (!baseops::LookupElement(cx, obj, index, &nobj, &shape))
         return false;
     if (!shape) {
         *attrsp = 0;
         return true;
     }
     if (!nobj->isNative())
-        return nobj->getElementAttributes(cx, index, attrsp);
+        return JSObject::getElementAttributes(cx, nobj, index, attrsp);
 
     *attrsp = shape->attributes();
     return true;
 }
 
 JSBool
 baseops::SetAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
     RootedObject nobj(cx);
     RootedShape shape(cx);
     if (!baseops::LookupProperty(cx, obj, id, &nobj, &shape))
         return false;
     if (!shape)
         return true;
     return nobj->isNative()
-           ? nobj->changePropertyAttributes(cx, shape, *attrsp)
-           : nobj->setGenericAttributes(cx, id, attrsp);
+           ? JSObject::changePropertyAttributes(cx, nobj, shape, *attrsp)
+           : JSObject::setGenericAttributes(cx, nobj, id, attrsp);
 }
 
 JSBool
 baseops::SetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp)
 {
     RootedObject nobj(cx);
     RootedShape shape(cx);
     if (!baseops::LookupElement(cx, obj, index, &nobj, &shape))
         return false;
     if (!shape)
         return true;
     return nobj->isNative()
-           ? nobj->changePropertyAttributes(cx, shape, *attrsp)
-           : nobj->setElementAttributes(cx, index, attrsp);
+           ? JSObject::changePropertyAttributes(cx, nobj, shape, *attrsp)
+           : JSObject::setElementAttributes(cx, nobj, index, attrsp);
 }
 
 JSBool
 baseops::DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue rval, JSBool strict)
 {
     rval.setBoolean(true);
 
     RootedObject proto(cx);
@@ -5238,17 +5244,17 @@ CheckAccess(JSContext *cx, JSObject *obj
         pobj = obj;
         if (!writing)
             vp->setObjectOrNull(obj->getProto());
         *attrsp = JSPROP_PERMANENT;
         break;
 
       default:
         RootedShape shape(cx);
-        if (!obj->lookupGeneric(cx, id, &pobj, &shape))
+        if (!JSObject::lookupGeneric(cx, obj, id, &pobj, &shape))
             return JS_FALSE;
         if (!shape) {
             if (!writing)
                 vp->setUndefined();
             *attrsp = 0;
             pobj = obj;
             break;
         }
@@ -5315,18 +5321,18 @@ bool
 js::FindClassPrototype(JSContext *cx, HandleObject scopeobj, JSProtoKey protoKey,
                        MutableHandleObject protop, Class *clasp)
 {
     RootedValue v(cx);
     if (!js_FindClassObject(cx, scopeobj, protoKey, &v, clasp))
         return false;
 
     if (IsFunctionObject(v)) {
-        JSObject *ctor = &v.get().toObject();
-        if (!ctor->getProperty(cx, cx->runtime->atomState.classPrototypeAtom, &v))
+        RootedObject ctor(cx, &v.get().toObject());
+        if (!JSObject::getProperty(cx, ctor, ctor, cx->runtime->atomState.classPrototypeAtom, &v))
             return false;
     }
 
     protop.set(v.get().isObject() ? &v.get().toObject() : NULL);
     return true;
 }
 
 /*
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -267,17 +267,17 @@ class WithObject;
 struct JSObject : public js::ObjectImpl
 {
   private:
     friend struct js::Shape;
     friend struct js::GCMarker;
     friend class  js::NewObjectCache;
 
     /* Make the type object to use for LAZY_TYPE objects. */
-    void makeLazyType(JSContext *cx);
+    js::types::TypeObject *makeLazyType(JSContext *cx);
 
   public:
     /*
      * Update the last property, keeping the number of allocated slots in sync
      * with the object's new slot span.
      */
     bool setLastProperty(JSContext *cx, js::Shape *shape);
 
@@ -431,17 +431,17 @@ struct JSObject : public js::ObjectImpl
     inline js::HeapSlot &getReservedSlotRef(unsigned index);
     inline void initReservedSlot(unsigned index, const js::Value &v);
     inline void setReservedSlot(unsigned index, const js::Value &v);
 
     /*
      * Marks this object as having a singleton type, and leave the type lazy.
      * Constructs a new, unique shape for the object.
      */
-    inline bool setSingletonType(JSContext *cx);
+    static inline bool setSingletonType(JSContext *cx, js::HandleObject obj);
 
     inline js::types::TypeObject *getType(JSContext *cx);
 
     const js::HeapPtr<js::types::TypeObject> &typeFromGC() const {
         /* Direct field access for use by GC. */
         return type_;
     }
 
@@ -530,29 +530,29 @@ struct JSObject : public js::ObjectImpl
     enum ImmutabilityType { SEAL, FREEZE };
 
     /*
      * The guts of Object.seal (ES5 15.2.3.8) and Object.freeze (ES5 15.2.3.9): mark the
      * object as non-extensible, and adjust each property's attributes appropriately: each
      * property becomes non-configurable, and if |freeze|, data properties become
      * read-only as well.
      */
-    bool sealOrFreeze(JSContext *cx, ImmutabilityType it);
+    static bool sealOrFreeze(JSContext *cx, js::HandleObject obj, ImmutabilityType it);
 
     static bool isSealedOrFrozen(JSContext *cx, js::HandleObject obj, ImmutabilityType it, bool *resultp);
 
     static inline unsigned getSealedOrFrozenAttributes(unsigned attrs, ImmutabilityType it);
 
   public:
     bool preventExtensions(JSContext *cx);
 
     /* ES5 15.2.3.8: non-extensible, all props non-configurable */
-    inline bool seal(JSContext *cx) { return sealOrFreeze(cx, SEAL); }
+    static inline bool seal(JSContext *cx, js::HandleObject obj) { return sealOrFreeze(cx, obj, SEAL); }
     /* ES5 15.2.3.9: non-extensible, all properties non-configurable, all data props read-only */
-    bool freeze(JSContext *cx) { return sealOrFreeze(cx, FREEZE); }
+    static inline bool freeze(JSContext *cx, js::HandleObject obj) { return sealOrFreeze(cx, obj, FREEZE); }
 
     static inline bool isSealed(JSContext *cx, js::HandleObject obj, bool *resultp) {
         return isSealedOrFrozen(cx, obj, SEAL, resultp);
     }
     static inline bool isFrozen(JSContext *cx, js::HandleObject obj, bool *resultp) {
         return isSealedOrFrozen(cx, obj, FREEZE, resultp);
     }
 
@@ -701,17 +701,18 @@ struct JSObject : public js::ObjectImpl
     /*
      * Back to generic stuff.
      */
     inline bool isCallable();
 
     inline void finish(js::FreeOp *fop);
     JS_ALWAYS_INLINE void finalize(js::FreeOp *fop);
 
-    inline bool hasProperty(JSContext *cx, js::HandleId id, bool *foundp, unsigned flags = 0);
+    static inline bool hasProperty(JSContext *cx, js::HandleObject obj,
+                                   js::HandleId id, bool *foundp, unsigned flags = 0);
 
     /*
      * Allocate and free an object slot.
      *
      * FIXME: bug 593129 -- slot allocation should be done by object methods
      * after calling object-parameter-free shape methods, avoiding coupling
      * logic across the object vs. shape module wall.
      */
@@ -780,100 +781,136 @@ struct JSObject : public js::ObjectImpl
     inline js::Shape *
     putProperty(JSContext *cx, js::PropertyName *name,
                 JSPropertyOp getter, JSStrictPropertyOp setter,
                 uint32_t slot, unsigned attrs, unsigned flags, int shortid) {
         return putProperty(cx, js::NameToId(name), getter, setter, slot, attrs, flags, shortid);
     }
 
     /* Change the given property into a sibling with the same id in this scope. */
-    js::Shape *changeProperty(JSContext *cx, js::Shape *shape, unsigned attrs, unsigned mask,
-                              JSPropertyOp getter, JSStrictPropertyOp setter);
+    static js::Shape *changeProperty(JSContext *cx, js::HandleObject obj,
+                                     js::Shape *shape, unsigned attrs, unsigned mask,
+                                     JSPropertyOp getter, JSStrictPropertyOp setter);
 
-    inline bool changePropertyAttributes(JSContext *cx, js::Shape *shape, unsigned attrs);
+    static inline bool changePropertyAttributes(JSContext *cx, js::HandleObject obj,
+                                                js::Shape *shape, unsigned attrs);
 
     /* Remove the property named by id from this object. */
     bool removeProperty(JSContext *cx, jsid id);
 
     /* Clear the scope, making it empty. */
     void clear(JSContext *cx);
 
-    inline JSBool lookupGeneric(JSContext *cx, js::HandleId id,
-                                js::MutableHandleObject objp, js::MutableHandleShape propp);
-    inline JSBool lookupProperty(JSContext *cx, js::PropertyName *name,
-                                 js::MutableHandleObject objp, js::MutableHandleShape propp);
-    inline JSBool lookupElement(JSContext *cx, uint32_t index,
-                                js::MutableHandleObject objp, js::MutableHandleShape propp);
-    inline JSBool lookupSpecial(JSContext *cx, js::SpecialId sid,
-                                js::MutableHandleObject objp, js::MutableHandleShape propp);
+    static inline JSBool lookupGeneric(JSContext *cx, js::HandleObject obj,
+                                       js::HandleId id,
+                                       js::MutableHandleObject objp, js::MutableHandleShape propp);
+    static inline JSBool lookupProperty(JSContext *cx, js::HandleObject obj,
+                                        js::PropertyName *name,
+                                        js::MutableHandleObject objp, js::MutableHandleShape propp);
+    static inline JSBool lookupElement(JSContext *cx, js::HandleObject obj,
+                                       uint32_t index,
+                                       js::MutableHandleObject objp, js::MutableHandleShape propp);
+    static inline JSBool lookupSpecial(JSContext *cx, js::HandleObject obj,
+                                       js::SpecialId sid,
+                                       js::MutableHandleObject objp, js::MutableHandleShape propp);
 
-    inline JSBool defineGeneric(JSContext *cx, js::HandleId id, js::HandleValue value,
-                                JSPropertyOp getter = JS_PropertyStub,
-                                JSStrictPropertyOp setter = JS_StrictPropertyStub,
-                                unsigned attrs = JSPROP_ENUMERATE);
-    inline JSBool defineProperty(JSContext *cx, js::PropertyName *name, js::HandleValue value,
-                                 JSPropertyOp getter = JS_PropertyStub,
-                                 JSStrictPropertyOp setter = JS_StrictPropertyStub,
-                                 unsigned attrs = JSPROP_ENUMERATE);
+    static inline JSBool defineGeneric(JSContext *cx, js::HandleObject obj,
+                                       js::HandleId id, js::HandleValue value,
+                                       JSPropertyOp getter = JS_PropertyStub,
+                                       JSStrictPropertyOp setter = JS_StrictPropertyStub,
+                                       unsigned attrs = JSPROP_ENUMERATE);
+    static inline JSBool defineProperty(JSContext *cx, js::HandleObject obj,
+                                        js::PropertyName *name, js::HandleValue value,
+                                        JSPropertyOp getter = JS_PropertyStub,
+                                        JSStrictPropertyOp setter = JS_StrictPropertyStub,
+                                        unsigned attrs = JSPROP_ENUMERATE);
 
-    inline JSBool defineElement(JSContext *cx, uint32_t index, js::HandleValue value,
-                                JSPropertyOp getter = JS_PropertyStub,
-                                JSStrictPropertyOp setter = JS_StrictPropertyStub,
-                                unsigned attrs = JSPROP_ENUMERATE);
-    inline JSBool defineSpecial(JSContext *cx, js::SpecialId sid, js::HandleValue value,
-                                JSPropertyOp getter = JS_PropertyStub,
-                                JSStrictPropertyOp setter = JS_StrictPropertyStub,
-                                unsigned attrs = JSPROP_ENUMERATE);
+    static inline JSBool defineElement(JSContext *cx, js::HandleObject obj,
+                                       uint32_t index, js::HandleValue value,
+                                       JSPropertyOp getter = JS_PropertyStub,
+                                       JSStrictPropertyOp setter = JS_StrictPropertyStub,
+                                       unsigned attrs = JSPROP_ENUMERATE);
+    static inline JSBool defineSpecial(JSContext *cx, js::HandleObject obj,
+                                       js::SpecialId sid, js::HandleValue value,
+                                       JSPropertyOp getter = JS_PropertyStub,
+                                       JSStrictPropertyOp setter = JS_StrictPropertyStub,
+                                       unsigned attrs = JSPROP_ENUMERATE);
 
-    inline JSBool getGeneric(JSContext *cx, js::HandleObject receiver, js::HandleId id, js::MutableHandleValue vp);
-    inline JSBool getProperty(JSContext *cx, js::HandleObject receiver, js::PropertyName *name,
-                              js::MutableHandleValue vp);
-    inline JSBool getElement(JSContext *cx, js::HandleObject receiver, uint32_t index, js::MutableHandleValue vp);
+    static inline JSBool getGeneric(JSContext *cx, js::HandleObject obj,
+                                    js::HandleObject receiver,
+                                    js::HandleId id, js::MutableHandleValue vp);
+    static inline JSBool getProperty(JSContext *cx, js::HandleObject obj,
+                                     js::HandleObject receiver,
+                                     js::PropertyName *name, js::MutableHandleValue vp);
+    static inline JSBool getElement(JSContext *cx, js::HandleObject obj,
+                                    js::HandleObject receiver,
+                                    uint32_t index, js::MutableHandleValue vp);
     /* If element is not present (e.g. array hole) *present is set to
        false and the contents of *vp are unusable garbage. */
-    inline JSBool getElementIfPresent(JSContext *cx, js::HandleObject receiver, uint32_t index,
-                                      js::MutableHandleValue vp, bool *present);
-    inline JSBool getSpecial(JSContext *cx, js::HandleObject receiver, js::SpecialId sid, js::MutableHandleValue vp);
-
-    inline JSBool getGeneric(JSContext *cx, js::HandleId id, js::MutableHandleValue vp);
-    inline JSBool getProperty(JSContext *cx, js::PropertyName *name, js::MutableHandleValue vp);
-    inline JSBool getElement(JSContext *cx, uint32_t index, js::MutableHandleValue vp);
-    inline JSBool getSpecial(JSContext *cx, js::SpecialId sid, js::MutableHandleValue vp);
+    static inline JSBool getElementIfPresent(JSContext *cx, js::HandleObject obj,
+                                             js::HandleObject receiver, uint32_t index,
+                                             js::MutableHandleValue vp, bool *present);
+    static inline JSBool getSpecial(JSContext *cx, js::HandleObject obj,
+                                    js::HandleObject receiver, js::SpecialId sid,
+                                    js::MutableHandleValue vp);
 
-    inline JSBool setGeneric(JSContext *cx, js::HandleObject receiver, js::HandleId id,
-                             js::MutableHandleValue vp, JSBool strict);
-    inline JSBool setProperty(JSContext *cx, js::HandleObject receiver,
-                              js::PropertyName *name, js::MutableHandleValue vp, JSBool strict);
-    inline JSBool setElement(JSContext *cx, js::HandleObject receiver, uint32_t index,
-                             js::MutableHandleValue vp, JSBool strict);
-    inline JSBool setSpecial(JSContext *cx, js::HandleObject receiver, js::SpecialId sid,
-                             js::MutableHandleValue vp, JSBool strict);
+    static inline JSBool setGeneric(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
+                                    js::HandleId id,
+                                    js::MutableHandleValue vp, JSBool strict);
+    static inline JSBool setProperty(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
+                                     js::PropertyName *name,
+                                     js::MutableHandleValue vp, JSBool strict);
+    static inline JSBool setElement(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
+                                    uint32_t index,
+                                    js::MutableHandleValue vp, JSBool strict);
+    static inline JSBool setSpecial(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
+                                    js::SpecialId sid,
+                                    js::MutableHandleValue vp, JSBool strict);
+
+    static JSBool nonNativeSetProperty(JSContext *cx, js::HandleObject obj,
+                                       js::HandleId id, js::MutableHandleValue vp, JSBool strict);
+    static JSBool nonNativeSetElement(JSContext *cx, js::HandleObject obj,
+                                      uint32_t index, js::MutableHandleValue vp, JSBool strict);
 
-    JSBool nonNativeSetProperty(JSContext *cx, js::HandleId id, js::MutableHandleValue vp, JSBool strict);
-    JSBool nonNativeSetElement(JSContext *cx, uint32_t index, js::MutableHandleValue vp, JSBool strict);
+    static inline JSBool getGenericAttributes(JSContext *cx, js::HandleObject obj,
+                                              js::HandleId id, unsigned *attrsp);
+    static inline JSBool getPropertyAttributes(JSContext *cx, js::HandleObject obj,
+                                               js::PropertyName *name, unsigned *attrsp);
+    static inline JSBool getElementAttributes(JSContext *cx, js::HandleObject obj,
+                                              uint32_t index, unsigned *attrsp);
+    static inline JSBool getSpecialAttributes(JSContext *cx, js::HandleObject obj,
+                                              js::SpecialId sid, unsigned *attrsp);
 
-    inline JSBool getGenericAttributes(JSContext *cx, js::HandleId id, unsigned *attrsp);
-    inline JSBool getPropertyAttributes(JSContext *cx, js::PropertyName *name, unsigned *attrsp);
-    inline JSBool getElementAttributes(JSContext *cx, uint32_t index, unsigned *attrsp);
-    inline JSBool getSpecialAttributes(JSContext *cx, js::SpecialId sid, unsigned *attrsp);
+    static inline JSBool setGenericAttributes(JSContext *cx, js::HandleObject obj,
+                                              js::HandleId id, unsigned *attrsp);
+    static inline JSBool setPropertyAttributes(JSContext *cx, js::HandleObject obj,
+                                               js::PropertyName *name, unsigned *attrsp);
+    static inline JSBool setElementAttributes(JSContext *cx, js::HandleObject obj,
+                                              uint32_t index, unsigned *attrsp);
+    static inline JSBool setSpecialAttributes(JSContext *cx, js::HandleObject obj,
+                                              js::SpecialId sid, unsigned *attrsp);
 
-    inline JSBool setGenericAttributes(JSContext *cx, js::HandleId id, unsigned *attrsp);
-    inline JSBool setPropertyAttributes(JSContext *cx, js::PropertyName *name, unsigned *attrsp);
-    inline JSBool setElementAttributes(JSContext *cx, uint32_t index, unsigned *attrsp);
-    inline JSBool setSpecialAttributes(JSContext *cx, js::SpecialId sid, unsigned *attrsp);
+    static inline bool deleteProperty(JSContext *cx, js::HandleObject obj,
+                                      js::HandlePropertyName name,
+                                      js::MutableHandleValue rval, bool strict);
+    static inline bool deleteElement(JSContext *cx, js::HandleObject obj,
+                                     uint32_t index,
+                                     js::MutableHandleValue rval, bool strict);
+    static inline bool deleteSpecial(JSContext *cx, js::HandleObject obj,
+                                     js::HandleSpecialId sid,
+                                     js::MutableHandleValue rval, bool strict);
+    static bool deleteByValue(JSContext *cx, js::HandleObject obj,
+                              const js::Value &property, js::MutableHandleValue rval, bool strict);
 
-    inline bool deleteProperty(JSContext *cx, js::HandlePropertyName name, js::MutableHandleValue rval, bool strict);
-    inline bool deleteElement(JSContext *cx, uint32_t index, js::MutableHandleValue rval, bool strict);
-    inline bool deleteSpecial(JSContext *cx, js::HandleSpecialId sid, js::MutableHandleValue rval, bool strict);
-    bool deleteByValue(JSContext *cx, const js::Value &property, js::MutableHandleValue rval, bool strict);
-
-    inline bool enumerate(JSContext *cx, JSIterateOp iterop, js::Value *statep, jsid *idp);
-    inline bool defaultValue(JSContext *cx, JSType hint, js::MutableHandleValue vp);
-    inline JSType typeOf(JSContext *cx);
-    inline JSObject *thisObject(JSContext *cx);
+    static inline bool enumerate(JSContext *cx, js::HandleObject obj,
+                                 JSIterateOp iterop, js::Value *statep, jsid *idp);
+    static inline bool defaultValue(JSContext *cx, js::HandleObject obj,
+                                    JSType hint, js::MutableHandleValue vp);
+    static inline JSType typeOf(JSContext *cx, js::HandleObject obj);
+    static inline JSObject *thisObject(JSContext *cx, js::HandleObject obj);
 
     static bool thisObject(JSContext *cx, const js::Value &v, js::Value *vp);
 
     bool swap(JSContext *cx, JSObject *other);
 
     inline void initArrayClass();
 
     /*
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -47,198 +47,180 @@
 #include "jsscriptinlines.h"
 
 #include "gc/Barrier-inl.h"
 
 #include "vm/ObjectImpl-inl.h"
 #include "vm/RegExpStatics-inl.h"
 #include "vm/String-inl.h"
 
-inline bool
-JSObject::enumerate(JSContext *cx, JSIterateOp iterop, js::Value *statep, jsid *idp)
+/* static */ inline bool
+JSObject::enumerate(JSContext *cx, js::HandleObject obj,
+                    JSIterateOp iterop, js::Value *statep, jsid *idp)
 {
-    JSNewEnumerateOp op = getOps()->enumerate;
-    js::Rooted<JSObject*> obj(cx, this);
+    JSNewEnumerateOp op = obj->getOps()->enumerate;
     return (op ? op : JS_EnumerateState)(cx, obj, iterop, statep, idp);
 }
 
-inline bool
-JSObject::defaultValue(JSContext *cx, JSType hint, js::MutableHandleValue vp)
+/* static */ inline bool
+JSObject::defaultValue(JSContext *cx, js::HandleObject obj, JSType hint, js::MutableHandleValue vp)
 {
-    js::RootedObject self(cx, this);
-
-    JSConvertOp op = getClass()->convert;
+    JSConvertOp op = obj->getClass()->convert;
     bool ok;
     if (op == JS_ConvertStub)
-        ok = js::DefaultValue(cx, self, hint, vp);
+        ok = js::DefaultValue(cx, obj, hint, vp);
     else
-        ok = op(cx, self, hint, vp);
+        ok = op(cx, obj, hint, vp);
     JS_ASSERT_IF(ok, vp.isPrimitive());
     return ok;
 }
 
-inline JSType
-JSObject::typeOf(JSContext *cx)
+/* static */ inline JSType
+JSObject::typeOf(JSContext *cx, js::HandleObject obj)
 {
-    js::TypeOfOp op = getOps()->typeOf;
-    js::Rooted<JSObject*> obj(cx, this);
+    js::TypeOfOp op = obj->getOps()->typeOf;
     return (op ? op : js::baseops::TypeOf)(cx, obj);
 }
 
-inline JSObject *
-JSObject::thisObject(JSContext *cx)
+/* static */ inline JSObject *
+JSObject::thisObject(JSContext *cx, js::HandleObject obj)
 {
-    JSObjectOp op = getOps()->thisObject;
-    js::Rooted<JSObject*> obj(cx, this);
-    return op ? op(cx, obj) : this;
+    JSObjectOp op = obj->getOps()->thisObject;
+    return op ? op(cx, obj) : obj;
 }
 
-inline JSBool
-JSObject::setGeneric(JSContext *cx, js::Handle<JSObject*> receiver, js::HandleId id, js::MutableHandleValue vp,
-                     JSBool strict)
+/* static */ inline JSBool
+JSObject::setGeneric(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
+                     js::HandleId id, js::MutableHandleValue vp, JSBool strict)
 {
-    if (getOps()->setGeneric)
-        return nonNativeSetProperty(cx, id, vp, strict);
-    js::Rooted<JSObject*> obj(cx, this);
+    if (obj->getOps()->setGeneric)
+        return nonNativeSetProperty(cx, obj, id, vp, strict);
     return js::baseops::SetPropertyHelper(cx, obj, receiver, id, 0, vp, strict);
 }
 
-inline JSBool
-JSObject::setProperty(JSContext *cx, js::Handle<JSObject*> receiver, js::PropertyName *name,
-                      js::MutableHandleValue vp, JSBool strict)
+/* static */ inline JSBool
+JSObject::setProperty(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
+                      js::PropertyName *name, js::MutableHandleValue vp, JSBool strict)
 {
-    js::Rooted<jsid> id(cx, js::NameToId(name));
-    return setGeneric(cx, receiver, id, vp, strict);
+    js::RootedId id(cx, js::NameToId(name));
+    return setGeneric(cx, obj, receiver, id, vp, strict);
 }
 
-inline JSBool
-JSObject::setElement(JSContext *cx, js::Handle<JSObject*> receiver, uint32_t index, js::MutableHandleValue vp,
-                     JSBool strict)
+/* static */ inline JSBool
+JSObject::setElement(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
+                     uint32_t index, js::MutableHandleValue vp, JSBool strict)
 {
-    if (getOps()->setElement)
-        return nonNativeSetElement(cx, index, vp, strict);
-    js::Rooted<JSObject*> obj(cx, this);
+    if (obj->getOps()->setElement)
+        return nonNativeSetElement(cx, obj, index, vp, strict);
     return js::baseops::SetElementHelper(cx, obj, receiver, index, 0, vp, strict);
 }
 
-inline JSBool
-JSObject::setSpecial(JSContext *cx, js::HandleObject receiver, js::SpecialId sid, js::MutableHandleValue vp,
-                     JSBool strict)
+/* static */ inline JSBool
+JSObject::setSpecial(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
+                     js::SpecialId sid, js::MutableHandleValue vp, JSBool strict)
 {
-    js::Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
-    return setGeneric(cx, receiver, id, vp, strict);
+    js::RootedId id(cx, SPECIALID_TO_JSID(sid));
+    return setGeneric(cx, obj, receiver, id, vp, strict);
 }
 
-inline JSBool
-JSObject::setGenericAttributes(JSContext *cx, js::HandleId id, unsigned *attrsp)
+/* static */ inline JSBool
+JSObject::setGenericAttributes(JSContext *cx, js::HandleObject obj,
+                               js::HandleId id, unsigned *attrsp)
 {
-    js::types::MarkTypePropertyConfigured(cx, this, id);
-    js::GenericAttributesOp op = getOps()->setGenericAttributes;
-    js::Rooted<JSObject*> obj(cx, this);
+    js::types::MarkTypePropertyConfigured(cx, obj, id);
+    js::GenericAttributesOp op = obj->getOps()->setGenericAttributes;
     return (op ? op : js::baseops::SetAttributes)(cx, obj, id, attrsp);
 }
 
-inline JSBool
-JSObject::setPropertyAttributes(JSContext *cx, js::PropertyName *name, unsigned *attrsp)
+/* static */ inline JSBool
+JSObject::setPropertyAttributes(JSContext *cx, js::HandleObject obj,
+                                js::PropertyName *name, unsigned *attrsp)
 {
-    js::Rooted<jsid> id(cx, js::NameToId(name));
-    return setGenericAttributes(cx, id, attrsp);
+    js::RootedId id(cx, js::NameToId(name));
+    return setGenericAttributes(cx, obj, id, attrsp);
 }
 
-inline JSBool
-JSObject::setElementAttributes(JSContext *cx, uint32_t index, unsigned *attrsp)
+/* static */ inline JSBool
+JSObject::setElementAttributes(JSContext *cx, js::HandleObject obj,
+                               uint32_t index, unsigned *attrsp)
 {
-    js::ElementAttributesOp op = getOps()->setElementAttributes;
-    js::Rooted<JSObject*> obj(cx, this);
+    js::ElementAttributesOp op = obj->getOps()->setElementAttributes;
     return (op ? op : js::baseops::SetElementAttributes)(cx, obj, index, attrsp);
 }
 
-inline JSBool
-JSObject::setSpecialAttributes(JSContext *cx, js::SpecialId sid, unsigned *attrsp)
+/* static */ inline JSBool
+JSObject::setSpecialAttributes(JSContext *cx, js::HandleObject obj,
+                               js::SpecialId sid, unsigned *attrsp)
 {
-    js::Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
-    return setGenericAttributes(cx, id, attrsp);
+    js::RootedId id(cx, SPECIALID_TO_JSID(sid));
+    return setGenericAttributes(cx, obj, id, attrsp);
 }
 
-inline bool
-JSObject::changePropertyAttributes(JSContext *cx, js::Shape *shape, unsigned attrs)
+/* static */ inline bool
+JSObject::changePropertyAttributes(JSContext *cx, js::HandleObject obj,
+                                   js::Shape *shape, unsigned attrs)
 {
-    return !!changeProperty(cx, shape, attrs, 0, shape->getter(), shape->setter());
+    return !!changeProperty(cx, obj, shape, attrs, 0, shape->getter(), shape->setter());
 }
 
-inline JSBool
-JSObject::getGeneric(JSContext *cx, js::HandleObject receiver, js::HandleId id, js::MutableHandleValue vp)
+/* static */ inline JSBool
+JSObject::getGeneric(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
+                     js::HandleId id, js::MutableHandleValue vp)
 {
-    js::RootedObject self(cx, this);
-
-    js::GenericIdOp op = getOps()->getGeneric;
+    js::GenericIdOp op = obj->getOps()->getGeneric;
     if (op) {
-        if (!op(cx, self, receiver, id, vp))
+        if (!op(cx, obj, receiver, id, vp))
             return false;
     } else {
-        if (!js::baseops::GetProperty(cx, self, receiver, id, vp))
+        if (!js::baseops::GetProperty(cx, obj, receiver, id, vp))
             return false;
     }
     return true;
 }
 
-inline JSBool
-JSObject::getProperty(JSContext *cx, js::HandleObject receiver, js::PropertyName *name, js::MutableHandleValue vp)
+/* static */ inline JSBool
+JSObject::getProperty(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
+                      js::PropertyName *name, js::MutableHandleValue vp)
 {
-    js::Rooted<jsid> id(cx, js::NameToId(name));
-    return getGeneric(cx, receiver, id, vp);
-}
-
-inline JSBool
-JSObject::getGeneric(JSContext *cx, js::HandleId id, js::MutableHandleValue vp)
-{
-    js::Rooted<JSObject*> obj(cx, this);
-    return getGeneric(cx, obj, id, vp);
+    js::RootedId id(cx, js::NameToId(name));
+    return getGeneric(cx, obj, receiver, id, vp);
 }
 
-inline JSBool
-JSObject::getProperty(JSContext *cx, js::PropertyName *name, js::MutableHandleValue vp)
-{
-    js::Rooted<jsid> id(cx, js::NameToId(name));
-    return getGeneric(cx, id, vp);
-}
-
-inline bool
-JSObject::deleteProperty(JSContext *cx, js::HandlePropertyName name, js::MutableHandleValue rval, bool strict)
+/* static */ inline bool
+JSObject::deleteProperty(JSContext *cx, js::HandleObject obj,
+                         js::HandlePropertyName name, js::MutableHandleValue rval, bool strict)
 {
     jsid id = js::NameToId(name);
-    js::types::AddTypePropertyId(cx, this, id, js::types::Type::UndefinedType());
-    js::types::MarkTypePropertyConfigured(cx, this, id);
-    js::DeletePropertyOp op = getOps()->deleteProperty;
-    js::Rooted<JSObject*> obj(cx, this);
+    js::types::AddTypePropertyId(cx, obj, id, js::types::Type::UndefinedType());
+    js::types::MarkTypePropertyConfigured(cx, obj, id);
+    js::DeletePropertyOp op = obj->getOps()->deleteProperty;
     return (op ? op : js::baseops::DeleteProperty)(cx, obj, name, rval, strict);
 }
 
-inline bool
-JSObject::deleteElement(JSContext *cx, uint32_t index, js::MutableHandleValue rval, bool strict)
+/* static */ inline bool
+JSObject::deleteElement(JSContext *cx, js::HandleObject obj,
+                        uint32_t index, js::MutableHandleValue rval, bool strict)
 {
-    js::RootedObject self(cx, this);
-
     jsid id;
     if (!js::IndexToId(cx, index, &id))
         return false;
-    js::types::AddTypePropertyId(cx, self, id, js::types::Type::UndefinedType());
-    js::types::MarkTypePropertyConfigured(cx, self, id);
-    js::DeleteElementOp op = self->getOps()->deleteElement;
-    return (op ? op : js::baseops::DeleteElement)(cx, self, index, rval, strict);
+    js::types::AddTypePropertyId(cx, obj, id, js::types::Type::UndefinedType());
+    js::types::MarkTypePropertyConfigured(cx, obj, id);
+    js::DeleteElementOp op = obj->getOps()->deleteElement;
+    return (op ? op : js::baseops::DeleteElement)(cx, obj, index, rval, strict);
 }
 
-inline bool
-JSObject::deleteSpecial(JSContext *cx, js::HandleSpecialId sid, js::MutableHandleValue rval, bool strict)
+/* static */ inline bool
+JSObject::deleteSpecial(JSContext *cx, js::HandleObject obj,
+                        js::HandleSpecialId sid, js::MutableHandleValue rval, bool strict)
 {
     jsid id = SPECIALID_TO_JSID(sid);
-    js::types::AddTypePropertyId(cx, this, id, js::types::Type::UndefinedType());
-    js::types::MarkTypePropertyConfigured(cx, this, id);
-    js::DeleteSpecialOp op = getOps()->deleteSpecial;
-    js::Rooted<JSObject*> obj(cx, this);
+    js::types::AddTypePropertyId(cx, obj, id, js::types::Type::UndefinedType());
+    js::types::MarkTypePropertyConfigured(cx, obj, id);
+    js::DeleteSpecialOp op = obj->getOps()->deleteSpecial;
     return (op ? op : js::baseops::DeleteSpecial)(cx, obj, sid, rval, strict);
 }
 
 inline void
 JSObject::finalize(js::FreeOp *fop)
 {
     js::Probes::finalizeObject(this);
 
@@ -648,41 +630,39 @@ inline void
 JSObject::setQNameLocalName(JSAtom *name)
 {
     JS_ASSERT(isQName());
     setSlot(JSSLOT_QNAME_LOCAL_NAME, name ? js::StringValue(name) : js::UndefinedValue());
 }
 
 #endif
 
-inline bool
-JSObject::setSingletonType(JSContext *cx)
+/* static */ inline bool
+JSObject::setSingletonType(JSContext *cx, js::HandleObject obj)
 {
     if (!cx->typeInferenceEnabled())
         return true;
 
-    JS::Rooted<JSObject*> self(cx, this);
-    JS_ASSERT(!hasLazyType());
-    JS_ASSERT_IF(self->getProto(), self->type() == self->getProto()->getNewType(cx, NULL));
+    JS_ASSERT(!obj->hasLazyType());
+    JS_ASSERT_IF(obj->getProto(), obj->type() == obj->getProto()->getNewType(cx, NULL));
 
-    js::types::TypeObject *type = cx->compartment->getLazyType(cx, self->getProto());
+    js::types::TypeObject *type = cx->compartment->getLazyType(cx, obj->getProto());
     if (!type)
         return false;
 
-    self->type_ = type;
+    obj->type_ = type;
     return true;
 }
 
 inline js::types::TypeObject *
 JSObject::getType(JSContext *cx)
 {
-    JS::RootedObject self(cx, this);
-    if (self->hasLazyType())
-        self->makeLazyType(cx);
-    return self->type_;
+    if (hasLazyType())
+        return makeLazyType(cx);
+    return type_;
 }
 
 /* static */ inline bool
 JSObject::clearType(JSContext *cx, js::HandleObject obj)
 {
     JS_ASSERT(!obj->hasSingletonType());
 
     js::types::TypeObject *type = cx->compartment->getEmptyType(cx);
@@ -908,23 +888,24 @@ inline void
 JSObject::finish(js::FreeOp *fop)
 {
     if (hasDynamicSlots())
         fop->free_(slots);
     if (hasDynamicElements())
         fop->free_(getElementsHeader());
 }
 
-inline bool
-JSObject::hasProperty(JSContext *cx, js::HandleId id, bool *foundp, unsigned flags)
+/* static */ inline bool
+JSObject::hasProperty(JSContext *cx, js::HandleObject obj,
+                      js::HandleId id, bool *foundp, unsigned flags)
 {
     js::RootedObject pobj(cx);
     js::RootedShape prop(cx);
     JSAutoResolveFlags rf(cx, flags);
-    if (!lookupGeneric(cx, id, &pobj, &prop))
+    if (!lookupGeneric(cx, obj, id, &pobj, &prop))
         return false;
     *foundp = !!prop;
     return true;
 }
 
 inline bool
 JSObject::isCallable()
 {
@@ -1030,190 +1011,180 @@ JSObject::sizeOfExcludingThis(JSMallocSi
     *miscSize = 0;
     if (isArguments()) {
         *miscSize += asArguments().sizeOfMisc(mallocSizeOf);
     } else if (isRegExpStatics()) {
         *miscSize += js::SizeOfRegExpStaticsData(this, mallocSizeOf);
     }
 }
 
-inline JSBool
-JSObject::lookupGeneric(JSContext *cx, js::HandleId id,
+/* static */ inline JSBool
+JSObject::lookupGeneric(JSContext *cx, js::HandleObject obj, js::HandleId id,
                         js::MutableHandleObject objp, js::MutableHandleShape propp)
 {
-    js::RootedObject self(cx, this);
-
-    js::LookupGenericOp op = getOps()->lookupGeneric;
+    js::LookupGenericOp op = obj->getOps()->lookupGeneric;
     if (op)
-        return op(cx, self, id, objp, propp);
-    return js::baseops::LookupProperty(cx, self, id, objp, propp);
+        return op(cx, obj, id, objp, propp);
+    return js::baseops::LookupProperty(cx, obj, id, objp, propp);
 }
 
-inline JSBool
-JSObject::lookupProperty(JSContext *cx, js::PropertyName *name,
+/* static */ inline JSBool
+JSObject::lookupProperty(JSContext *cx, js::HandleObject obj, js::PropertyName *name,
                          js::MutableHandleObject objp, js::MutableHandleShape propp)
 {
-    js::Rooted<jsid> id(cx, js::NameToId(name));
-    return lookupGeneric(cx, id, objp, propp);
+    js::RootedId id(cx, js::NameToId(name));
+    return lookupGeneric(cx, obj, id, objp, propp);
 }
 
-inline JSBool
-JSObject::defineGeneric(JSContext *cx, js::HandleId id, js::HandleValue value,
+/* static */ inline JSBool
+JSObject::defineGeneric(JSContext *cx, js::HandleObject obj,
+                        js::HandleId id, js::HandleValue value,
                         JSPropertyOp getter /* = JS_PropertyStub */,
                         JSStrictPropertyOp setter /* = JS_StrictPropertyStub */,
                         unsigned attrs /* = JSPROP_ENUMERATE */)
 {
-    js::RootedObject self(cx, this);
-
     JS_ASSERT(!(attrs & JSPROP_NATIVE_ACCESSORS));
-    js::DefineGenericOp op = getOps()->defineGeneric;
-    return (op ? op : js::baseops::DefineGeneric)(cx, self, id, value, getter, setter, attrs);
+    js::DefineGenericOp op = obj->getOps()->defineGeneric;
+    return (op ? op : js::baseops::DefineGeneric)(cx, obj, id, value, getter, setter, attrs);
 }
 
-inline JSBool
-JSObject::defineProperty(JSContext *cx, js::PropertyName *name, js::HandleValue value,
+/* static */ inline JSBool
+JSObject::defineProperty(JSContext *cx, js::HandleObject obj,
+                         js::PropertyName *name, js::HandleValue value,
                         JSPropertyOp getter /* = JS_PropertyStub */,
                         JSStrictPropertyOp setter /* = JS_StrictPropertyStub */,
                         unsigned attrs /* = JSPROP_ENUMERATE */)
 {
-    js::Rooted<jsid> id(cx, js::NameToId(name));
-    return defineGeneric(cx, id, value, getter, setter, attrs);
+    js::RootedId id(cx, js::NameToId(name));
+    return defineGeneric(cx, obj, id, value, getter, setter, attrs);
 }
 
-inline JSBool
-JSObject::defineElement(JSContext *cx, uint32_t index, js::HandleValue value,
+/* static */ inline JSBool
+JSObject::defineElement(JSContext *cx, js::HandleObject obj,
+                        uint32_t index, js::HandleValue value,
                         JSPropertyOp getter /* = JS_PropertyStub */,
                         JSStrictPropertyOp setter /* = JS_StrictPropertyStub */,
                         unsigned attrs /* = JSPROP_ENUMERATE */)
 {
-    js::RootedObject self(cx, this);
-
-    js::DefineElementOp op = getOps()->defineElement;
-    return (op ? op : js::baseops::DefineElement)(cx, self, index, value, getter, setter, attrs);
+    js::DefineElementOp op = obj->getOps()->defineElement;
+    return (op ? op : js::baseops::DefineElement)(cx, obj, index, value, getter, setter, attrs);
 }
 
-inline JSBool
-JSObject::defineSpecial(JSContext *cx, js::SpecialId sid, js::HandleValue value,
+/* static */ inline JSBool
+JSObject::defineSpecial(JSContext *cx, js::HandleObject obj, js::SpecialId sid, js::HandleValue value,
                         JSPropertyOp getter /* = JS_PropertyStub */,
                         JSStrictPropertyOp setter /* = JS_StrictPropertyStub */,
                         unsigned attrs /* = JSPROP_ENUMERATE */)
 {
-    js::Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
-    return defineGeneric(cx, id, value, getter, setter, attrs);
+    js::RootedId id(cx, SPECIALID_TO_JSID(sid));
+    return defineGeneric(cx, obj, id, value, getter, setter, attrs);
 }
 
-inline JSBool
-JSObject::lookupElement(JSContext *cx, uint32_t index,
+/* static */ inline JSBool
+JSObject::lookupElement(JSContext *cx, js::HandleObject obj, uint32_t index,
                         js::MutableHandleObject objp, js::MutableHandleShape propp)
 {
-    js::RootedObject self(cx, this);
-
-    js::LookupElementOp op = getOps()->lookupElement;
-    return (op ? op : js::baseops::LookupElement)(cx, self, index, objp, propp);
+    js::LookupElementOp op = obj->getOps()->lookupElement;
+    return (op ? op : js::baseops::LookupElement)(cx, obj, index, objp, propp);
 }
 
-inline JSBool
-JSObject::lookupSpecial(JSContext *cx, js::SpecialId sid,
+/* static */ inline JSBool
+JSObject::lookupSpecial(JSContext *cx, js::HandleObject obj, js::SpecialId sid,
                         js::MutableHandleObject objp, js::MutableHandleShape propp)
 {
-    js::Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
-    return lookupGeneric(cx, id, objp, propp);
+    js::RootedId id(cx, SPECIALID_TO_JSID(sid));
+    return lookupGeneric(cx, obj, id, objp, propp);
 }
 
-inline JSBool
-JSObject::getElement(JSContext *cx, js::HandleObject receiver, uint32_t index, js::MutableHandleValue vp)
+/* static */ inline JSBool
+JSObject::getElement(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
+                     uint32_t index, js::MutableHandleValue vp)
 {
-    js::RootedObject self(cx, this);
-
-    js::ElementIdOp op = getOps()->getElement;
+    js::ElementIdOp op = obj->getOps()->getElement;
     if (op)
-        return op(cx, self, receiver, index, vp);
+        return op(cx, obj, receiver, index, vp);
 
     js::RootedId id(cx);
     if (!js::IndexToId(cx, index, id.address()))
         return false;
-    return self->getGeneric(cx, receiver, id, vp);
-}
-
-inline JSBool
-JSObject::getElement(JSContext *cx, uint32_t index, js::MutableHandleValue vp)
-{
-    js::Rooted<JSObject*> obj(cx, this);
-    return getElement(cx, obj, index, vp);
+    return getGeneric(cx, obj, receiver, id, vp);
 }
 
-inline JSBool
-JSObject::getElementIfPresent(JSContext *cx, js::HandleObject receiver, uint32_t index, js::MutableHandleValue vp,
+/* static */ inline JSBool
+JSObject::getElementIfPresent(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
+                              uint32_t index, js::MutableHandleValue vp,
                               bool *present)
 {
-    js::RootedObject self(cx, this);
-
-    js::ElementIfPresentOp op = getOps()->getElementIfPresent;
+    js::ElementIfPresentOp op = obj->getOps()->getElementIfPresent;
     if (op)
-        return op(cx, self, receiver, index, vp, present);
+        return op(cx, obj, receiver, index, vp, present);
 
     /*
      * For now, do the index-to-id conversion just once, then use
      * lookupGeneric/getGeneric.  Once lookupElement and getElement stop both
      * doing index-to-id conversions, we can use those here.
      */
     js::RootedId id(cx);
     if (!js::IndexToId(cx, index, id.address()))
         return false;
 
     js::RootedObject obj2(cx);
     js::RootedShape prop(cx);
-    if (!self->lookupGeneric(cx, id, &obj2, &prop))
+    if (!lookupGeneric(cx, obj, id, &obj2, &prop))
         return false;
 
     if (!prop) {
         *present = false;
         return true;
     }
 
     *present = true;
-    return self->getGeneric(cx, receiver, id, vp);
+    return getGeneric(cx, obj, receiver, id, vp);
 }
 
-inline JSBool
-JSObject::getSpecial(JSContext *cx, js::HandleObject receiver, js::SpecialId sid, js::MutableHandleValue vp)
+/* static */ inline JSBool
+JSObject::getSpecial(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
+                     js::SpecialId sid, js::MutableHandleValue vp)
 {
-    js::Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
-    return getGeneric(cx, receiver, id, vp);
+    js::RootedId id(cx, SPECIALID_TO_JSID(sid));
+    return getGeneric(cx, obj, receiver, id, vp);
 }
 
-inline JSBool
-JSObject::getGenericAttributes(JSContext *cx, js::HandleId id, unsigned *attrsp)
+/* static */ inline JSBool
+JSObject::getGenericAttributes(JSContext *cx, js::HandleObject obj,
+                               js::HandleId id, unsigned *attrsp)
 {
-    js::GenericAttributesOp op = getOps()->getGenericAttributes;
-    js::Rooted<JSObject*> obj(cx, this);
+    js::GenericAttributesOp op = obj->getOps()->getGenericAttributes;
     return (op ? op : js::baseops::GetAttributes)(cx, obj, id, attrsp);
 }
 
-inline JSBool
-JSObject::getPropertyAttributes(JSContext *cx, js::PropertyName *name, unsigned *attrsp)
+/* static */ inline JSBool
+JSObject::getPropertyAttributes(JSContext *cx, js::HandleObject obj,
+                                js::PropertyName *name, unsigned *attrsp)
 {
-    js::Rooted<jsid> id(cx, js::NameToId(name));
-    return getGenericAttributes(cx, id, attrsp);
+    js::RootedId id(cx, js::NameToId(name));
+    return getGenericAttributes(cx, obj, id, attrsp);
 }
 
-inline JSBool
-JSObject::getElementAttributes(JSContext *cx, uint32_t index, unsigned *attrsp)
+/* static */ inline JSBool
+JSObject::getElementAttributes(JSContext *cx, js::HandleObject obj,
+                               uint32_t index, unsigned *attrsp)
 {
     js::RootedId id(cx);
     if (!js::IndexToId(cx, index, id.address()))
         return false;
-    return getGenericAttributes(cx, id, attrsp);
+    return getGenericAttributes(cx, obj, id, attrsp);
 }
 
-inline JSBool
-JSObject::getSpecialAttributes(JSContext *cx, js::SpecialId sid, unsigned *attrsp)
+/* static */ inline JSBool
+JSObject::getSpecialAttributes(JSContext *cx, js::HandleObject obj,
+                               js::SpecialId sid, unsigned *attrsp)
 {
-    js::Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
-    return getGenericAttributes(cx, id, attrsp);
+    js::RootedId id(cx, SPECIALID_TO_JSID(sid));
+    return getGenericAttributes(cx, obj, id, attrsp);
 }
 
 inline bool
 JSObject::isProxy() const
 {
     return js::IsProxy(const_cast<JSObject*>(this));
 }
 
@@ -1305,32 +1276,34 @@ IsStopIteration(const js::Value &v)
 }
 
 /* ES5 9.1 ToPrimitive(input). */
 static JS_ALWAYS_INLINE bool
 ToPrimitive(JSContext *cx, Value *vp)
 {
     if (vp->isPrimitive())
         return true;
+    RootedObject obj(cx, &vp->toObject());
     RootedValue value(cx, *vp);
-    if (!vp->toObject().defaultValue(cx, JSTYPE_VOID, &value))
+    if (!JSObject::defaultValue(cx, obj, JSTYPE_VOID, &value))
         return false;
     *vp = value;
     return true;
 }
 
 /* ES5 9.1 ToPrimitive(input, PreferredType). */
 static JS_ALWAYS_INLINE bool
 ToPrimitive(JSContext *cx, JSType preferredType, Value *vp)
 {
     JS_ASSERT(preferredType != JSTYPE_VOID); /* Use the other ToPrimitive! */
     if (vp->isPrimitive())
         return true;
+    RootedObject obj(cx, &vp->toObject());
     RootedValue value(cx, *vp);
-    if (!vp->toObject().defaultValue(cx, preferredType, &value))
+    if (!JSObject::defaultValue(cx, obj, preferredType, &value))
         return false;
     *vp = value;
     return true;
 }
 
 /*
  * Return true if this is a compiler-created internal function accessed by
  * its own object. Such a function object must not be accessible to script
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -410,17 +410,17 @@ JO(JSContext *cx, HandleObject obj, Stri
          * Steps 8a-8b.  Note that the call to Str is broken up into 1) getting
          * the property; 2) processing for toJSON, calling the replacer, and
          * handling boxed Number/String/Boolean objects; 3) filtering out
          * values which process to |undefined|, and 4) stringifying all values
          * which pass the filter.
          */
         id = propertyList[i];
         RootedValue outputValue(cx);
-        if (!obj->getGeneric(cx, id, &outputValue))
+        if (!JSObject::getGeneric(cx, obj, obj, id, &outputValue))
             return false;
         if (!PreprocessValue(cx, obj, HandleId(id), &outputValue, scx))
             return false;
         if (IsFilteredValue(outputValue))
             continue;
 
         /* Output a comma unless this is the first member to write. */
         if (wroteMember && !scx->sb.append(','))
@@ -468,17 +468,17 @@ JA(JSContext *cx, HandleObject obj, Stri
     if (!detect.init(cx))
         return JS_FALSE;
 
     if (!scx->sb.append('['))
         return JS_FALSE;
 
     /* Step 6. */
     uint32_t length;
-    if (!js_GetLengthProperty(cx, obj, &length))
+    if (!GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
 
     /* Steps 7-10. */
     if (length != 0) {
         /* Steps 4, 10b(i). */
         if (!WriteIndent(cx, scx, scx->depth))
             return JS_FALSE;
 
@@ -486,17 +486,17 @@ JA(JSContext *cx, HandleObject obj, Stri
         RootedValue outputValue(cx);
         for (uint32_t i = 0; i < length; i++) {
             /*
              * Steps 8a-8c.  Again note how the call to the spec's Str method
              * is broken up into getting the property, running it past toJSON
              * and the replacer and maybe unboxing, and interpreting some
              * values as |null| in separate steps.
              */
-            if (!obj->getElement(cx, i, &outputValue))
+            if (!JSObject::getElement(cx, obj, obj, i, &outputValue))
                 return JS_FALSE;
             if (!PreprocessValue(cx, obj, i, &outputValue, scx))
                 return JS_FALSE;
             if (IsFilteredValue(outputValue)) {
                 if (!scx->sb.append("null"))
                     return JS_FALSE;
             } else {
                 if (!Str(cx, outputValue, scx))
@@ -622,32 +622,32 @@ js_Stringify(JSContext *cx, MutableHandl
              *      6. If item is not undefined and item is not currently an
              *         element of PropertyList then,
              *         a. Append item to the end of PropertyList.
              *      7. Let i be i + 1.
              */
 
             /* Step 4b(ii). */
             uint32_t len;
-            JS_ALWAYS_TRUE(js_GetLengthProperty(cx, replacer, &len));
+            JS_ALWAYS_TRUE(GetLengthProperty(cx, replacer, &len));
             if (replacer->isDenseArray())
                 len = Min(len, replacer->getDenseArrayCapacity());
 
             HashSet<jsid> idSet(cx);
             if (!idSet.init(len))
                 return false;
 
             /* Step 4b(iii). */
             uint32_t i = 0;
 
             /* Step 4b(iv). */
             RootedValue v(cx);
             for (; i < len; i++) {
                 /* Step 4b(iv)(2). */
-                if (!replacer->getElement(cx, i, &v))
+                if (!JSObject::getElement(cx, replacer, replacer, i, &v))
                     return false;
 
                 jsid id;
                 if (v.isNumber()) {
                     /* Step 4b(iv)(4). */
                     int32_t n;
                     if (v.isNumber() && ValueFitsInInt32(v, &n) && INT_FITS_IN_JSID(n)) {
                         id = INT_TO_JSID(n);
@@ -748,17 +748,17 @@ js_Stringify(JSContext *cx, MutableHandl
 /* ES5 15.12.2 Walk. */
 static bool
 Walk(JSContext *cx, HandleObject holder, HandleId name, HandleValue reviver, MutableHandleValue vp)
 {
     JS_CHECK_RECURSION(cx, return false);
 
     /* Step 1. */
     RootedValue val(cx);
-    if (!holder->getGeneric(cx, name, &val))
+    if (!JSObject::getGeneric(cx, holder, holder, name, &val))
         return false;
 
     /* Step 2. */
     if (val.isObject()) {
         RootedObject obj(cx, &val.toObject());
 
         /* 'val' must have been produced by the JSON parser, so not a proxy. */
         JS_ASSERT(!obj->isProxy());
@@ -809,17 +809,17 @@ Walk(JSContext *cx, HandleObject holder,
             for (size_t i = 0, len = keys.length(); i < len; i++) {
                 /* Step 2b(ii)(1). */
                 id = keys[i];
                 if (!Walk(cx, obj, id, reviver, &newElement))
                     return false;
 
                 if (newElement.isUndefined()) {
                     /* Step 2b(ii)(2). */
-                    if (!obj->deleteByValue(cx, IdToValue(id), &newElement, false))
+                    if (!JSObject::deleteByValue(cx, obj, IdToValue(id), &newElement, false))
                         return false;
                 } else {
                     /* Step 2b(ii)(3). */
                     JS_ASSERT(obj->isNative());
                     if (!DefineNativeProperty(cx, obj, id, newElement, JS_PropertyStub,
                                               JS_StrictPropertyStub, JSPROP_ENUMERATE, 0, 0))
                     {
                         return false;
@@ -851,17 +851,17 @@ Walk(JSContext *cx, HandleObject holder,
 
 static bool
 Revive(JSContext *cx, HandleValue reviver, MutableHandleValue vp)
 {
     RootedObject obj(cx, NewBuiltinClassInstance(cx, &ObjectClass));
     if (!obj)
         return false;
 
-    if (!obj->defineProperty(cx, cx->runtime->atomState.emptyAtom, vp))
+    if (!JSObject::defineProperty(cx, obj, cx->runtime->atomState.emptyAtom, vp))
         return false;
 
     Rooted<jsid> id(cx, NameToId(cx->runtime->atomState.emptyAtom));
     return Walk(cx, obj, id, reviver, vp);
 }
 
 namespace js {
 
@@ -910,17 +910,17 @@ js_InitJSONClass(JSContext *cx, JSObject
      * JSON requires that Boolean.prototype.valueOf be created and stashed in a
      * reserved slot on the global object; see js::BooleanGetPrimitiveValueSlow
      * called from PreprocessValue above.
      */
     if (!global->getOrCreateBooleanPrototype(cx))
         return NULL;
 
     RootedObject JSON(cx, NewObjectWithClassProto(cx, &JSONClass, NULL, global));
-    if (!JSON || !JSON->setSingletonType(cx))
+    if (!JSON || !JSObject::setSingletonType(cx, JSON))
         return NULL;
 
     if (!JS_DefineProperty(cx, global, js_JSON_str, OBJECT_TO_JSVAL(JSON),
                            JS_PropertyStub, JS_StrictPropertyStub, 0))
         return NULL;
 
     if (!JS_DefineFunctions(cx, JSON, json_static_methods))
         return NULL;
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -605,31 +605,33 @@ DirectProxyHandler::hasOwn(JSContext *cx
 
 bool
 DirectProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver_,
                         jsid id_, Value *vp)
 {
     RootedObject receiver(cx, receiver_);
     RootedId id(cx, id_);
     RootedValue value(cx);
-    if (!GetProxyTargetObject(proxy)->getGeneric(cx, receiver, id, &value))
+    RootedObject target(cx, GetProxyTargetObject(proxy));
+    if (!JSObject::getGeneric(cx, target, receiver, id, &value))
         return false;
 
     *vp = value;
     return true;
 }
 
 bool
 DirectProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiverArg,
                         jsid id_, bool strict, Value *vp)
 {
     RootedId id(cx, id_);
     Rooted<JSObject*> receiver(cx, receiverArg);
     RootedValue value(cx, *vp);
-    if (!GetProxyTargetObject(proxy)->setGeneric(cx, receiver, id, &value, strict))
+    RootedObject target(cx, GetProxyTargetObject(proxy));
+    if (!JSObject::setGeneric(cx, target, receiver, id, &value, strict))
         return false;
 
     *vp = value;
     return true;
 }
 
 bool
 DirectProxyHandler::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props)
@@ -650,17 +652,17 @@ DirectProxyHandler::iterate(JSContext *c
     return true;
 }
 
 static bool
 GetTrap(JSContext *cx, HandleObject handler, HandlePropertyName name, MutableHandleValue fvalp)
 {
     JS_CHECK_RECURSION(cx, return false);
 
-    return handler->getProperty(cx, name, fvalp);
+    return JSObject::getProperty(cx, handler, handler, name, fvalp);
 }
 
 static bool
 GetFundamentalTrap(JSContext *cx, HandleObject handler, HandlePropertyName name, MutableHandleValue fvalp)
 {
     if (!GetTrap(cx, handler, name, fvalp))
         return false;
 
@@ -753,24 +755,24 @@ ArrayToIdVector(JSContext *cx, const Val
 {
     JS_ASSERT(props.length() == 0);
 
     if (array.isPrimitive())
         return true;
 
     RootedObject obj(cx, &array.toObject());
     uint32_t length;
-    if (!js_GetLengthProperty(cx, obj, &length))
+    if (!GetLengthProperty(cx, obj, &length))
         return false;
 
     RootedValue v(cx);
     for (uint32_t n = 0; n < length; ++n) {
         if (!JS_CHECK_OPERATION_LIMIT(cx))
             return false;
-        if (!obj->getElement(cx, n, &v))
+        if (!JSObject::getElement(cx, obj, obj, n, &v))
             return false;
         jsid id;
         if (!ValueToId(cx, v, &id))
             return false;
         if (!props.append(id))
             return false;
     }
 
@@ -1061,18 +1063,18 @@ class AutoPendingProxyOperation {
     ~AutoPendingProxyOperation() {
         JS_ASSERT(rt->pendingProxyOperation == &op);
         rt->pendingProxyOperation = op.next;
     }
 };
 
 #define INVOKE_ON_PROTOTYPE(cx, handler, proxy, protoCall)                   \
     JS_BEGIN_MACRO                                                           \
-        JSObject *proto;                                                     \
-        if (!handler->getPrototypeOf(cx, proxy, &proto))                     \
+        RootedObject proto(cx);                                              \
+        if (!handler->getPrototypeOf(cx, proxy, proto.address()))            \
             return false;                                                    \
         if (!proto)                                                          \
             return true;                                                     \
         assertSameCompartment(cx, proxy, proto);                             \
         return protoCall;                                                    \
     JS_END_MACRO                                                             \
 
 
@@ -1230,17 +1232,17 @@ Proxy::get(JSContext *cx, HandleObject p
            MutableHandleValue vp)
 {
     JS_CHECK_RECURSION(cx, return false);
     AutoPendingProxyOperation pending(cx, proxy);
     BaseProxyHandler *handler = GetProxyHandler(proxy);
     bool own = false;
     if (!handler->hasPrototype() || (handler->hasOwn(cx, proxy, id, &own) && own))
         return handler->get(cx, proxy, receiver, id, vp.address());
-    INVOKE_ON_PROTOTYPE(cx, handler, proxy, proto->getGeneric(cx, receiver, id, vp));
+    INVOKE_ON_PROTOTYPE(cx, handler, proxy, JSObject::getGeneric(cx, proto, receiver, id, vp));
 }
 
 bool
 Proxy::getElementIfPresent(JSContext *cx, HandleObject proxy, HandleObject receiver, uint32_t index,
                            MutableHandleValue vp, bool *present)
 {
     JS_CHECK_RECURSION(cx, return false);
     AutoPendingProxyOperation pending(cx, proxy);
@@ -1250,17 +1252,17 @@ Proxy::getElementIfPresent(JSContext *cx
         ((status = handler->hasOwn(cx, proxy, INT_TO_JSID(index), &hasOwn)) && hasOwn))
     {
         return GetProxyHandler(proxy)->getElementIfPresent(cx, proxy, receiver,
                                                            index, vp.address(), present);
     } else if (!status) {
         return false;
     }
     INVOKE_ON_PROTOTYPE(cx, handler, proxy,
-                        proto->getElementIfPresent(cx, receiver, index, vp, present));
+                        JSObject::getElementIfPresent(cx, proto, receiver, index, vp, present));
 }
 
 bool
 Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, bool strict,
            MutableHandleValue vp)
 {
     JS_CHECK_RECURSION(cx, return false);
     AutoPendingProxyOperation pending(cx, proxy);
@@ -1271,17 +1273,17 @@ Proxy::set(JSContext *cx, HandleObject p
         // we have a non-own property with a setter.
         bool hasOwn;
         AutoPropertyDescriptorRooter desc(cx);
         if (handler->hasOwn(cx, proxy, id, &hasOwn) && !hasOwn &&
             handler->getPrototypeOf(cx, proxy, proto.address()) && proto &&
             JS_GetPropertyDescriptorById(cx, proto, id, JSRESOLVE_QUALIFIED, &desc) &&
             desc.obj && desc.setter)
         {
-            return proto->setGeneric(cx, receiver, id, vp, strict);
+            return JSObject::setGeneric(cx, proto, receiver, id, vp, strict);
         } else if (cx->isExceptionPending()) {
             return false;
         }
     }
     return handler->set(cx, proxy, receiver, id, strict, vp.address());
 }
 
 bool
@@ -1936,33 +1938,33 @@ js::NewProxyObject(JSContext *cx, BasePr
     /*
      * Eagerly mark properties unknown for proxies, so we don't try to track
      * their properties and so that we don't need to walk the compartment if
      * their prototype changes later.
      */
     if (proto && !proto->setNewTypeUnknown(cx))
         return NULL;
 
-    JSObject *obj = NewObjectWithGivenProto(cx, clasp, proto, parent);
+    RootedObject obj(cx, NewObjectWithGivenProto(cx, clasp, proto, parent));
     if (!obj)
         return NULL;
     obj->setSlot(JSSLOT_PROXY_HANDLER, PrivateValue(handler));
     obj->setSlot(JSSLOT_PROXY_PRIVATE, priv);
     if (fun) {
         obj->setSlot(JSSLOT_PROXY_CALL, call ? ObjectValue(*call) : UndefinedValue());
         if (construct) {
             obj->setSlot(JSSLOT_PROXY_CONSTRUCT, ObjectValue(*construct));
         }
     }
 
     /* Don't track types of properties of proxies. */
     MarkTypeObjectUnknownProperties(cx, obj->type());
 
     /* Mark the new proxy as having singleton type. */
-    if (clasp == &OuterWindowProxyClass && !obj->setSingletonType(cx))
+    if (clasp == &OuterWindowProxyClass && !JSObject::setSingletonType(cx, obj))
         return NULL;
 
     return obj;
 }
 
 static JSBool
 proxy_create(JSContext *cx, unsigned argc, Value *vp)
 {
@@ -2065,17 +2067,17 @@ Class js::ProxyClass = {
     JS_ConvertStub
 };
 
 JS_FRIEND_API(JSObject *)
 js_InitProxyClass(JSContext *cx, JSObject *obj_)
 {
     RootedObject obj(cx, obj_);
     RootedObject module(cx, NewObjectWithClassProto(cx, &ProxyClass, NULL, obj));
-    if (!module || !module->setSingletonType(cx))
+    if (!module || !JSObject::setSingletonType(cx, module))
         return NULL;
 
     if (!JS_DefineProperty(cx, obj, "Proxy", OBJECT_TO_JSVAL(module),
                            JS_PropertyStub, JS_StrictPropertyStub, 0)) {
         return NULL;
     }
     if (!JS_DefineFunctions(cx, module, static_methods))
         return NULL;
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -402,32 +402,33 @@ class NodeBuilder
 
         Value cb = callbacks[type];
         if (!cb.isNull())
             return callback(cb, array, pos, dst);
 
         return newNode(type, pos, propName, array, dst);
     }
 
-    bool setProperty(JSObject *obj, const char *name, Value val_) {
-        RootedValue val(cx, val_);
+    bool setProperty(JSObject *objArg, const char *name, Value valArg) {
+        RootedObject obj(cx, objArg);
+        RootedValue val(cx, valArg);
         JS_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
 
         /* Represent "no node" as null and ensure users are not exposed to magic values. */
         if (val.isMagic(JS_SERIALIZE_NO_NODE))
             val.setNull();
 
         /*
          * Bug 575416: instead of Atomize, lookup constant atoms in tbl file
          */
         JSAtom *atom = Atomize(cx, name, strlen(name));
         if (!atom)
             return false;
 
-        return obj->defineProperty(cx, atom->asPropertyName(), val);
+        return JSObject::defineProperty(cx, obj, atom->asPropertyName(), val);
     }
 
     bool newNodeLoc(TokenPos *pos, Value *dst);
 
     bool setNodeLoc(JSObject *obj, TokenPos *pos);
 
     bool setResult(JSObject *obj, Value *dst) {
         JS_ASSERT(obj);
@@ -653,17 +654,17 @@ NodeBuilder::newArray(NodeVector &elts, 
         RootedValue val(cx, elts[i]);
 
         JS_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
 
         /* Represent "no node" as an array hole by not adding the value. */
         if (val.isMagic(JS_SERIALIZE_NO_NODE))
             continue;
 
-        if (!array->setElement(cx, array, i, &val, false))
+        if (!JSObject::setElement(cx, array, array, i, &val, false))
             return false;
     }
 
     dst->setObject(*array);
     return true;
 }
 
 bool
@@ -3291,17 +3292,17 @@ static JSFunctionSpec static_methods[] =
 
 JS_BEGIN_EXTERN_C
 
 JS_PUBLIC_API(JSObject *)
 JS_InitReflect(JSContext *cx, JSObject *objArg)
 {
     RootedObject obj(cx, objArg);
     RootedObject Reflect(cx, NewObjectWithClassProto(cx, &ObjectClass, NULL, obj));
-    if (!Reflect || !Reflect->setSingletonType(cx))
+    if (!Reflect || !JSObject::setSingletonType(cx, Reflect))
         return NULL;
 
     if (!JS_DefineProperty(cx, obj, "Reflect", OBJECT_TO_JSVAL(Reflect),
                            JS_PropertyStub, JS_StrictPropertyStub, 0)) {
         return NULL;
     }
 
     if (!JS_DefineFunctions(cx, Reflect, static_methods))
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -729,53 +729,53 @@ JSObject::putProperty(JSContext *cx, jsi
         JS_ATOMIC_INCREMENT(&cx->runtime->propertyRemovals);
     }
 
     self->checkShapeConsistency();
 
     return shape;
 }
 
-Shape *
-JSObject::changeProperty(JSContext *cx, Shape *shape, unsigned attrs, unsigned mask,
+/* static */ Shape *
+JSObject::changeProperty(JSContext *cx, HandleObject obj, Shape *shape, unsigned attrs, unsigned mask,
                          PropertyOp getter, StrictPropertyOp setter)
 {
-    JS_ASSERT(nativeContainsNoAllocation(*shape));
+    JS_ASSERT(obj->nativeContainsNoAllocation(*shape));
 
     attrs |= shape->attrs & mask;
 
     /* Allow only shared (slotless) => unshared (slotful) transition. */
     JS_ASSERT(!((attrs ^ shape->attrs) & JSPROP_SHARED) ||
               !(attrs & JSPROP_SHARED));
 
-    types::MarkTypePropertyConfigured(cx, this, shape->propid());
+    types::MarkTypePropertyConfigured(cx, obj, shape->propid());
     if (attrs & (JSPROP_GETTER | JSPROP_SETTER))
-        types::AddTypePropertyId(cx, this, shape->propid(), types::Type::UnknownType());
+        types::AddTypePropertyId(cx, obj, shape->propid(), types::Type::UnknownType());
 
     if (getter == JS_PropertyStub)
         getter = NULL;
     if (setter == JS_StrictPropertyStub)
         setter = NULL;
 
-    if (!CheckCanChangeAttrs(cx, this, shape, &attrs))
+    if (!CheckCanChangeAttrs(cx, obj, shape, &attrs))
         return NULL;
 
     if (shape->attrs == attrs && shape->getter() == getter && shape->setter() == setter)
         return shape;
 
     /*
      * Let JSObject::putProperty handle this |overwriting| case, including
      * the conservation of shape->slot (if it's valid). We must not call
      * removeProperty because it will free an allocated shape->slot, and
      * putProperty won't re-allocate it.
      */
-    Shape *newShape = putProperty(cx, shape->propid(), getter, setter, shape->maybeSlot(),
-                                  attrs, shape->flags, shape->maybeShortid());
+    Shape *newShape = obj->putProperty(cx, shape->propid(), getter, setter, shape->maybeSlot(),
+                                       attrs, shape->flags, shape->maybeShortid());
 
-    checkShapeConsistency();
+    obj->checkShapeConsistency();
     return newShape;
 }
 
 bool
 JSObject::removeProperty(JSContext *cx, jsid id_)
 {
     RootedId id(cx, id_);
     RootedObject self(cx, this);
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -368,19 +368,20 @@ str_enumerate(JSContext *cx, HandleObjec
 {
     RootedString str(cx, obj->asString().unbox());
     RootedValue value(cx);
     for (size_t i = 0, length = str->length(); i < length; i++) {
         JSString *str1 = js_NewDependentString(cx, str, i, 1);
         if (!str1)
             return false;
         value.setString(str1);
-        if (!obj->defineElement(cx, i, value,
-                                JS_PropertyStub, JS_StrictPropertyStub,
-                                STRING_ELEMENT_ATTRS)) {
+        if (!JSObject::defineElement(cx, obj, i, value,
+                                     JS_PropertyStub, JS_StrictPropertyStub,
+                                     STRING_ELEMENT_ATTRS))
+        {
             return false;
         }
     }
 
     return true;
 }
 
 static JSBool
@@ -393,18 +394,19 @@ str_resolve(JSContext *cx, HandleObject 
     JSString *str = obj->asString().unbox();
 
     int32_t slot = JSID_TO_INT(id);
     if ((size_t)slot < str->length()) {
         JSString *str1 = cx->runtime->staticStrings.getUnitStringForElement(cx, str, size_t(slot));
         if (!str1)
             return JS_FALSE;
         RootedValue value(cx, StringValue(str1));
-        if (!obj->defineElement(cx, uint32_t(slot), value, NULL, NULL,
-                                STRING_ELEMENT_ATTRS)) {
+        if (!JSObject::defineElement(cx, obj, uint32_t(slot), value, NULL, NULL,
+                                     STRING_ELEMENT_ATTRS))
+        {
             return JS_FALSE;
         }
         objp.set(obj);
     }
     return JS_TRUE;
 }
 
 Class js::StringClass = {
@@ -1717,19 +1719,19 @@ BuildFlatMatchArray(JSContext *cx, Handl
     RootedObject obj(cx, NewSlowEmptyArray(cx));
     if (!obj)
         return false;
 
     RootedValue patternVal(cx, StringValue(fm.pattern()));
     RootedValue matchVal(cx, Int32Value(fm.match()));
     RootedValue textVal(cx, StringValue(textstr));
 
-    if (!obj->defineElement(cx, 0, patternVal) ||
-        !obj->defineProperty(cx, cx->runtime->atomState.indexAtom, matchVal) ||
-        !obj->defineProperty(cx, cx->runtime->atomState.inputAtom, textVal))
+    if (!JSObject::defineElement(cx, obj, 0, patternVal) ||
+        !JSObject::defineProperty(cx, obj, cx->runtime->atomState.indexAtom, matchVal) ||
+        !JSObject::defineProperty(cx, obj, cx->runtime->atomState.inputAtom, textVal))
     {
         return false;
     }
 
     args->rval().setObject(*obj);
     return true;
 }
 
@@ -1746,18 +1748,19 @@ MatchCallback(JSContext *cx, RegExpStati
 
     JSObject *&arrayobj = *static_cast<MatchArgType>(p);
     if (!arrayobj) {
         arrayobj = NewDenseEmptyArray(cx);
         if (!arrayobj)
             return false;
     }
 
+    RootedObject obj(cx, arrayobj);
     RootedValue v(cx);
-    return res->createLastMatch(cx, v.address()) && arrayobj->defineElement(cx, count, v);
+    return res->createLastMatch(cx, v.address()) && JSObject::defineElement(cx, obj, count, v);
 }
 
 JSBool
 js::str_match(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedString str(cx, ThisToStringForStringProto(cx, args));
     if (!str)
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -335,40 +335,40 @@ ArrayBufferObject::obj_trace(JSTracer *t
 JSBool
 ArrayBufferObject::obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
                                      MutableHandleObject objp, MutableHandleShape propp)
 {
     RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
     if (!delegate)
         return false;
 
-    JSBool delegateResult = delegate->lookupGeneric(cx, id, objp, propp);
+    JSBool delegateResult = JSObject::lookupGeneric(cx, delegate, id, objp, propp);
 
     /* If false, there was an error, so propagate it.
      * Otherwise, if propp is non-null, the property
      * was found. Otherwise it was not
      * found so look in the prototype chain.
      */
     if (!delegateResult)
         return false;
 
     if (propp) {
         if (objp == delegate)
             objp.set(obj);
         return true;
     }
 
-    JSObject *proto = obj->getProto();
+    RootedObject proto(cx, obj->getProto());
     if (!proto) {
         objp.set(NULL);
         propp.set(NULL);
         return true;
     }
 
-    return proto->lookupGeneric(cx, id, objp, propp);
+    return JSObject::lookupGeneric(cx, proto, id, objp, propp);
 }
 
 JSBool
 ArrayBufferObject::obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
                                       MutableHandleObject objp, MutableHandleShape propp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return obj_lookupGeneric(cx, obj, id, objp, propp);
@@ -383,27 +383,28 @@ ArrayBufferObject::obj_lookupElement(JSC
         return false;
 
     /*
      * If false, there was an error, so propagate it.
      * Otherwise, if propp is non-null, the property
      * was found. Otherwise it was not
      * found so look in the prototype chain.
      */
-    if (!delegate->lookupElement(cx, index, objp, propp))
+    if (!JSObject::lookupElement(cx, delegate, index, objp, propp))
         return false;
 
     if (propp) {
         if (objp == delegate)
             objp.set(obj);
         return true;
     }
 
-    if (JSObject *proto = obj->getProto())
-        return proto->lookupElement(cx, index, objp, propp);
+    RootedObject proto(cx, obj->getProto());
+    if (proto)
+        return JSObject::lookupElement(cx, proto, index, objp, propp);
 
     objp.set(NULL);
     propp.set(NULL);
     return true;
 }
 
 JSBool
 ArrayBufferObject::obj_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
@@ -503,17 +504,17 @@ ArrayBufferObject::obj_getElement(JSCont
 JSBool
 ArrayBufferObject::obj_getElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver,
                                            uint32_t index, MutableHandleValue vp, bool *present)
 {
     RootedObject buffer(cx, getArrayBuffer(obj));
     RootedObject delegate(cx, ArrayBufferDelegate(cx, buffer));
     if (!delegate)
         return false;
-    return delegate->getElementIfPresent(cx, receiver, index, vp, present);
+    return JSObject::getElementIfPresent(cx, delegate, receiver, index, vp, present);
 }
 
 JSBool
 ArrayBufferObject::obj_getSpecial(JSContext *cx, HandleObject obj,
                                   HandleObject receiver, HandleSpecialId sid,
                                   MutableHandleValue vp)
 {
     Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
@@ -724,24 +725,24 @@ TypedArray::obj_lookupGeneric(JSContext 
     JS_ASSERT(tarray->isTypedArray());
 
     if (isArrayIndex(cx, tarray, id)) {
         MarkNonNativePropertyFound(tarray, propp);
         objp.set(tarray);
         return true;
     }
 
-    JSObject *proto = tarray->getProto();
+    RootedObject proto(cx, tarray->getProto());
     if (!proto) {
         objp.set(NULL);
         propp.set(NULL);
         return true;
     }
 
-    return proto->lookupGeneric(cx, id, objp, propp);
+    return JSObject::lookupGeneric(cx, proto, id, objp, propp);
 }
 
 JSBool
 TypedArray::obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
                                MutableHandleObject objp, MutableHandleShape propp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return obj_lookupGeneric(cx, obj, id, objp, propp);
@@ -754,18 +755,19 @@ TypedArray::obj_lookupElement(JSContext 
     JS_ASSERT(tarray->isTypedArray());
 
     if (index < length(tarray)) {
         MarkNonNativePropertyFound(tarray, propp);
         objp.set(tarray);
         return true;
     }
 
-    if (JSObject *proto = tarray->getProto())
-        return proto->lookupElement(cx, index, objp, propp);
+    RootedObject proto(cx, tarray->getProto());
+    if (proto)
+        return JSObject::lookupElement(cx, proto, index, objp, propp);
 
     objp.set(NULL);
     propp.set(NULL);
     return true;
 }
 
 JSBool
 TypedArray::obj_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
@@ -933,56 +935,56 @@ class TypedArrayTemplate
     {
         MarkSlot(trc, &obj->getFixedSlotRef(FIELD_BUFFER), "typedarray.buffer");
     }
 
     static JSBool
     obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandlePropertyName name,
                     MutableHandleValue vp)
     {
-        JSObject *proto = obj->getProto();
+        RootedObject proto(cx, obj->getProto());
         if (!proto) {
             vp.setUndefined();
             return true;
         }
 
-        return proto->getProperty(cx, receiver, name, vp);
+        return JSObject::getProperty(cx, proto, receiver, name, vp);
     }
 
     static JSBool
     obj_getElement(JSContext *cx, HandleObject tarray, HandleObject receiver, uint32_t index,
                    MutableHandleValue vp)
     {
         JS_ASSERT(tarray->isTypedArray());
 
         if (index < length(tarray)) {
             copyIndexToValue(cx, tarray, index, vp);
             return true;
         }
 
-        JSObject *proto = tarray->getProto();
+        RootedObject proto(cx, tarray->getProto());
         if (!proto) {
             vp.setUndefined();
             return true;
         }
 
-        return proto->getElement(cx, receiver, index, vp);
+        return JSObject::getElement(cx, proto, receiver, index, vp);
     }
 
     static JSBool
     obj_getSpecial(JSContext *cx, HandleObject obj, HandleObject receiver, HandleSpecialId sid,
                    MutableHandleValue vp)
     {
-        JSObject *proto = obj->getProto();
+        RootedObject proto(cx, obj->getProto());
         if (!proto) {
             vp.setUndefined();
             return true;
         }
 
-        return proto->getSpecial(cx, receiver, sid, vp);
+        return JSObject::getSpecial(cx, proto, receiver, sid, vp);
     }
 
     static JSBool
     obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
                    MutableHandleValue vp)
     {
         RootedValue idval(cx, IdToValue(id));
 
@@ -1014,23 +1016,23 @@ class TypedArrayTemplate
         // Fast-path the common case of index < length
         if (index < length(tarray)) {
             // this inline function is specialized for each type
             copyIndexToValue(cx, tarray, index, vp);
             *present = true;
             return true;
         }
 
-        JSObject *proto = tarray->getProto();
+        RootedObject proto(cx, tarray->getProto());
         if (!proto) {
             vp.setUndefined();
             return true;
         }
 
-        return proto->getElementIfPresent(cx, receiver, index, vp, present);
+        return JSObject::getElementIfPresent(cx, proto, receiver, index, vp, present);
     }
 
     static bool
     toDoubleForTypedArray(JSContext *cx, HandleValue vp, double *d)
     {
         if (vp.isDouble()) {
             *d = vp.toDouble();
         } else if (vp.isNull()) {
@@ -1263,17 +1265,17 @@ class TypedArrayTemplate
 
         if (proto) {
             types::TypeObject *type = proto->getNewType(cx);
             if (!type)
                 return NULL;
             obj->setType(type);
         } else if (cx->typeInferenceEnabled()) {
             if (len * sizeof(NativeType) >= TypedArray::SINGLETON_TYPE_BYTE_LENGTH) {
-                if (!obj->setSingletonType(cx))
+                if (!JSObject::setSingletonType(cx, obj))
                     return NULL;
             } else {
                 jsbytecode *pc;
                 RootedScript script(cx, cx->stack.currentScript(&pc));
                 if (script) {
                     if (!types::SetInitializerObjectType(cx, script, pc, obj))
                         return NULL;
                 }
@@ -1607,17 +1609,17 @@ class TypedArrayTemplate
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
                 return false;
             }
 
             if (!copyFromTypedArray(cx, tarray, arg0, offset))
                 return false;
         } else {
             uint32_t len;
-            if (!js_GetLengthProperty(cx, arg0, &len))
+            if (!GetLengthProperty(cx, arg0, &len))
                 return false;
 
             // avoid overflow; we know that offset <= length
             if (len > length(tarray) - offset) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
                 return false;
             }
 
@@ -1744,17 +1746,17 @@ class TypedArrayTemplate
             return NULL;
         return makeInstance(cx, buffer, 0, nelements);
     }
 
     static JSObject *
     fromArray(JSContext *cx, HandleObject other)
     {
         uint32_t len;
-        if (!js_GetLengthProperty(cx, other, &len))
+        if (!GetLengthProperty(cx, other, &len))
             return NULL;
 
         RootedObject bufobj(cx, createBufferWithSizeAndCount(cx, len));
         if (!bufobj)
             return NULL;
 
         RootedObject obj(cx, makeInstance(cx, bufobj, 0, len));
         if (!obj || !copyFromArray(cx, obj, other, len))
@@ -1858,17 +1860,17 @@ class TypedArrayTemplate
              * treats a hole as undefined.
              */
             for (unsigned i = 0; i < len; ++i)
                 *dest++ = nativeFromValue(cx, *src++);
         } else {
             RootedValue v(cx);
 
             for (unsigned i = 0; i < len; ++i) {
-                if (!ar->getElement(cx, i, &v))
+                if (!JSObject::getElement(cx, ar, ar, i, &v))
                     return false;
                 *dest++ = nativeFromValue(cx, v);
             }
         }
 
         return true;
     }
 
@@ -3045,22 +3047,24 @@ InitTypedArrayClass(JSContext *cx)
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, proto))
         return NULL;
 
     RootedValue bytesValue(cx, Int32Value(ArrayType::BYTES_PER_ELEMENT));
 
-    if (!ctor->defineProperty(cx, cx->runtime->atomState.BYTES_PER_ELEMENTAtom, bytesValue,
-                              JS_PropertyStub, JS_StrictPropertyStub,
-                              JSPROP_PERMANENT | JSPROP_READONLY) ||
-        !proto->defineProperty(cx, cx->runtime->atomState.BYTES_PER_ELEMENTAtom, bytesValue,
-                               JS_PropertyStub, JS_StrictPropertyStub,
-                               JSPROP_PERMANENT | JSPROP_READONLY))
+    if (!JSObject::defineProperty(cx, ctor,
+                                  cx->runtime->atomState.BYTES_PER_ELEMENTAtom, bytesValue,
+                                  JS_PropertyStub, JS_StrictPropertyStub,
+                                  JSPROP_PERMANENT | JSPROP_READONLY) ||
+        !JSObject::defineProperty(cx, proto,
+                                  cx->runtime->atomState.BYTES_PER_ELEMENTAtom, bytesValue,
+                                  JS_PropertyStub, JS_StrictPropertyStub,
+                                  JSPROP_PERMANENT | JSPROP_READONLY))
     {
         return NULL;
     }
 
     if (!ArrayType::defineGetters(cx, proto))
         return NULL;
 
     if (!JS_DefineFunctions(cx, proto, ArrayType::jsfuncs))
--- a/js/src/jstypedarrayinlines.h
+++ b/js/src/jstypedarrayinlines.h
@@ -171,17 +171,17 @@ DataViewObject::create(JSContext *cx, ui
 
     if (proto) {
         types::TypeObject *type = proto->getNewType(cx);
         if (!type)
             return NULL;
         obj->setType(type);
     } else if (cx->typeInferenceEnabled()) {
         if (byteLength >= TypedArray::SINGLETON_TYPE_BYTE_LENGTH) {
-            if (!obj->setSingletonType(cx))
+            if (!JSObject::setSingletonType(cx, obj))
                 return NULL;
         } else {
             jsbytecode *pc;
             RootedScript script(cx, cx->stack.currentScript(&pc));
             if (script) {
                 if (!types::SetInitializerObjectType(cx, script, pc, obj))
                     return NULL;
             }
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -6019,17 +6019,17 @@ NamespacesToJSArray(JSContext *cx, JSXML
     *rval = OBJECT_TO_JSVAL(arrayobj);
 
     RootedValue v(cx);
     for (uint32_t i = 0, n = array->length; i < n; i++) {
         JSObject *ns = XMLARRAY_MEMBER(array, i, JSObject);
         if (!ns)
             continue;
         v.setObject(*ns);
-        if (!arrayobj->setElement(cx, arrayobj, i, &v, false))
+        if (!JSObject::setElement(cx, arrayobj, arrayobj, i, &v, false))
             return false;
     }
     return true;
 }
 
 static JSBool
 xml_inScopeNamespaces(JSContext *cx, unsigned argc, jsval *vp)
 {
@@ -7439,19 +7439,19 @@ js_InitXMLClass(JSContext *cx, JSObject 
     if (!SetDefaultXMLSettings(cx, ctor))
         return NULL;
 
     /* Define the XMLList function, and give it the same .prototype as XML. */
     RootedFunction xmllist(cx, JS_DefineFunction(cx, global, js_XMLList_str, XMLList, 1, JSFUN_CONSTRUCTOR));
     if (!xmllist)
         return NULL;
     RootedValue value(cx, ObjectValue(*xmlProto));
-    if (!xmllist->defineProperty(cx, cx->runtime->atomState.classPrototypeAtom,
-                                 value, JS_PropertyStub, JS_StrictPropertyStub,
-                                 JSPROP_PERMANENT | JSPROP_READONLY))
+    if (!JSObject::defineProperty(cx, xmllist, cx->runtime->atomState.classPrototypeAtom,
+                                  value, JS_PropertyStub, JS_StrictPropertyStub,
+                                  JSPROP_PERMANENT | JSPROP_READONLY))
     {
         return NULL;
     }
 
     if (!DefineConstructorAndPrototype(cx, global, JSProto_XML, ctor, xmlProto))
         return NULL;
 
     /* Define the isXMLName function. */
@@ -7518,64 +7518,65 @@ GlobalObject::getFunctionNamespace(JSCon
  * its v argument as the uri of a new Namespace, with "" as the prefix.  See
  * ECMA-357 12.1 and 12.1.1.  Note that if Set is called with a Namespace n,
  * the default XML namespace will be set to ("", n.uri).  So the uri string
  * is really the only usefully stored value of the default namespace.
  */
 JSBool
 js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp)
 {
-    JSObject *ns, *obj;
+    JSObject *ns;
+    RootedObject obj(cx);
     RootedValue v(cx);
 
     RootedObject tmp(cx);
 
     JSObject *scopeChain = GetCurrentScopeChain(cx);
     if (!scopeChain)
         return false;
 
     obj = NULL;
     for (tmp = scopeChain; tmp; tmp = tmp->enclosingScope()) {
         if (tmp->isBlock() || tmp->isWith())
             continue;
-        if (!tmp->getSpecial(cx, tmp, SpecialId::defaultXMLNamespace(), &v))
+        if (!JSObject::getSpecial(cx, tmp, tmp, SpecialId::defaultXMLNamespace(), &v))
             return JS_FALSE;
         if (!JSVAL_IS_PRIMITIVE(v)) {
             *vp = v;
             return JS_TRUE;
         }
         obj = tmp;
     }
 
     ns = ConstructObjectWithArguments(cx, &NamespaceClass, 0, NULL);
     if (!ns)
         return JS_FALSE;
     v = OBJECT_TO_JSVAL(ns);
-    if (!obj->defineSpecial(cx, SpecialId::defaultXMLNamespace(), v,
-                            JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT)) {
+    if (!JSObject::defineSpecial(cx, obj, SpecialId::defaultXMLNamespace(), v,
+                                 JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT)) {
         return JS_FALSE;
     }
     *vp = v;
     return JS_TRUE;
 }
 
 JSBool
 js_SetDefaultXMLNamespace(JSContext *cx, const Value &v)
 {
     Value argv[2];
     argv[0].setString(cx->runtime->emptyString);
     argv[1] = v;
     JSObject *ns = ConstructObjectWithArguments(cx, &NamespaceClass, 2, argv);
     if (!ns)
         return JS_FALSE;
 
-    JSObject &varobj = cx->fp()->varObj();
+    RootedObject varobj(cx, &cx->fp()->varObj());
     RootedValue value(cx, ObjectValue(*ns));
-    if (!varobj.defineSpecial(cx, SpecialId::defaultXMLNamespace(), value,
-                              JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT)) {
+    if (!JSObject::defineSpecial(cx, varobj, SpecialId::defaultXMLNamespace(), value,
+                                 JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT)) {
         return JS_FALSE;
     }
     return JS_TRUE;
 }
 
 JSBool
 js_ToAttributeName(JSContext *cx, Value *vp)
 {
@@ -7668,17 +7669,18 @@ js_GetAnyName(JSContext *cx, jsid *idp)
 
 JSBool
 js_FindXMLProperty(JSContext *cx, const Value &nameval, MutableHandleObject objp, jsid *idp)
 {
     JSObject *nameobj;
     jsval v;
     JSObject *qn;
     RootedId funid(cx);
-    JSObject *obj, *target, *proto;
+    RootedObject target(cx);
+    JSObject *obj, *proto;
     JSXML *xml;
     JSBool found;
 
     JS_ASSERT(nameval.isObject());
     nameobj = &nameval.toObject();
     if (nameobj->getClass() == &AnyNameClass) {
         v = STRING_TO_JSVAL(cx->runtime->atomState.starAtom);
         nameobj = ConstructObjectWithArguments(cx, &QNameClass, 1, &v);
@@ -7718,17 +7720,17 @@ js_FindXMLProperty(JSContext *cx, const 
             if (found) {
                 *idp = OBJECT_TO_JSID(nameobj);
                 objp.set(target);
                 return JS_TRUE;
             }
         } else if (!JSID_IS_VOID(funid)) {
             RootedObject pobj(cx);
             RootedShape prop(cx);
-            if (!target->lookupGeneric(cx, funid, &pobj, &prop))
+            if (!JSObject::lookupGeneric(cx, target, funid, &pobj, &prop))
                 return JS_FALSE;
             if (prop) {
                 *idp = funid;
                 objp.set(target);
                 return JS_TRUE;
             }
         }
     } while ((obj = obj->enclosingScope()) != NULL);
@@ -7762,21 +7764,21 @@ GetXMLFunction(JSContext *cx, HandleObje
             break;
     }
 
     JSXML *xml = (JSXML *) obj->getPrivate();
     if (!HasSimpleContent(xml))
         return true;
 
     /* Search in String.prototype to implement 11.2.2.1 Step 3(f). */
-    JSObject *proto = obj->global().getOrCreateStringPrototype(cx);
+    RootedObject proto(cx, obj->global().getOrCreateStringPrototype(cx));
     if (!proto)
         return false;
 
-    return proto->getGeneric(cx, id, vp);
+    return JSObject::getGeneric(cx, proto, proto, id, vp);
 }
 
 static JSXML *
 GetPrivate(JSContext *cx, JSObject *obj, const char *method)
 {
     if (!obj->isXML()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_INCOMPATIBLE_METHOD,
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -5180,17 +5180,17 @@ mjit::Compiler::testSingletonProperty(Ha
             return false;
         if (nobj->getClass()->ops.lookupGeneric)
             return false;
         nobj = nobj->getProto();
     }
 
     RootedObject holder(cx);
     RootedShape shape(cx);
-    if (!obj->lookupGeneric(cx, id, &holder, &shape))
+    if (!JSObject::lookupGeneric(cx, obj, id, &holder, &shape))
         return false;
     if (!shape)
         return false;
 
     if (shape->hasDefaultGetter()) {
         if (!shape->hasSlot())
             return false;
         if (holder->getSlot(shape->slot()).isUndefined())
--- a/js/src/methodjit/MonoIC.cpp
+++ b/js/src/methodjit/MonoIC.cpp
@@ -1076,17 +1076,17 @@ ic::SplatApplyArgs(VMFrame &f)
     if (!args[1].isObject()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_APPLY_ARGS, js_apply_str);
         THROWV(false);
     }
 
     /* Steps 4-5. */
     RootedObject aobj(cx, &args[1].toObject());
     uint32_t length;
-    if (!js_GetLengthProperty(cx, aobj, &length))
+    if (!GetLengthProperty(cx, aobj, &length))
         THROWV(false);
 
     /* Step 6. */
     if (length > StackSpace::ARGS_LENGTH_MAX) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_TOO_MANY_FUN_APPLY_ARGS);
         THROWV(false);
     }
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -436,17 +436,17 @@ class SetPropCompiler : public PICStubCo
         if (clasp->ops.setProperty)
             return disable("ops set property hook");
 
         RootedObject holder(cx);
         RootedShape shape(cx);
 
         /* lookupProperty can trigger recompilations. */
         RecompilationMonitor monitor(cx);
-        if (!obj->lookupProperty(cx, name, &holder, &shape))
+        if (!JSObject::lookupProperty(cx, obj, name, &holder, &shape))
             return error();
         if (monitor.recompiled())
             return Lookup_Uncacheable;
 
         /* If the property exists but is on a prototype, treat as addprop. */
         if (shape && holder != obj) {
             if (!holder->isNative())
                 return disable("non-native holder");
@@ -651,27 +651,27 @@ struct GetPropHelper {
             return ic.disable(cx, "non-native");
         if (!IsCacheableProtoChain(obj, holder))
             return ic.disable(cx, "non-native holder");
         shape = prop;
         return Lookup_Cacheable;
     }
 
     LookupStatus lookup() {
-        JSObject *aobj = obj;
+        RootedObject aobj(cx, obj);
         if (obj->isDenseArray())
             aobj = obj->getProto();
         else if (IsCacheableListBase(obj))
             aobj = obj->getProto();
 
         if (!aobj->isNative())
             return ic.disable(f, "non-native");
 
         RecompilationMonitor monitor(cx);
-        if (!aobj->lookupProperty(cx, name, &holder, &prop))
+        if (!JSObject::lookupProperty(cx, aobj, name, &holder, &prop))
             return ic.error(cx);
         if (monitor.recompiled())
             return Lookup_Uncacheable;
 
         if (!prop) {
             /*
              * Just because we didn't find the property on the object doesn't
              * mean it won't magically appear through various engine hacks:
@@ -1736,18 +1736,18 @@ class ScopeNameCompiler : public PICStub
         if (obj->isGlobal())
             return generateGlobalStub(obj);
 
         return disable("scope object not handled yet");
     }
 
     bool retrieve(MutableHandleValue vp, PICInfo::Kind kind)
     {
-        JSObject *obj = getprop.obj;
-        Rooted<JSObject*> holder(cx, getprop.holder);
+        RootedObject obj(cx, getprop.obj);
+        RootedObject holder(cx, getprop.holder);
         RootedShape prop(cx, getprop.prop);
 
         if (!prop) {
             /* Kludge to allow (typeof foo == "undefined") tests. */
             if (kind == ic::PICInfo::NAME) {
                 JSOp op2 = JSOp(f.pc()[JSOP_NAME_LENGTH]);
                 if (op2 == JSOP_TYPEOF) {
                     vp.setUndefined();
@@ -1756,17 +1756,17 @@ class ScopeNameCompiler : public PICStub
             }
             ReportAtomNotDefined(cx, name);
             return false;
         }
 
         // If the property was found, but we decided not to cache it, then
         // take a slow path and do a full property fetch.
         if (!getprop.shape) {
-            if (!obj->getProperty(cx, name, vp))
+            if (!JSObject::getProperty(cx, obj, obj, name, vp))
                 return false;
             return true;
         }
 
         RootedShape shape(cx, getprop.shape);
         Rooted<JSObject*> normalized(cx, obj);
         if (obj->isWith() && !shape->hasDefaultGetter())
             normalized = &obj->asWith().object();
@@ -1968,20 +1968,21 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic
             if (status == Lookup_Error)
                 THROW();
             JSString *str = f.regs.sp[-1].toString();
             f.regs.sp[-1].setInt32(str->length());
         } else {
             LookupStatus status = cc.generateStringPropertyStub();
             if (status == Lookup_Error)
                 THROW();
-            JSObject *obj = ToObjectFromStack(f.cx, objval);
+            RootedObject obj(f.cx, ToObjectFromStack(f.cx, objval));
             if (!obj)
                 THROW();
-            if (!obj->getProperty(f.cx, name, MutableHandleValue::fromMarkedLocation(&f.regs.sp[-1])))
+            MutableHandleValue vp = MutableHandleValue::fromMarkedLocation(&f.regs.sp[-1]);
+            if (!JSObject::getProperty(f.cx, obj, obj, name, vp))
                 THROW();
         }
         return;
     }
 
     RecompilationMonitor monitor(f.cx);
 
     RootedObject obj(f.cx, ToObjectFromStack(f.cx, objval));
@@ -1994,17 +1995,17 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic
             THROW();
     }
 
     RootedValue v(f.cx);
     if (cached) {
         if (!GetPropertyOperation(f.cx, f.pc(), &objval, &v))
             THROW();
     } else {
-        if (!obj->getProperty(f.cx, name, &v))
+        if (!JSObject::getProperty(f.cx, obj, obj, name, &v))
             THROW();
     }
 
     f.regs.sp[-1] = v;
 }
 
 static void JS_FASTCALL
 DisabledSetPropIC(VMFrame &f, ic::PICInfo *pic)
@@ -2515,17 +2516,17 @@ GetElementIC::attachTypedArray(VMFrame &
     // For simplicitly, they are currently monomorphic.
     if (stubsGenerated == MAX_GETELEM_IC_STUBS)
         disable(f, "max stubs reached");
 
     disable(f, "generated typed array stub");
 
     // Fetch the value as expected of Lookup_Cacheable for GetElement.
     Rooted<jsid> idRoot(cx, id);
-    if (!obj->getGeneric(cx, idRoot, vp))
+    if (!JSObject::getGeneric(cx, obj, obj, idRoot, vp))
         return Lookup_Error;
 
     return Lookup_Cacheable;
 }
 #endif /* JS_METHODJIT_TYPED_ARRAY */
 
 LookupStatus
 GetElementIC::update(VMFrame &f, HandleObject obj, HandleValue v, HandleId id, MutableHandleValue vp)
@@ -2610,17 +2611,17 @@ ic::GetElement(VMFrame &f, ic::GetElemen
                 THROW();
 
             // If the result can be cached, the value was already retrieved.
             JS_ASSERT(!f.regs.sp[-2].isMagic());
             return;
         }
     }
 
-    if (!obj->getGeneric(cx, id, res))
+    if (!JSObject::getGeneric(cx, obj, obj, id, res))
         THROW();
 
 #if JS_HAS_NO_SUCH_METHOD
     if (*f.pc() == JSOP_CALLELEM && JS_UNLIKELY(f.regs.sp[-2].isPrimitive())) {
         if (!OnUnknownMethod(cx, obj, idval, res))
             THROW();
     }
 #endif
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -139,17 +139,17 @@ stubs::SetElem(VMFrame &f)
                 obj->setDenseArrayElementWithType(cx, i, rval);
                 goto end_setelem;
             } else {
                 if (f.script()->hasAnalysis())
                     f.script()->analysis()->getCode(f.pc()).arrayWriteHole = true;
             }
         }
     } while (0);
-    if (!obj->setGeneric(cx, obj, id, &rval, strict))
+    if (!JSObject::setGeneric(cx, obj, obj, id, &rval, strict))
         THROW();
   end_setelem:
     /* :FIXME: Moving the assigned object into the lowest stack slot
      * is a temporary hack. What we actually want is an implementation
      * of popAfterSet() that allows popping more than one value;
      * this logic can then be handled in Compiler.cpp. */
     regs.sp[-3] = regs.sp[-1];
 }
@@ -324,38 +324,38 @@ stubs::DefFun(VMFrame &f, JSFunction *fu
      * and functions defined by eval inside let or with blocks.
      */
     Rooted<JSObject*> parent(cx, &fp->varObj());
 
     /* ES5 10.5 (NB: with subsequent errata). */
     RootedPropertyName name(cx, fun->atom->asPropertyName());
     RootedShape shape(cx);
     RootedObject pobj(cx);
-    if (!parent->lookupProperty(cx, name, &pobj, &shape))
+    if (!JSObject::lookupProperty(cx, parent, name, &pobj, &shape))
         THROW();
 
     RootedValue rval(cx, ObjectValue(*fun));
 
     do {
         /* Steps 5d, 5f. */
         if (!shape || pobj != parent) {
-            if (!parent->defineProperty(cx, name, rval,
-                                        JS_PropertyStub, JS_StrictPropertyStub, attrs))
+            if (!JSObject::defineProperty(cx, parent, name, rval,
+                                          JS_PropertyStub, JS_StrictPropertyStub, attrs))
             {
                 THROW();
             }
             break;
         }
 
         /* Step 5e. */
         JS_ASSERT(parent->isNative());
         if (parent->isGlobal()) {
             if (shape->configurable()) {
-                if (!parent->defineProperty(cx, name, rval,
-                                            JS_PropertyStub, JS_StrictPropertyStub, attrs))
+                if (!JSObject::defineProperty(cx, parent, name, rval,
+                                              JS_PropertyStub, JS_StrictPropertyStub, attrs))
                 {
                     THROW();
                 }
                 break;
             }
 
             if (shape->isAccessorDescriptor() || !shape->writable() || !shape->enumerable()) {
                 JSAutoByteString bytes;
@@ -370,17 +370,17 @@ stubs::DefFun(VMFrame &f, JSFunction *fu
         /*
          * Non-global properties, and global properties which we aren't simply
          * redefining, must be set.  First, this preserves their attributes.
          * Second, this will produce warnings and/or errors as necessary if the
          * specified Call object property is not writable (const).
          */
 
         /* Step 5f. */
-        if (!parent->setProperty(cx, parent, name, &rval, strict))
+        if (!JSObject::setProperty(cx, parent, parent, name, &rval, strict))
             THROW();
     } while (false);
 }
 
 template void JS_FASTCALL stubs::DefFun<true>(VMFrame &f, JSFunction *fun);
 template void JS_FASTCALL stubs::DefFun<false>(VMFrame &f, JSFunction *fun);
 
 #define RELATIONAL(OP)                                                        \
@@ -922,20 +922,20 @@ stubs::InitElem(VMFrame &f, uint32_t las
      * If rref is a hole, do not call JSObject::defineProperty. In this case,
      * obj must be an array, so if the current op is the last element
      * initialiser, set the array length to one greater than id.
      */
     if (rref.isMagic(JS_ARRAY_HOLE)) {
         JS_ASSERT(obj->isArray());
         JS_ASSERT(JSID_IS_INT(id));
         JS_ASSERT(uint32_t(JSID_TO_INT(id)) < StackSpace::ARGS_LENGTH_MAX);
-        if (last && !js_SetLengthProperty(cx, obj, (uint32_t) (JSID_TO_INT(id) + 1)))
+        if (last && !SetLengthProperty(cx, obj, (uint32_t) (JSID_TO_INT(id) + 1)))
             THROW();
     } else {
-        if (!obj->defineGeneric(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE))
+        if (!JSObject::defineGeneric(cx, obj, id, rref, NULL, NULL, JSPROP_ENUMERATE))
             THROW();
     }
 }
 
 void JS_FASTCALL
 stubs::RegExp(VMFrame &f, JSObject *regex)
 {
     /*
@@ -985,20 +985,19 @@ stubs::GetPropNoCache(VMFrame &f, Proper
     FrameRegs &regs = f.regs;
 
     const Value &lval = f.regs.sp[-1];
 
     // Uncached lookups are only used for .prototype accesses at the start of constructors.
     JS_ASSERT(lval.isObject());
     JS_ASSERT(name == cx->runtime->atomState.classPrototypeAtom);
 
-    JSObject *obj = &lval.toObject();
-
+    RootedObject obj(cx, &lval.toObject());
     RootedValue rval(cx);
-    if (!obj->getProperty(cx, name, &rval))
+    if (!JSObject::getProperty(cx, obj, obj, name, &rval))
         THROW();
 
     regs.sp[-1] = rval;
 }
 
 void JS_FASTCALL
 stubs::SetProp(VMFrame &f, PropertyName *name)
 {
@@ -1350,58 +1349,58 @@ stubs::DelName(VMFrame &f, PropertyName 
 
     /* Strict mode code should never contain JSOP_DELNAME opcodes. */
     JS_ASSERT(!f.script()->strictModeCode);
 
     /* ECMA says to return true if name is undefined or inherited. */
     f.regs.sp++;
     f.regs.sp[-1] = BooleanValue(true);
     if (prop) {
-        if (!obj->deleteProperty(f.cx, name, MutableHandleValue::fromMarkedLocation(&f.regs.sp[-1]), false))
+        if (!JSObject::deleteProperty(f.cx, obj, name, MutableHandleValue::fromMarkedLocation(&f.regs.sp[-1]), false))
             THROW();
     }
 }
 
 template<JSBool strict>
 void JS_FASTCALL
 stubs::DelProp(VMFrame &f, PropertyName *name_)
 {
     JSContext *cx = f.cx;
     RootedPropertyName name(cx, name_);
 
     RootedValue objval(cx, f.regs.sp[-1]);
-    JSObject *obj = ToObjectFromStack(cx, objval);
+    RootedObject obj(cx, ToObjectFromStack(cx, objval));
     if (!obj)
         THROW();
 
     RootedValue rval(cx);
-    if (!obj->deleteProperty(cx, name, &rval, strict))
+    if (!JSObject::deleteProperty(cx, obj, name, &rval, strict))
         THROW();
 
     f.regs.sp[-1] = rval;
 }
 
 template void JS_FASTCALL stubs::DelProp<true>(VMFrame &f, PropertyName *name);
 template void JS_FASTCALL stubs::DelProp<false>(VMFrame &f, PropertyName *name);
 
 template<JSBool strict>
 void JS_FASTCALL
 stubs::DelElem(VMFrame &f)
 {
     JSContext *cx = f.cx;
 
     RootedValue objval(cx, f.regs.sp[-2]);
-    JSObject *obj = ToObjectFromStack(cx, objval);
+    RootedObject obj(cx, ToObjectFromStack(cx, objval));
     if (!obj)
         THROW();
 
     const Value &propval = f.regs.sp[-1];
     MutableHandleValue rval = MutableHandleValue::fromMarkedLocation(&f.regs.sp[-2]);
 
-    if (!obj->deleteByValue(cx, propval, rval, strict))
+    if (!JSObject::deleteByValue(cx, obj, propval, rval, strict))
         THROW();
 }
 
 void JS_FASTCALL
 stubs::DefVarOrConst(VMFrame &f, PropertyName *dn)
 {
     unsigned attrs = JSPROP_ENUMERATE;
     if (!f.fp()->isEvalFrame())
@@ -1416,21 +1415,21 @@ stubs::DefVarOrConst(VMFrame &f, Propert
         THROW();
 }
 
 void JS_FASTCALL
 stubs::SetConst(VMFrame &f, PropertyName *name)
 {
     JSContext *cx = f.cx;
 
-    JSObject *obj = &f.fp()->varObj();
+    RootedObject obj(cx, &f.fp()->varObj());
     HandleValue ref = HandleValue::fromMarkedLocation(&f.regs.sp[-1]);
 
-    if (!obj->defineProperty(cx, name, ref, JS_PropertyStub, JS_StrictPropertyStub,
-                             JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY))
+    if (!JSObject::defineProperty(cx, obj, name, ref, JS_PropertyStub, JS_StrictPropertyStub,
+                                  JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY))
     {
         THROW();
     }
 }
 
 JSBool JS_FASTCALL
 stubs::In(VMFrame &f)
 {
@@ -1448,17 +1447,17 @@ stubs::In(VMFrame &f)
     if (!FetchElementId(f.cx, obj, f.regs.sp[-2], id.address(),
                         MutableHandleValue::fromMarkedLocation(&f.regs.sp[-2])))
     {
         THROWV(JS_FALSE);
     }
 
     RootedObject obj2(cx);
     RootedShape prop(cx);
-    if (!obj->lookupGeneric(cx, id, &obj2, &prop))
+    if (!JSObject::lookupGeneric(cx, obj, id, &obj2, &prop))
         THROWV(JS_FALSE);
 
     return !!prop;
 }
 
 template void JS_FASTCALL stubs::DelElem<true>(VMFrame &f);
 template void JS_FASTCALL stubs::DelElem<false>(VMFrame &f);
 
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -2725,23 +2725,24 @@ CopyProperty(JSContext *cx, HandleObject
         propFlags = shape->getFlags();
     } else if (IsProxy(referent)) {
         PropertyDescriptor desc;
         if (!Proxy::getOwnPropertyDescriptor(cx, referent, id, false, &desc))
             return false;
         if (!desc.obj)
             return true;
     } else {
-        if (!referent->lookupGeneric(cx, id, objp, &shape))
+        if (!JSObject::lookupGeneric(cx, referent, id, objp, &shape))
             return false;
         if (objp != referent)
             return true;
         RootedValue value(cx);
-        if (!referent->getGeneric(cx, id, &value) ||
-            !referent->getGenericAttributes(cx, id, &desc.attrs)) {
+        if (!JSObject::getGeneric(cx, referent, referent, id, &value) ||
+            !JSObject::getGenericAttributes(cx, referent, id, &desc.attrs))
+        {
             return false;
         }
         desc.value = value;
         desc.attrs &= JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT;
         desc.getter = JS_PropertyStub;
         desc.setter = JS_StrictPropertyStub;
         desc.shortid = 0;
     }
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -1812,17 +1812,18 @@ Debugger::construct(JSContext *cx, unsig
         if (!IsCrossCompartmentWrapper(argobj)) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CCW_REQUIRED, "Debugger");
             return false;
         }
     }
 
     /* Get Debugger.prototype. */
     RootedValue v(cx);
-    if (!args.callee().getProperty(cx, cx->runtime->atomState.classPrototypeAtom, &v))
+    RootedObject callee(cx, &args.callee());
+    if (!JSObject::getProperty(cx, callee, callee, cx->runtime->atomState.classPrototypeAtom, &v))
         return false;
     RootedObject proto(cx, &v.toObject());
     JS_ASSERT(proto->getClass() == &Debugger::jsclass);
 
     /*
      * Make the new Debugger object. Each one has a reference to
      * Debugger.{Frame,Object,Script}.prototype in reserved slots. The rest of
      * the reserved slots are for hooks; they default to undefined.
@@ -2016,17 +2017,17 @@ class Debugger::ScriptQuery {
      * it specifies.
      */
     bool parseQuery(HandleObject query) {
         /*
          * Check for a 'global' property, which limits the results to those
          * scripts scoped to a particular global object.
          */
         RootedValue global(cx);
-        if (!query->getProperty(cx, cx->runtime->atomState.globalAtom, &global))
+        if (!JSObject::getProperty(cx, query, query, cx->runtime->atomState.globalAtom, &global))
             return false;
         if (global.isUndefined()) {
             matchAllDebuggeeGlobals();
         } else {
             JSObject *referent = debugger->unwrapDebuggeeArgument(cx, global);
             if (!referent)
                 return false;
             GlobalObject *globalObject = &referent->global();
@@ -2037,27 +2038,27 @@ class Debugger::ScriptQuery {
              */
             if (debugger->debuggees.has(globalObject)) {
                 if (!matchSingleGlobal(globalObject))
                     return false;
             }
         }
 
         /* Check for a 'url' property. */
-        if (!query->getProperty(cx, cx->runtime->atomState.urlAtom, &url))
+        if (!JSObject::getProperty(cx, query, query, cx->runtime->atomState.urlAtom, &url))
             return false;
         if (!url.isUndefined() && !url.isString()) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE,
                                  "query object's 'url' property", "neither undefined nor a string");
             return false;
         }
 
         /* Check for a 'line' property. */
         RootedValue lineProperty(cx);
-        if (!query->getProperty(cx, cx->runtime->atomState.lineAtom, &lineProperty))
+        if (!JSObject::getProperty(cx, query, query, cx->runtime->atomState.lineAtom, &lineProperty))
             return false;
         if (lineProperty.isUndefined()) {
             hasLine = false;
         } else if (lineProperty.isNumber()) {
             if (url.isUndefined()) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_QUERY_LINE_WITHOUT_URL);
                 return false;
             }
@@ -2071,18 +2072,19 @@ class Debugger::ScriptQuery {
         } else {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE,
                                  "query object's 'line' property",
                                  "neither undefined nor an integer");
             return false;
         }
 
         /* Check for an 'innermost' property. */
+        PropertyName *innermostName = cx->runtime->atomState.innermostAtom;
         RootedValue innermostProperty(cx);
-        if (!query->getProperty(cx, cx->runtime->atomState.innermostAtom, &innermostProperty))
+        if (!JSObject::getProperty(cx, query, query, innermostName, &innermostProperty))
             return false;
         innermost = ToBoolean(innermostProperty);
         if (innermost) {
             /* Technically, we need only check hasLine, but this is clearer. */
             if (url.isUndefined() || !hasLine) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_QUERY_INNERMOST_WITHOUT_LINE_URL);
                 return false;
@@ -2820,17 +2822,17 @@ DebuggerScript_getAllOffsets(JSContext *
                 offsets = NewDenseEmptyArray(cx);
                 if (!offsets ||
                     !ValueToId(cx, NumberValue(lineno), id.address()))
                 {
                     return false;
                 }
 
                 RootedValue value(cx, ObjectValue(*offsets));
-                if (!result->defineGeneric(cx, id, value))
+                if (!JSObject::defineGeneric(cx, result, id, value))
                     return false;
             }
 
             /* Append the current offset to the offsets array. */
             if (!js_NewbornArrayPush(cx, offsets, NumberValue(offset)))
                 return false;
         }
     }
@@ -3497,17 +3499,17 @@ DebuggerFrameEval(JSContext *cx, unsigne
             !GetPropertyNames(cx, bindingsobj, JSITER_OWNONLY, &keys) ||
             !values.growBy(keys.length()))
         {
             return false;
         }
         for (size_t i = 0; i < keys.length(); i++) {
             HandleId keyp = HandleId::fromMarkedLocation(&keys[i]);
             MutableHandleValue valp = MutableHandleValue::fromMarkedLocation(&values[i]);
-            if (!bindingsobj->getGeneric(cx, bindingsobj, keyp, valp) ||
+            if (!JSObject::getGeneric(cx, bindingsobj, bindingsobj, keyp, valp) ||
                 !dbg->unwrapDebuggeeValue(cx, valp.address()))
             {
                 return false;
             }
         }
     }
 
     AutoCompartment ac(cx, fp->scopeChain());
@@ -4003,36 +4005,36 @@ DebuggerObject_deleteProperty(JSContext 
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "deleteProperty", args, dbg, obj);
     Value nameArg = argc > 0 ? args[0] : UndefinedValue();
 
     AutoCompartment ac(cx, obj);
     if (!ac.enter() || !cx->compartment->wrap(cx, &nameArg))
         return false;
 
     ErrorCopier ec(ac, dbg->toJSObject());
-    return obj->deleteByValue(cx, nameArg, args.rval(), false);
+    return JSObject::deleteByValue(cx, obj, nameArg, args.rval(), false);
 }
 
 enum SealHelperOp { Seal, Freeze, PreventExtensions };
 
 static JSBool
 DebuggerObject_sealHelper(JSContext *cx, unsigned argc, Value *vp, SealHelperOp op, const char *name)
 {
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, name, args, dbg, obj);
 
     AutoCompartment ac(cx, obj);
     if (!ac.enter())
         return false;
 
     ErrorCopier ec(ac, dbg->toJSObject());
     bool ok;
     if (op == Seal) {
-        ok = obj->seal(cx);
+        ok = JSObject::seal(cx, obj);
     } else if (op == Freeze) {
-        ok = obj->freeze(cx);
+        ok = JSObject::freeze(cx, obj);
     } else {
         JS_ASSERT(op == PreventExtensions);
         if (!obj->isExtensible()) {
             args.rval().setUndefined();
             return true;
         }
         ok = obj->preventExtensions(cx);
     }
@@ -4134,17 +4136,17 @@ ApplyOrCall(JSContext *cx, unsigned argc
     if (mode == ApplyMode) {
         if (argc >= 2 && !args[1].isNullOrUndefined()) {
             if (!args[1].isObject()) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_APPLY_ARGS,
                                      js_apply_str);
                 return false;
             }
             RootedObject argsobj(cx, &args[1].toObject());
-            if (!js_GetLengthProperty(cx, argsobj, &callArgc))
+            if (!GetLengthProperty(cx, argsobj, &callArgc))
                 return false;
             callArgc = unsigned(Min(callArgc, StackSpace::ARGS_LENGTH_MAX));
             if (!argv.growBy(callArgc) || !GetElements(cx, argsobj, callArgc, argv.begin()))
                 return false;
             callArgv = argv.begin();
         }
     } else {
         callArgc = argc > 0 ? unsigned(Min(argc - 1, StackSpace::ARGS_LENGTH_MAX)) : 0;
@@ -4463,17 +4465,17 @@ DebuggerEnv_find(JSContext *cx, unsigned
         if (!ac.enter() || !cx->compartment->wrapId(cx, id.address()))
             return false;
 
         /* This can trigger resolve hooks. */
         ErrorCopier ec(ac, dbg->toJSObject());
         RootedShape prop(cx);
         RootedObject pobj(cx);
         for (; env && !prop; env = env->enclosingScope()) {
-            if (!env->lookupGeneric(cx, id, &pobj, &prop))
+            if (!JSObject::lookupGeneric(cx, env, id, &pobj, &prop))
                 return false;
             if (prop)
                 break;
         }
     }
 
     return dbg->wrapEnvironment(cx, env, args.rval().address());
 }
@@ -4491,17 +4493,17 @@ DebuggerEnv_getVariable(JSContext *cx, u
     RootedValue v(cx);
     {
         AutoCompartment ac(cx, env);
         if (!ac.enter() || !cx->compartment->wrapId(cx, id.address()))
             return false;
 
         /* This can trigger getters. */
         ErrorCopier ec(ac, dbg->toJSObject());
-        if (!env->getGeneric(cx, id, &v))
+        if (!JSObject::getGeneric(cx, env, env, id, &v))
             return false;
     }
 
     if (!dbg->wrapDebuggeeValue(cx, v.address()))
         return false;
     args.rval().set(v);
     return true;
 }
@@ -4529,25 +4531,25 @@ DebuggerEnv_setVariable(JSContext *cx, u
             return false;
         }
 
         /* This can trigger setters. */
         ErrorCopier ec(ac, dbg->toJSObject());
 
         /* Make sure the environment actually has the specified binding. */
         bool has;
-        if (!env->hasProperty(cx, id, &has))
+        if (!JSObject::hasProperty(cx, env, id, &has))
             return false;
         if (!has) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEBUG_VARIABLE_NOT_FOUND);
             return false;
         }
 
         /* Just set the property. */
-        if (!env->setGeneric(cx, env, id, &v, true))
+        if (!JSObject::setGeneric(cx, env, env, id, &v, true))
             return false;
     }
 
     args.rval().setUndefined();
     return true;
 }
 
 static JSPropertySpec DebuggerEnv_properties[] = {
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -259,17 +259,17 @@ GlobalObject::initFunctionAndObjectClass
 
     RootedObject objectProto(cx);
 
     /*
      * Create |Object.prototype| first, mirroring CreateBlankProto but for the
      * prototype of the created object.
      */
     objectProto = NewObjectWithGivenProto(cx, &ObjectClass, NULL, self);
-    if (!objectProto || !objectProto->setSingletonType(cx))
+    if (!objectProto || !JSObject::setSingletonType(cx, objectProto))
         return NULL;
 
     /*
      * The default 'new' type of Object.prototype is required by type inference
      * to have unknown properties, to simplify handling of e.g. heterogenous
      * objects in JSON and script literals.
      */
     if (!objectProto->setNewTypeUnknown(cx))
@@ -320,17 +320,17 @@ GlobalObject::initFunctionAndObjectClass
                                                       ss->length()));
         if (!script || !JSScript::fullyInitTrivial(cx, script))
             return NULL;
 
         functionProto->initScript(script);
         functionProto->getType(cx)->interpretedFunction = functionProto;
         script->setFunction(functionProto);
 
-        if (!functionProto->setSingletonType(cx))
+        if (!JSObject::setSingletonType(cx, functionProto))
             return NULL;
 
         /*
          * The default 'new' type of Function.prototype is required by type
          * inference to have unknown properties, to simplify handling of e.g.
          * CloneFunctionObject.
          */
         if (!functionProto->setNewTypeUnknown(cx))
@@ -394,20 +394,21 @@ GlobalObject::initFunctionAndObjectClass
     Rooted<JSFunction*> getter(cx, js_NewFunction(cx, NULL, ProtoGetter, 0, 0, self, NULL));
     if (!getter)
         return NULL;
 #if JS_HAS_OBJ_PROTO_PROP
     Rooted<JSFunction*> setter(cx, js_NewFunction(cx, NULL, ProtoSetter, 0, 0, self, NULL));
     if (!setter)
         return NULL;
     RootedValue undefinedValue(cx, UndefinedValue());
-    if (!objectProto->defineProperty(cx, cx->runtime->atomState.protoAtom, undefinedValue,
-                                     JS_DATA_TO_FUNC_PTR(PropertyOp, getter.get()),
-                                     JS_DATA_TO_FUNC_PTR(StrictPropertyOp, setter.get()),
-                                     JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED))
+    if (!JSObject::defineProperty(cx, objectProto,
+                                  cx->runtime->atomState.protoAtom, undefinedValue,
+                                  JS_DATA_TO_FUNC_PTR(PropertyOp, getter.get()),
+                                  JS_DATA_TO_FUNC_PTR(StrictPropertyOp, setter.get()),
+                                  JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED))
     {
         return NULL;
     }
 #endif /* JS_HAS_OBJ_PROTO_PROP */
     self->setProtoGetter(getter);
 
 
     if (!DefinePropertiesAndBrand(cx, objectCtor, NULL, object_static_methods) ||
@@ -477,17 +478,17 @@ GlobalObject::create(JSContext *cx, Clas
     JSObject *obj = NewObjectWithGivenProto(cx, clasp, NULL, NULL);
     if (!obj)
         return NULL;
 
     Rooted<GlobalObject *> global(cx, &obj->asGlobal());
 
     cx->compartment->initGlobal(*global);
 
-    if (!global->setSingletonType(cx) || !global->setVarObj(cx))
+    if (!JSObject::setSingletonType(cx, global) || !global->setVarObj(cx))
         return NULL;
 
     /* Construct a regexp statics object for this global object. */
     JSObject *res = RegExpStatics::create(cx, global);
     if (!res)
         return NULL;
     global->initSlot(REGEXP_STATICS, ObjectValue(*res));
     global->initFlags(0);
@@ -497,18 +498,18 @@ GlobalObject::create(JSContext *cx, Clas
 
 /* static */ bool
 GlobalObject::initStandardClasses(JSContext *cx, Handle<GlobalObject*> global)
 {
     JSAtomState &state = cx->runtime->atomState;
 
     /* Define a top-level property 'undefined' with the undefined value. */
     RootedValue undefinedValue(cx, UndefinedValue());
-    if (!global->defineProperty(cx, state.typeAtoms[JSTYPE_VOID], undefinedValue,
-                                JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT | JSPROP_READONLY))
+    if (!JSObject::defineProperty(cx, global, state.typeAtoms[JSTYPE_VOID], undefinedValue,
+                                  JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT | JSPROP_READONLY))
     {
         return false;
     }
 
     if (!global->initFunctionAndObjectClasses(cx))
         return false;
 
     /* Initialize the rest of the standard objects and functions. */
@@ -613,17 +614,17 @@ GlobalObject::createConstructor(JSContex
 
 static JSObject *
 CreateBlankProto(JSContext *cx, Class *clasp, JSObject &proto, GlobalObject &global)
 {
     JS_ASSERT(clasp != &ObjectClass);
     JS_ASSERT(clasp != &FunctionClass);
 
     RootedObject blankProto(cx, NewObjectWithGivenProto(cx, clasp, &proto, &global));
-    if (!blankProto || !blankProto->setSingletonType(cx))
+    if (!blankProto || !JSObject::setSingletonType(cx, blankProto))
         return NULL;
 
     return blankProto;
 }
 
 JSObject *
 GlobalObject::createBlankPrototype(JSContext *cx, Class *clasp)
 {
@@ -644,21 +645,21 @@ GlobalObject::createBlankPrototypeInheri
 bool
 LinkConstructorAndPrototype(JSContext *cx, JSObject *ctor_, JSObject *proto_)
 {
     RootedObject ctor(cx, ctor_), proto(cx, proto_);
 
     RootedValue protoVal(cx, ObjectValue(*proto));
     RootedValue ctorVal(cx, ObjectValue(*ctor));
 
-    return ctor->defineProperty(cx, cx->runtime->atomState.classPrototypeAtom,
-                                protoVal, JS_PropertyStub, JS_StrictPropertyStub,
-                                JSPROP_PERMANENT | JSPROP_READONLY) &&
-           proto->defineProperty(cx, cx->runtime->atomState.constructorAtom,
-                                 ctorVal, JS_PropertyStub, JS_StrictPropertyStub, 0);
+    return JSObject::defineProperty(cx, ctor, cx->runtime->atomState.classPrototypeAtom,
+                                    protoVal, JS_PropertyStub, JS_StrictPropertyStub,
+                                    JSPROP_PERMANENT | JSPROP_READONLY) &&
+           JSObject::defineProperty(cx, proto, cx->runtime->atomState.constructorAtom,
+                                    ctorVal, JS_PropertyStub, JS_StrictPropertyStub, 0);
 }
 
 bool
 DefinePropertiesAndBrand(JSContext *cx, JSObject *obj_,
                          const JSPropertySpec *ps, const JSFunctionSpec *fs)
 {
     RootedObject obj(cx, obj_);
 
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -283,30 +283,31 @@ WithObject::create(JSContext *cx, Handle
     if (!obj)
         return NULL;
 
     if (!obj->asScope().setEnclosingScope(cx, enclosing))
         return NULL;
 
     obj->setReservedSlot(DEPTH_SLOT, PrivateUint32Value(depth));
 
-    JSObject *thisp = proto->thisObject(cx);
+    JSObject *thisp = JSObject::thisObject(cx, proto);
     if (!thisp)
         return NULL;
 
     obj->setFixedSlot(THIS_SLOT, ObjectValue(*thisp));
 
     return &obj->asWith();
 }
 
 static JSBool
 with_LookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
                    MutableHandleObject objp, MutableHandleShape propp)
 {
-    return obj->asWith().object().lookupGeneric(cx, id, objp, propp);
+    RootedObject actual(cx, &obj->asWith().object());
+    return JSObject::lookupGeneric(cx, actual, id, objp, propp);
 }
 
 static JSBool
 with_LookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
                     MutableHandleObject objp, MutableHandleShape propp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return with_LookupGeneric(cx, obj, id, objp, propp);
@@ -329,17 +330,18 @@ with_LookupSpecial(JSContext *cx, Handle
     Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return with_LookupGeneric(cx, obj, id, objp, propp);
 }
 
 static JSBool
 with_GetGeneric(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
                 MutableHandleValue vp)
 {
-    return obj->asWith().object().getGeneric(cx, id, vp);
+    RootedObject actual(cx, &obj->asWith().object());
+    return JSObject::getGeneric(cx, actual, actual, id, vp);
 }
 
 static JSBool
 with_GetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandlePropertyName name,
                  MutableHandleValue vp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return with_GetGeneric(cx, obj, receiver, id, vp);
@@ -363,117 +365,129 @@ with_GetSpecial(JSContext *cx, HandleObj
     return with_GetGeneric(cx, obj, receiver, id, vp);
 }
 
 static JSBool
 with_SetGeneric(JSContext *cx, HandleObject obj, HandleId id,
                 MutableHandleValue vp, JSBool strict)
 {
     Rooted<JSObject*> actual(cx, &obj->asWith().object());
-    return actual->setGeneric(cx, actual, id, vp, strict);
+    return JSObject::setGeneric(cx, actual, actual, id, vp, strict);
 }
 
 static JSBool
 with_SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
                  MutableHandleValue vp, JSBool strict)
 {
     Rooted<JSObject*> actual(cx, &obj->asWith().object());
-    return actual->setProperty(cx, actual, name, vp, strict);
+    return JSObject::setProperty(cx, actual, actual, name, vp, strict);
 }
 
 static JSBool
 with_SetElement(JSContext *cx, HandleObject obj, uint32_t index,
                 MutableHandleValue vp, JSBool strict)
 {
     Rooted<JSObject*> actual(cx, &obj->asWith().object());
-    return actual->setElement(cx, actual, index, vp, strict);
+    return JSObject::setElement(cx, actual, actual, index, vp, strict);
 }
 
 static JSBool
 with_SetSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
                 MutableHandleValue vp, JSBool strict)
 {
     Rooted<JSObject*> actual(cx, &obj->asWith().object());
-    return actual->setSpecial(cx, actual, sid, vp, strict);
+    return JSObject::setSpecial(cx, actual, actual, sid, vp, strict);
 }
 
 static JSBool
 with_GetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
-    return obj->asWith().object().getGenericAttributes(cx, id, attrsp);
+    RootedObject actual(cx, &obj->asWith().object());
+    return JSObject::getGenericAttributes(cx, actual, id, attrsp);
 }
 
 static JSBool
 with_GetPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name, unsigned *attrsp)
 {
-    return obj->asWith().object().getPropertyAttributes(cx, name, attrsp);
+    RootedObject actual(cx, &obj->asWith().object());
+    return JSObject::getPropertyAttributes(cx, actual, name, attrsp);
 }
 
 static JSBool
 with_GetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp)
 {
-    return obj->asWith().object().getElementAttributes(cx, index, attrsp);
+    RootedObject actual(cx, &obj->asWith().object());
+    return JSObject::getElementAttributes(cx, actual, index, attrsp);
 }
 
 static JSBool
 with_GetSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid, unsigned *attrsp)
 {
-    return obj->asWith().object().getSpecialAttributes(cx, sid, attrsp);
+    RootedObject actual(cx, &obj->asWith().object());
+    return JSObject::getSpecialAttributes(cx, actual, sid, attrsp);
 }
 
 static JSBool
 with_SetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
-    return obj->asWith().object().setGenericAttributes(cx, id, attrsp);
+    RootedObject actual(cx, &obj->asWith().object());
+    return JSObject::setGenericAttributes(cx, actual, id, attrsp);
 }
 
 static JSBool
 with_SetPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name, unsigned *attrsp)
 {
-    return obj->asWith().object().setPropertyAttributes(cx, name, attrsp);
+    RootedObject actual(cx, &obj->asWith().object());
+    return JSObject::setPropertyAttributes(cx, actual, name, attrsp);
 }
 
 static JSBool
 with_SetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp)
 {
-    return obj->asWith().object().setElementAttributes(cx, index, attrsp);
+    RootedObject actual(cx, &obj->asWith().object());
+    return JSObject::setElementAttributes(cx, actual, index, attrsp);
 }
 
 static JSBool
 with_SetSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid, unsigned *attrsp)
 {
-    return obj->asWith().object().setSpecialAttributes(cx, sid, attrsp);
+    RootedObject actual(cx, &obj->asWith().object());
+    return JSObject::setSpecialAttributes(cx, actual, sid, attrsp);
 }
 
 static JSBool
 with_DeleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
                     MutableHandleValue rval, JSBool strict)
 {
-    return obj->asWith().object().deleteProperty(cx, name, rval, strict);
+    RootedObject actual(cx, &obj->asWith().object());
+    return JSObject::deleteProperty(cx, actual, name, rval, strict);
 }
 
 static JSBool
 with_DeleteElement(JSContext *cx, HandleObject obj, uint32_t index,
                    MutableHandleValue rval, JSBool strict)
 {
-    return obj->asWith().object().deleteElement(cx, index, rval, strict);
+    RootedObject actual(cx, &obj->asWith().object());
+    return JSObject::deleteElement(cx, actual, index, rval, strict);
 }
 
 static JSBool
 with_DeleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
                    MutableHandleValue rval, JSBool strict)
 {
-    return obj->asWith().object().deleteSpecial(cx, sid, rval, strict);
+    RootedObject actual(cx, &obj->asWith().object());
+    return JSObject::deleteSpecial(cx, actual, sid, rval, strict);
 }
 
 static JSBool
 with_Enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
                Value *statep, jsid *idp)
 {
-    return obj->asWith().object().enumerate(cx, enum_op, statep, idp);
+    RootedObject actual(cx, &obj->asWith().object());
+    return JSObject::enumerate(cx, actual, enum_op, statep, idp);
 }
 
 static JSType
 with_TypeOf(JSContext *cx, HandleObject obj)
 {
     return JSTYPE_OBJECT;
 }
 
@@ -1286,17 +1300,17 @@ class DebugScopeProxy : public BaseProxy
             *vp = ObjectValue(*maybeArgsObj);
             return true;
         }
 
         if (handleUnaliasedAccess(cx, debugScope, scope, id, GET, vp))
             return true;
 
         RootedValue value(cx);
-        if (!scope->getGeneric(cx, scope, id, &value))
+        if (!JSObject::getGeneric(cx, scope, scope, id, &value))
             return false;
 
         *vp = value;
         return true;
     }
 
     bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid idArg, bool strict,
                      Value *vp) MOZ_OVERRIDE
@@ -1304,17 +1318,17 @@ class DebugScopeProxy : public BaseProxy
         Rooted<DebugScopeObject*> debugScope(cx, &proxy->asDebugScope());
         Rooted<ScopeObject*> scope(cx, &proxy->asDebugScope().scope());
         RootedId id(cx, idArg);
 
         if (handleUnaliasedAccess(cx, debugScope, scope, id, SET, vp))
             return true;
 
         RootedValue value(cx, *vp);
-        if (!scope->setGeneric(cx, scope, id, &value, strict))
+        if (!JSObject::setGeneric(cx, scope, scope, id, &value, strict))
             return false;
 
         *vp = value;
         return true;
     }
 
     bool defineProperty(JSContext *cx, JSObject *proxy, jsid idArg, PropertyDescriptor *desc) MOZ_OVERRIDE
     {