Make JSObject::doSomethingToThisObject methods static, bug 782646. r=terrence
authorBrian Hackett <bhackett1024@gmail.com>
Tue, 21 Aug 2012 13:13:28 -0600
changeset 102957 bf1a005f1e61d7e3861b644b5db1953d487792a0
parent 102956 987f760ee458f2587ba1fc0697cad8c0c5ebe9cb
child 102958 a8d115b3b7e11865bae4b7502d76c9f038a13f66
push id23317
push userryanvm@gmail.com
push dateWed, 22 Aug 2012 02:05:02 +0000
treeherdermozilla-central@abc17059522b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs782646
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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
     {