Back out e4c82a6b298c, 036194408a50, 39acc9f51df8 (bug 714647 and followups) because of test_finalizer.js crashes in Linux64 PGO builds
authorMatt Brubeck <mbrubeck@mozilla.com>
Thu, 12 Apr 2012 22:07:43 -0700
changeset 95324 906aa73122d98b423452bdca8d93d31a92a77525
parent 95323 3e7aa45f40f7d7e8fc232dd07669082b2bd27a7c
child 95325 9c81a70ddb1c59dbf4a13df868b2cb0819ac58b1
child 95340 622e0d1cc986f7342cacaf0ad9961d5fca88dddb
push id160
push userlsblakk@mozilla.com
push dateFri, 13 Jul 2012 18:18:57 +0000
treeherdermozilla-release@228ba1a111fc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs714647
milestone14.0a1
backs oute4c82a6b298c57415fc574fc79151a31acafc4a1
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
Back out e4c82a6b298c, 036194408a50, 39acc9f51df8 (bug 714647 and followups) because of test_finalizer.js crashes in Linux64 PGO builds
js/public/Utility.h
js/src/Makefile.in
js/src/builtin/RegExp.cpp
js/src/configure.in
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeEmitter-inl.h
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/FoldConstants.cpp
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/frontend/TokenStream.cpp
js/src/frontend/TokenStream.h
js/src/gc/Barrier-inl.h
js/src/gc/Root.h
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/jscntxt.cpp
js/src/jscntxt.h
js/src/jscntxtinlines.h
js/src/jsdate.cpp
js/src/jsdbgapi.cpp
js/src/jsexn.cpp
js/src/jsfriendapi.h
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsfuninlines.h
js/src/jsgc.cpp
js/src/jsinfer.cpp
js/src/jsinferinlines.h
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jsinterpinlines.h
js/src/jsiter.cpp
js/src/jsiter.h
js/src/jsmath.cpp
js/src/jsnum.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/json.cpp
js/src/jsonparser.cpp
js/src/jspropertycache.cpp
js/src/jsproxy.cpp
js/src/jsprvtd.h
js/src/jspubtd.h
js/src/jsreflect.cpp
js/src/jsscope.cpp
js/src/jsscope.h
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsstr.cpp
js/src/jsstr.h
js/src/jsstrinlines.h
js/src/jstypedarray.cpp
js/src/jswrapper.cpp
js/src/jsxml.cpp
js/src/jsxml.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/shell/js.cpp
js/src/vm/ArgumentsObject.cpp
js/src/vm/ArgumentsObject.h
js/src/vm/Debugger.cpp
js/src/vm/ObjectImpl.cpp
js/src/vm/ObjectImpl.h
js/src/vm/RegExpObject.cpp
js/src/vm/RegExpObject.h
js/src/vm/ScopeObject-inl.h
js/src/vm/ScopeObject.cpp
js/src/vm/ScopeObject.h
js/src/vm/String-inl.h
js/src/vm/String.cpp
js/src/vm/String.h
js/src/vm/StringObject-inl.h
js/src/vm/StringObject.h
--- a/js/public/Utility.h
+++ b/js/public/Utility.h
@@ -899,50 +899,16 @@ class ReentrancyGuard
 JS_ALWAYS_INLINE size_t
 RoundUpPow2(size_t x)
 {
     return size_t(1) << JS_CEILING_LOG2W(x);
 }
 
 } /* namespace js */
 
-namespace JS {
-
-/*
- * Methods for poisoning GC heap pointer words and checking for poisoned words.
- * These are in this file for use in Value methods and so forth.
- *
- * If the moving GC hazard analysis is in use and detects a non-rooted stack
- * pointer to a GC thing, one byte of that pointer is poisoned to refer to an
- * invalid location. For both 32 bit and 64 bit systems, the fourth byte of the
- * pointer is overwritten, to reduce the likelihood of accidentally changing
- * a live integer value.
- */
-
-inline void PoisonPtr(uintptr_t *v)
-{
-#if defined(JSGC_ROOT_ANALYSIS) && defined(DEBUG)
-    uint8_t *ptr = (uint8_t *) v + 3;
-    *ptr = JS_FREE_PATTERN;
-#endif
-}
-
-template <typename T>
-inline bool IsPoisonedPtr(T *v)
-{
-#if defined(JSGC_ROOT_ANALYSIS) && defined(DEBUG)
-    uint32_t mask = uintptr_t(v) & 0xff000000;
-    return mask == uint32_t(JS_FREE_PATTERN << 24);
-#else
-    return false;
-#endif
-}
-
-}
-
 #endif /* defined(__cplusplus) */
 
 /*
  * This is SpiderMonkey's equivalent to |nsMallocSizeOfFun|.
  */
 typedef size_t(*JSMallocSizeOfFun)(const void *p);
 
 /* sixgill annotation defines */
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -221,17 +221,16 @@ EXPORTS_NAMESPACES += ds gc
 
 EXPORTS_ds = \
 		BitArray.h \
 		$(NULL)
 
 EXPORTS_gc = \
 		Statistics.h \
 		Barrier.h \
-		Root.h \
 		$(NULL)
 
 ######################################################
 # BEGIN include exported headers from the JS engine
 #
 #       Ultimately, after cleansing INSTALLED_HEADERS,
 #       these will be the ONLY headers exported by
 #       the js engine
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -49,25 +49,25 @@
 #include "vm/RegExpStatics-inl.h"
 
 using namespace js;
 using namespace js::types;
 
 class RegExpMatchBuilder
 {
     JSContext   * const cx;
-    RootedVarObject array;
+    JSObject    * const array;
 
     bool setProperty(JSAtom *name, Value v) {
         return !!js_DefineProperty(cx, array, ATOM_TO_JSID(name), &v,
                                    JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE);
     }
 
   public:
-    RegExpMatchBuilder(JSContext *cx, JSObject *array) : cx(cx), array(cx, array) {}
+    RegExpMatchBuilder(JSContext *cx, JSObject *array) : cx(cx), array(array) {}
 
     bool append(uint32_t index, Value v) {
         JS_ASSERT(!array->getOps()->getElement);
         return !!js_DefineElement(cx, array, index, &v, JS_PropertyStub, JS_StrictPropertyStub,
                                   JSPROP_ENUMERATE);
     }
 
     bool setIndex(int index) {
@@ -76,31 +76,29 @@ class RegExpMatchBuilder
 
     bool setInput(JSString *str) {
         JS_ASSERT(str);
         return setProperty(cx->runtime->atomState.inputAtom, StringValue(str));
     }
 };
 
 static bool
-CreateRegExpMatchResult(JSContext *cx, JSString *input_, const jschar *chars, size_t length,
+CreateRegExpMatchResult(JSContext *cx, JSString *input, const jschar *chars, size_t length,
                         MatchPairs *matchPairs, Value *rval)
 {
-    RootedVarString input(cx, input_);
-
     /*
      * Create the (slow) result array for a match.
      *
      * Array contents:
      *  0:              matched string
      *  1..pairCount-1: paren matches
      *  input:          input string
      *  index:          start index for the match
      */
-    RootedVarObject array(cx, NewSlowEmptyArray(cx));
+    JSObject *array = NewSlowEmptyArray(cx);
     if (!array)
         return false;
 
     if (!input) {
         input = js_NewStringCopyN(cx, chars, length);
         if (!input)
             return false;
     }
@@ -222,18 +220,17 @@ EscapeNakedForwardSlashes(JSContext *cx,
  *  _ => pattern := ToString(pattern) if defined(pattern) else ''
  *       flags := ToString(flags) if defined(flags) else ''
  */
 static bool
 CompileRegExpObject(JSContext *cx, RegExpObjectBuilder &builder, CallArgs args)
 {
     if (args.length() == 0) {
         RegExpStatics *res = cx->regExpStatics();
-        RegExpObject *reobj = builder.build(RootedVarAtom(cx, cx->runtime->emptyString),
-                                            res->getFlags());
+        RegExpObject *reobj = builder.build(cx->runtime->emptyString, res->getFlags());
         if (!reobj)
             return false;
         args.rval() = ObjectValue(*reobj);
         return true;
     }
 
     Value sourceValue = args[0];
 
@@ -270,17 +267,17 @@ CompileRegExpObject(JSContext *cx, RegEx
         /*
          * 'toSource' is a permanent read-only property, so this is equivalent
          * to executing RegExpObject::getSource on the unwrapped object.
          */
         Value v;
         if (!sourceObj.getProperty(cx, cx->runtime->atomState.sourceAtom, &v))
             return false;
 
-        RegExpObject *reobj = builder.build(RootedVarAtom(cx, &v.toString()->asAtom()), flags);
+        RegExpObject *reobj = builder.build(&v.toString()->asAtom(), flags);
         if (!reobj)
             return false;
 
         args.rval() = ObjectValue(*reobj);
         return true;
     }
 
     JSAtom *source;
@@ -302,17 +299,17 @@ CompileRegExpObject(JSContext *cx, RegEx
         JSString *flagStr = ToString(cx, args[1]);
         if (!flagStr)
             return false;
         args[1].setString(flagStr);
         if (!ParseRegExpFlags(cx, flagStr, &flags))
             return false;
     }
 
-    RootedVarAtom escapedSourceStr(cx, EscapeNakedForwardSlashes(cx, source));
+    JSAtom *escapedSourceStr = EscapeNakedForwardSlashes(cx, source);
     if (!escapedSourceStr)
         return false;
 
     if (!js::detail::RegExpCode::checkSyntax(cx, NULL, escapedSourceStr))
         return false;
 
     RegExpStatics *res = cx->regExpStatics();
     RegExpObject *reobj = builder.build(escapedSourceStr, RegExpFlag(flags | res->getFlags()));
@@ -480,32 +477,32 @@ static JSPropertySpec regexp_static_prop
     {0,0,0,0,0}
 };
 
 JSObject *
 js_InitRegExpClass(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isNative());
 
-    RootedVar<GlobalObject*> global(cx, &obj->asGlobal());
+    GlobalObject *global = &obj->asGlobal();
 
-    RootedVarObject proto(cx, global->createBlankPrototype(cx, &RegExpClass));
+    JSObject *proto = global->createBlankPrototype(cx, &RegExpClass);
     if (!proto)
         return NULL;
     proto->setPrivate(NULL);
 
-    RegExpObjectBuilder builder(cx, &proto->asRegExp());
-    if (!builder.build(RootedVarAtom(cx, cx->runtime->emptyString), RegExpFlag(0)))
+    RegExpObject *reproto = &proto->asRegExp();
+    RegExpObjectBuilder builder(cx, reproto);
+    if (!builder.build(cx->runtime->emptyString, RegExpFlag(0)))
         return NULL;
 
     if (!DefinePropertiesAndBrand(cx, proto, NULL, regexp_methods))
         return NULL;
 
-    RootedVarFunction ctor(cx);
-    ctor = global->createConstructor(cx, regexp_construct, CLASS_ATOM(cx, RegExp), 2);
+    JSFunction *ctor = global->createConstructor(cx, regexp_construct, CLASS_ATOM(cx, RegExp), 2);
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, proto))
         return NULL;
 
     /* Add static properties to the RegExp constructor. */
     if (!JS_DefineProperties(cx, ctor, regexp_static_props))
@@ -573,24 +570,24 @@ ExecuteRegExp(JSContext *cx, Native nati
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
     bool ok;
     JSObject *obj = NonGenericMethodGuard(cx, args, native, &RegExpClass, &ok);
     if (!obj)
         return ok;
 
-    RootedVar<RegExpObject*> reobj(cx, &obj->asRegExp());
+    RegExpObject &reobj = obj->asRegExp();
 
     RegExpGuard re;
-    if (StartsWithGreedyStar(reobj->getSource())) {
-        if (!GetSharedForGreedyStar(cx, reobj->getSource(), reobj->getFlags(), &re))
+    if (StartsWithGreedyStar(reobj.getSource())) {
+        if (!GetSharedForGreedyStar(cx, reobj.getSource(), reobj.getFlags(), &re))
             return false;
     } else {
-        if (!reobj->getShared(cx, &re))
+        if (!reobj.getShared(cx, &re))
             return false;
     }
 
     RegExpStatics *res = cx->regExpStatics();
 
     /* Step 2. */
     JSString *input = ToString(cx, (args.length() > 0) ? args[0] : UndefinedValue());
     if (!input)
@@ -599,48 +596,48 @@ ExecuteRegExp(JSContext *cx, Native nati
     /* Step 3. */
     JSLinearString *linearInput = input->ensureLinear(cx);
     if (!linearInput)
         return false;
     const jschar *chars = linearInput->chars();
     size_t length = input->length();
 
     /* Step 4. */
-    const Value &lastIndex = reobj->getLastIndex();
+    const Value &lastIndex = reobj.getLastIndex();
 
     /* Step 5. */
     double i;
     if (!ToInteger(cx, lastIndex, &i))
         return false;
 
     /* Steps 6-7 (with sticky extension). */
     if (!re->global() && !re->sticky())
         i = 0;
 
     /* Step 9a. */
     if (i < 0 || i > length) {
-        reobj->zeroLastIndex();
+        reobj.zeroLastIndex();
         args.rval() = NullValue();
         return true;
     }
 
     /* Steps 8-21. */
     RegExpExecType execType = (native == regexp_test) ? RegExpTest : RegExpExec;
     size_t lastIndexInt(i);
     if (!ExecuteRegExp(cx, res, *re, linearInput, chars, length, &lastIndexInt, execType,
                        &args.rval())) {
         return false;
     }
 
     /* Step 11 (with sticky extension). */
     if (re->global() || (!args.rval().isNull() && re->sticky())) {
         if (args.rval().isNull())
-            reobj->zeroLastIndex();
+            reobj.zeroLastIndex();
         else
-            reobj->setLastIndex(lastIndexInt);
+            reobj.setLastIndex(lastIndexInt);
     }
 
     return true;
 }
 
 /* ES5 15.10.6.2. */
 JSBool
 js::regexp_exec(JSContext *cx, unsigned argc, Value *vp)
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -4150,17 +4150,17 @@ MOZ_ARG_ENABLE_BOOL(gcgenerational,
     JSGC_GENERATIONAL= )
 if test -n "$JSGC_GENERATIONAL"; then
     AC_DEFINE(JSGC_GENERATIONAL)
 fi
 
 dnl ========================================================
 dnl = Perform moving GC stack rooting analysis
 dnl ========================================================
-MOZ_ARG_ENABLE_BOOL(root-analysis,
+MOZ_ARG_ENABLE_BOOL(gcrootanalysis,
 [  --enable-root-analysis Enable moving GC stack root analysis],
     JSGC_ROOT_ANALYSIS=1,
     JSGC_ROOT_ANALYSIS= )
 if test -n "$JSGC_ROOT_ANALYSIS"; then
     AC_DEFINE(JSGC_ROOT_ANALYSIS)
 fi
 
 dnl ========================================================
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -48,21 +48,19 @@
 #include "vm/GlobalObject.h"
 
 #include "jsinferinlines.h"
 
 using namespace js;
 using namespace js::frontend;
 
 bool
-DefineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript* script)
+DefineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript *script)
 {
-    Root<JSScript*> root(cx, &script);
-
-    HandleObject globalObj = globalScope.globalObj;
+    JSObject *globalObj = globalScope.globalObj;
 
     /* Define and update global properties. */
     for (size_t i = 0; i < globalScope.defs.length(); i++) {
         GlobalScope::GlobalDef &def = globalScope.defs[i];
 
         /* Names that could be resolved ahead of time can be skipped. */
         if (!def.atom)
             continue;
@@ -162,16 +160,17 @@ frontend::CompileScript(JSContext *cx, J
                         uint32_t tcflags,
                         const jschar *chars, size_t length,
                         const char *filename, unsigned lineno, JSVersion version,
                         JSString *source /* = NULL */,
                         unsigned staticLevel /* = 0 */)
 {
     TokenKind tt;
     ParseNode *pn;
+    JSScript *script;
     bool inDirectivePrologue;
 
     JS_ASSERT(!(tcflags & ~(TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL | TCF_COMPILE_FOR_EVAL
                             | TCF_NEED_SCRIPT_GLOBAL)));
 
     /*
      * The scripted callerFrame can only be given for compile-and-go scripts
      * and non-zero static level requires callerFrame.
@@ -195,17 +194,18 @@ frontend::CompileScript(JSContext *cx, J
     // We can specialize a bit for the given scope chain if that scope chain is the global object.
     JSObject *globalObj = scopeChain && scopeChain == &scopeChain->global()
                           ? &scopeChain->global()
                           : NULL;
 
     JS_ASSERT_IF(globalObj, globalObj->isNative());
     JS_ASSERT_IF(globalObj, JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(globalObj->getClass()));
 
-    RootedVar<JSScript*> script(cx);
+    /* Null script early in case of error, to reduce our code footprint. */
+    script = NULL;
 
     GlobalScope globalScope(cx, globalObj, &bce);
     bce.flags |= tcflags;
     bce.setScopeChain(scopeChain);
     bce.globalScope = &globalScope;
     if (!SetStaticLevel(&bce, staticLevel))
         goto out;
 
--- a/js/src/frontend/BytecodeEmitter-inl.h
+++ b/js/src/frontend/BytecodeEmitter-inl.h
@@ -44,19 +44,18 @@
 #include "frontend/ParseNode.h"
 #include "frontend/TokenStream.h"
 
 namespace js {
 
 inline
 TreeContext::TreeContext(Parser *prs)
   : flags(0), bodyid(0), blockidGen(0), parenDepth(0), yieldCount(0),
-    topStmt(NULL), topScopeStmt(NULL), blockChain(prs->context), blockNode(NULL),
-    decls(prs->context), parser(prs), yieldNode(NULL), argumentsNode(NULL),
-    fun_(prs->context), scopeChain_(prs->context),
+    topStmt(NULL), topScopeStmt(NULL), blockChain(NULL), blockNode(NULL),
+    decls(prs->context), parser(prs), yieldNode(NULL), argumentsNode(NULL), scopeChain_(NULL),
     lexdeps(prs->context), parent(prs->tc), staticLevel(0), funbox(NULL), functionList(NULL),
     innermostWith(NULL), bindings(prs->context), bindingsRoot(prs->context, &bindings),
     funcStmts(NULL)
 {
     prs->tc = this;
 }
 
 /*
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -418,17 +418,17 @@ frontend::GenerateBlockId(TreeContext *t
 void
 frontend::PushStatement(TreeContext *tc, StmtInfo *stmt, StmtType type, ptrdiff_t top)
 {
     stmt->type = type;
     stmt->flags = 0;
     stmt->blockid = tc->blockid();
     SET_STATEMENT_TOP(stmt, top);
     stmt->label = NULL;
-    stmt->blockObj = NULL;
+    JS_ASSERT(!stmt->blockObj);
     stmt->down = tc->topStmt;
     tc->topStmt = stmt;
     if (STMT_LINKS_SCOPE(stmt)) {
         stmt->downScope = tc->topScopeStmt;
         tc->topScopeStmt = stmt;
     } else {
         stmt->downScope = NULL;
     }
@@ -1355,16 +1355,17 @@ BindGlobal(JSContext *cx, BytecodeEmitte
  * to update the special cases in EmitFor (for-in) and EmitAssignment (= and
  * op=, e.g. +=).
  */
 static JSBool
 BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
     Definition *dn;
     JSOp op;
+    JSAtom *atom;
     Definition::Kind dn_kind;
 
     JS_ASSERT(pn->isKind(PNK_NAME));
 
     /* Idempotency tests come first, since we may be called more than once. */
     if (pn->pn_dflags & PND_BOUND)
         return JS_TRUE;
 
@@ -1388,17 +1389,17 @@ BindNameToSlot(JSContext *cx, BytecodeEm
         dn = (Definition *) pn;
     }
 
     op = pn->getOp();
     if (op == JSOP_NOP)
         return JS_TRUE;
 
     JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
-    RootedVarAtom atom(cx, pn->pn_atom);
+    atom = pn->pn_atom;
     UpvarCookie cookie = dn->pn_cookie;
     dn_kind = dn->kind();
 
     /*
      * Turn attempts to mutate const-declared bindings into get ops (for
      * pre-increment and pre-decrement ops, our caller will have to emit
      * JSOP_POS, JSOP_ONE, and JSOP_ADD as well).
      *
@@ -2363,17 +2364,17 @@ EmitSwitch(JSContext *cx, BytecodeEmitte
     ptrdiff_t top, off, defaultOffset;
     ParseNode *pn2, *pn3, *pn4;
     uint32_t caseCount, tableLength;
     ParseNode **table;
     int32_t i, low, high;
     int noteIndex;
     size_t switchSize, tableSize;
     jsbytecode *pc, *savepc;
-    StmtInfo stmtInfo(cx);
+    StmtInfo stmtInfo;
 
     /* Try for most optimal, fall back if not dense ints, and per ECMAv2. */
     switchOp = JSOP_TABLESWITCH;
     ok = JS_TRUE;
     hasDefault = constPropagated = JS_FALSE;
     defaultOffset = -1;
 
     pn2 = pn->pn_right;
@@ -3976,17 +3977,17 @@ ParseNode::getConstantValue(JSContext *c
         types::FixArrayType(cx, obj);
         vp->setObject(*obj);
         return true;
       }
       case PNK_RC: {
         JS_ASSERT(isOp(JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST));
 
         gc::AllocKind kind = GuessObjectGCKind(pn_count);
-        RootedVarObject obj(cx, NewBuiltinClassInstance(cx, &ObjectClass, kind));
+        JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
         if (!obj)
             return false;
 
         for (ParseNode *pn = pn_head; pn; pn = pn->pn_next) {
             Value value;
             if (!pn->pn_right->getConstantValue(cx, strictChecks, &value))
                 return false;
 
@@ -4135,17 +4136,17 @@ EmitCatch(JSContext *cx, BytecodeEmitter
 
 /*
  * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr12127. See
  * the comment on EmitSwitch.
  */
 MOZ_NEVER_INLINE static bool
 EmitTry(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
-    StmtInfo stmtInfo(cx);
+    StmtInfo stmtInfo;
     ptrdiff_t catchJump = -1;
 
     /*
      * Push stmtInfo to track jumps-over-catches and gosubs-to-finally
      * for later fixup.
      *
      * When a finally block is active (STMT_FINALLY in our tree context),
      * non-local jumps (including jumps-over-catches) result in a GOSUB
@@ -4367,17 +4368,17 @@ EmitTry(JSContext *cx, BytecodeEmitter *
         return false;
 
     return true;
 }
 
 static bool
 EmitIf(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
-    StmtInfo stmtInfo(cx);
+    StmtInfo stmtInfo;
 
     /* Initialize so we can detect else-if chains and avoid recursion. */
     stmtInfo.type = STMT_IF;
     ptrdiff_t beq = -1;
     ptrdiff_t jmp = -1;
     ptrdiff_t noteIndex = -1;
 
   if_again:
@@ -4524,17 +4525,17 @@ EmitLet(JSContext *cx, BytecodeEmitter *
     for (uint32_t i = alreadyPushed; i < blockObjCount; ++i) {
         /* Tell the decompiler not to print the decl in the let head. */
         if (NewSrcNote(cx, bce, SRC_CONTINUE) < 0)
             return false;
         if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
             return false;
     }
 
-    StmtInfo stmtInfo(cx);
+    StmtInfo stmtInfo;
     PushBlockScope(bce, &stmtInfo, blockObj, bce->offset());
 
     if (!letNotes.update(cx, bce, bce->offset()))
         return false;
 
     ptrdiff_t declNote = NewSrcNote(cx, bce, SRC_DECL);
     if (declNote < 0)
         return false;
@@ -4650,17 +4651,17 @@ EmitXMLProcessingInstruction(JSContext *
  * the comment on EmitSwitch.
  */
 MOZ_NEVER_INLINE static bool
 EmitLexicalScope(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
     JS_ASSERT(pn->isKind(PNK_LEXICALSCOPE));
     JS_ASSERT(pn->getOp() == JSOP_LEAVEBLOCK);
 
-    StmtInfo stmtInfo(cx);
+    StmtInfo stmtInfo;
     ObjectBox *objbox = pn->pn_objbox;
     StaticBlockObject &blockObj = objbox->object->asStaticBlock();
     PushBlockScope(bce, &stmtInfo, blockObj, bce->offset());
 
     /*
      * For compound statements (i.e. { stmt-list }), the decompiler does not
      * emit curlies by default. However, if this stmt-list contains a let
      * declaration, this is semantically invalid so we need to add a srcnote to
@@ -4699,34 +4700,34 @@ EmitLexicalScope(JSContext *cx, Bytecode
     EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, blockObj.slotCount());
 
     return PopStatementBCE(cx, bce);
 }
 
 static bool
 EmitWith(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
-    StmtInfo stmtInfo(cx);
+    StmtInfo stmtInfo;
     if (!EmitTree(cx, bce, pn->pn_left))
         return false;
     PushStatement(bce, &stmtInfo, STMT_WITH, bce->offset());
     if (Emit1(cx, bce, JSOP_ENTERWITH) < 0)
         return false;
 
     if (!EmitTree(cx, bce, pn->pn_right))
         return false;
     if (Emit1(cx, bce, JSOP_LEAVEWITH) < 0)
         return false;
     return PopStatementBCE(cx, bce);
 }
 
 static bool
 EmitForIn(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
 {
-    StmtInfo stmtInfo(cx);
+    StmtInfo stmtInfo;
     PushStatement(bce, &stmtInfo, STMT_FOR_IN_LOOP, top);
 
     ParseNode *forHead = pn->pn_left;
     ParseNode *forBody = pn->pn_right;
 
     ParseNode *pn1 = forHead->pn_kid1;
     bool letDecl = pn1 && pn1->isKind(PNK_LEXICALSCOPE);
     JS_ASSERT_IF(letDecl, pn1->isLet());
@@ -4782,17 +4783,17 @@ EmitForIn(JSContext *cx, BytecodeEmitter
      * object depending on the loop variant (for-in, for-each-in, or
      * destructuring for-in).
      */
     JS_ASSERT(pn->isOp(JSOP_ITER));
     if (Emit2(cx, bce, JSOP_ITER, (uint8_t) pn->pn_iflags) < 0)
         return false;
 
     /* Enter the block before the loop body, after evaluating the obj. */
-    StmtInfo letStmt(cx);
+    StmtInfo letStmt;
     if (letDecl) {
         PushBlockScope(bce, &letStmt, *blockObj, bce->offset());
         letStmt.flags |= SIF_FOR_BLOCK;
         if (!EmitEnterBlock(cx, bce, pn1, JSOP_ENTERLET1))
             return false;
     }
 
     /* Annotate so the decompiler can find the loop-closing jump. */
@@ -4892,17 +4893,17 @@ EmitForIn(JSContext *cx, BytecodeEmitter
     }
 
     return true;
 }
 
 static bool
 EmitNormalFor(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
 {
-    StmtInfo stmtInfo(cx);
+    StmtInfo stmtInfo;
     PushStatement(bce, &stmtInfo, STMT_FOR_LOOP, top);
 
     ParseNode *forHead = pn->pn_left;
     ParseNode *forBody = pn->pn_right;
 
     /* C-style for (init; cond; update) ... loop. */
     JSOp op = JSOP_POP;
     ParseNode *pn3 = forHead->pn_kid1;
@@ -5049,17 +5050,17 @@ EmitFor(JSContext *cx, BytecodeEmitter *
 static JS_NEVER_INLINE bool
 EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
 #if JS_HAS_XML_SUPPORT
     if (pn->isArity(PN_NULLARY))
         return Emit1(cx, bce, JSOP_GETFUNNS) >= 0;
 #endif
 
-    RootedVarFunction fun(cx, pn->pn_funbox->function());
+    JSFunction *fun = pn->pn_funbox->function();
     JS_ASSERT(fun->isInterpreted());
     if (fun->script()) {
         /*
          * This second pass is needed to emit JSOP_NOP with a source note
          * for the already-emitted function definition prolog opcode. See
          * comments in the PNK_STATEMENTLIST case.
          */
         JS_ASSERT(pn->isOp(JSOP_NOP));
@@ -5172,17 +5173,17 @@ EmitDo(JSContext *cx, BytecodeEmitter *b
 
     /* Compile the loop body. */
     ptrdiff_t top = EmitLoopHead(cx, bce, pn->pn_left);
     if (top < 0)
         return false;
     if (!EmitLoopEntry(cx, bce, NULL))
         return false;
 
-    StmtInfo stmtInfo(cx);
+    StmtInfo stmtInfo;
     PushStatement(bce, &stmtInfo, STMT_DO_LOOP, top);
     if (!EmitTree(cx, bce, pn->pn_left))
         return false;
 
     /* Set loop and enclosing label update offsets, for continue. */
     ptrdiff_t off = bce->offset();
     StmtInfo *stmt = &stmtInfo;
     do {
@@ -5225,17 +5226,17 @@ EmitWhile(JSContext *cx, BytecodeEmitter
      *  i    test at the top                 test at the bottom
      *  =    ===============                 ==================
      *  0    ifeq-pass                       goto; ifne-fail
      *  1    ifeq-fail; goto; ifne-pass      goto; ifne-pass; ifne-fail
      *  2    2*(ifeq-fail; goto); ifeq-pass  goto; 2*ifne-pass; ifne-fail
      *  . . .
      *  N    N*(ifeq-fail; goto); ifeq-pass  goto; N*ifne-pass; ifne-fail
      */
-    StmtInfo stmtInfo(cx);
+    StmtInfo stmtInfo;
     PushStatement(bce, &stmtInfo, STMT_WHILE_LOOP, top);
 
     ptrdiff_t noteIndex = NewSrcNote(cx, bce, SRC_WHILE);
     if (noteIndex < 0)
         return false;
 
     ptrdiff_t jmp = EmitJump(cx, bce, JSOP_GOTO, 0);
     if (jmp < 0)
@@ -5363,17 +5364,17 @@ EmitStatementList(JSContext *cx, Bytecod
     ptrdiff_t noteIndex = -1;
     ptrdiff_t tmp = bce->offset();
     if (pn->pn_xflags & PNX_NEEDBRACES) {
         noteIndex = NewSrcNote2(cx, bce, SRC_BRACE, 0);
         if (noteIndex < 0 || Emit1(cx, bce, JSOP_NOP) < 0)
             return false;
     }
 
-    StmtInfo stmtInfo(cx);
+    StmtInfo stmtInfo;
     PushStatement(bce, &stmtInfo, STMT_BLOCK, top);
 
     ParseNode *pnchild = pn->pn_head;
     if (pn->pn_xflags & PNX_FUNCDEFS) {
         /*
          * This block contains top-level function definitions. To ensure
          * that we emit the bytecode defining them before the rest of code
          * in the block we use a separate pass over functions. During the
@@ -5844,17 +5845,17 @@ EmitLabel(JSContext *cx, BytecodeEmitter
     if (noteIndex < 0)
         return false;
 
     ptrdiff_t top = EmitJump(cx, bce, JSOP_LABEL, 0);
     if (top < 0)
         return false;
 
     /* Emit code for the labeled statement. */
-    StmtInfo stmtInfo(cx);
+    StmtInfo stmtInfo;
     PushStatement(bce, &stmtInfo, STMT_LABEL, bce->offset());
     stmtInfo.label = atom;
     if (!EmitTree(cx, bce, pn2))
         return false;
     if (!PopStatementBCE(cx, bce))
         return false;
 
     /* Patch the JSOP_LABEL offset. */
@@ -5868,17 +5869,17 @@ EmitLabel(JSContext *cx, BytecodeEmitter
 
     return true;
 }
 
 static bool
 EmitSyntheticStatements(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
 {
     JS_ASSERT(pn->isArity(PN_LIST));
-    StmtInfo stmtInfo(cx);
+    StmtInfo stmtInfo;
     PushStatement(bce, &stmtInfo, STMT_SEQ, top);
     for (ParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
         if (!EmitTree(cx, bce, pn2))
             return false;
     }
     return PopStatementBCE(cx, bce);
 }
 
@@ -5944,17 +5945,17 @@ EmitObject(JSContext *cx, BytecodeEmitte
     ptrdiff_t offset = bce->next() - bce->base();
     if (!EmitNewInit(cx, bce, JSProto_Object, pn))
         return false;
 
     /*
      * Try to construct the shape of the object as we go, so we can emit a
      * JSOP_NEWOBJECT with the final shape instead.
      */
-    RootedVarObject obj(cx);
+    JSObject *obj = NULL;
     if (bce->compileAndGo()) {
         gc::AllocKind kind = GuessObjectGCKind(pn->pn_count);
         obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
         if (!obj)
             return false;
     }
 
     for (ParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -49,18 +49,16 @@
 #include "jsopcode.h"
 #include "jsscript.h"
 #include "jsprvtd.h"
 #include "jspubtd.h"
 
 #include "frontend/Parser.h"
 #include "frontend/ParseMaps.h"
 
-#include "vm/ScopeObject.h"
-
 namespace js {
 
 typedef HashSet<JSAtom *> FuncStmtSet;
 
 /*
  * NB: If you add enumerators for scope statements, add them between STMT_WITH
  * and STMT_CATCH, or you will break the STMT_TYPE_IS_SCOPE macro. If you add
  * non-looping statement enumerators, add them before STMT_DO_LOOP or you will
@@ -133,22 +131,22 @@ STMT_TYPE_IN_RANGE(uint16_t type, StmtTy
 
 struct StmtInfo {
     uint16_t        type;           /* statement type */
     uint16_t        flags;          /* flags, see below */
     uint32_t        blockid;        /* for simplified dominance computation */
     ptrdiff_t       update;         /* loop update offset (top if none) */
     ptrdiff_t       breaks;         /* offset of last break in loop */
     ptrdiff_t       continues;      /* offset of last continue in loop */
-    RootedVarAtom   label;          /* name of LABEL */
-    RootedVar<StaticBlockObject *> blockObj; /* block scope object */
+    union {
+        JSAtom      *label;         /* name of LABEL */
+        StaticBlockObject *blockObj;/* block scope object */
+    };
     StmtInfo        *down;          /* info for enclosing statement */
     StmtInfo        *downScope;     /* next enclosing lexical scope */
-
-    StmtInfo(JSContext *cx) : label(cx), blockObj(cx) {}
 };
 
 #define SIF_SCOPE        0x0001     /* statement has its own lexical scope */
 #define SIF_BODY_BLOCK   0x0002     /* STMT_BLOCK type is a function body */
 #define SIF_FOR_BLOCK    0x0004     /* for (let ...) induced block scope */
 
 /*
  * To reuse space in StmtInfo, rename breaks and continues for use during
@@ -333,35 +331,36 @@ struct TreeContext {                /* t
     uint32_t        bodyid;         /* block number of program/function body */
     uint32_t        blockidGen;     /* preincremented block number generator */
     uint32_t        parenDepth;     /* nesting depth of parens that might turn out
                                        to be generator expressions */
     uint32_t        yieldCount;     /* number of |yield| tokens encountered at
                                        non-zero depth in current paren tree */
     StmtInfo        *topStmt;       /* top of statement info stack */
     StmtInfo        *topScopeStmt;  /* top lexical scope statement */
-    RootedVar<StaticBlockObject *> blockChain;
-                                    /* compile time block scope chain (NB: one
+    StaticBlockObject *blockChain;  /* compile block scope chain (NB: one
                                        deeper than the topScopeStmt/downScope
                                        chain when in head of let block/expr) */
     ParseNode       *blockNode;     /* parse node for a block with let declarations
                                        (block with its own lexical scope)  */
     AtomDecls       decls;          /* function, const, and var declarations */
     Parser          *parser;        /* ptr to common parsing and lexing data */
     ParseNode       *yieldNode;     /* parse node for a yield expression that might
                                        be an error if we turn out to be inside a
                                        generator expression */
     ParseNode       *argumentsNode; /* parse node for an arguments variable that
                                        might be an error if we turn out to be
                                        inside a generator expression */
 
   private:
-    RootedVarFunction fun_;         /* function to store argument and variable
+    union {
+        JSFunction  *fun_;          /* function to store argument and variable
                                        names when flags & TCF_IN_FUNCTION */
-    RootedVarObject   scopeChain_;  /* scope chain object for the script */
+        JSObject    *scopeChain_;   /* scope chain object for the script */
+    };
 
   public:
     JSFunction *fun() const {
         JS_ASSERT(inFunction());
         return fun_;
     }
     void setFunction(JSFunction *fun) {
         JS_ASSERT(inFunction());
@@ -540,51 +539,43 @@ class GCConstList {
     GCConstList(JSContext *cx) : list(cx) {}
     bool append(Value v) { return list.append(v); }
     size_t length() const { return list.length(); }
     void finish(JSConstArray *array);
 };
 
 struct GlobalScope {
     GlobalScope(JSContext *cx, JSObject *globalObj, BytecodeEmitter *bce)
-      : globalObj(cx, globalObj), bce(bce), defs(cx), names(cx),
-        defsRoot(cx, &defs), namesRoot(cx, &names)
+      : globalObj(globalObj), bce(bce), defs(cx), names(cx)
     { }
 
     struct GlobalDef {
         JSAtom        *atom;        // If non-NULL, specifies the property name to add.
         FunctionBox   *funbox;      // If non-NULL, function value for the property.
                                     // This value is only set/used if atom is non-NULL.
         uint32_t      knownSlot;    // If atom is NULL, this is the known shape slot.
 
         GlobalDef() { }
         GlobalDef(uint32_t knownSlot) : atom(NULL), knownSlot(knownSlot) { }
         GlobalDef(JSAtom *atom, FunctionBox *box) : atom(atom), funbox(box) { }
     };
 
-    RootedVarObject globalObj;
+    JSObject        *globalObj;
     BytecodeEmitter *bce;
 
     /*
      * This is the table of global names encountered during parsing. Each
      * global name appears in the list only once, and the |names| table
      * maps back into |defs| for fast lookup.
      *
      * A definition may either specify an existing global property, or a new
      * one that must be added after compilation succeeds.
      */
     Vector<GlobalDef, 16> defs;
     AtomIndexMap      names;
-
-    /*
-     * Protect the inline elements within defs/names from being clobbered by
-     * root analysis. The atoms in this structure must be separately rooted.
-     */
-    JS::SkipRoot      defsRoot;
-    JS::SkipRoot      namesRoot;
 };
 
 struct BytecodeEmitter : public TreeContext
 {
     struct {
         jsbytecode  *base;          /* base of JS bytecode vector */
         jsbytecode  *limit;         /* one byte beyond end of bytecode */
         jsbytecode  *next;          /* pointer to next free bytecode */
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -225,18 +225,18 @@ FoldBinaryNumeric(JSContext *cx, JSOp op
 
 static JSBool
 FoldXMLConstants(JSContext *cx, ParseNode *pn, TreeContext *tc)
 {
     JS_ASSERT(pn->isArity(PN_LIST));
     ParseNodeKind kind = pn->getKind();
     ParseNode **pnp = &pn->pn_head;
     ParseNode *pn1 = *pnp;
-    RootedVarString accum(cx);
-    RootedVarString str(cx);
+    JSString *accum = NULL;
+    JSString *str = NULL;
     if ((pn->pn_xflags & PNX_CANTFOLD) == 0) {
         if (kind == PNK_XMLETAGO)
             accum = cx->runtime->atomState.etagoAtom;
         else if (kind == PNK_XMLSTAGO || kind == PNK_XMLPTAGC)
             accum = cx->runtime->atomState.stagoAtom;
     }
 
     /*
@@ -740,23 +740,25 @@ js::FoldConstants(JSContext *cx, ParseNo
             pn->setOp(JSOP_STRING);
             pn->setArity(PN_NULLARY);
             break;
         }
 
         /* Handle a binary string concatenation. */
         JS_ASSERT(pn->isArity(PN_BINARY));
         if (pn1->isKind(PNK_STRING) || pn2->isKind(PNK_STRING)) {
+            JSString *left, *right, *str;
+
             if (!FoldType(cx, !pn1->isKind(PNK_STRING) ? pn1 : pn2, PNK_STRING))
                 return false;
             if (!pn1->isKind(PNK_STRING) || !pn2->isKind(PNK_STRING))
                 return true;
-            RootedVarString left(cx, pn1->pn_atom);
-            RootedVarString right(cx, pn2->pn_atom);
-            RootedVarString str(cx, js_ConcatStrings(cx, left, right));
+            left = pn1->pn_atom;
+            right = pn2->pn_atom;
+            str = js_ConcatStrings(cx, left, right);
             if (!str)
                 return false;
             pn->pn_atom = js_AtomizeString(cx, str);
             if (!pn->pn_atom)
                 return false;
             pn->setKind(PNK_STRING);
             pn->setOp(JSOP_STRING);
             pn->setArity(PN_NULLARY);
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -169,18 +169,16 @@ Parser::setPrincipals(JSPrincipals *prin
     originPrincipals = originPrin;
     if (originPrincipals)
         JS_HoldPrincipals(originPrincipals);
 }
 
 ObjectBox *
 Parser::newObjectBox(JSObject *obj)
 {
-    JS_ASSERT(obj && !IsPoisonedPtr(obj));
-
     /*
      * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
      * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
      * arenas containing the entries must be alive until we are done with
      * scanning, parsing and code generation for the whole script or top-level
      * function.
      */
     ObjectBox *objbox = context->tempLifoAlloc().new_<ObjectBox>();
@@ -194,17 +192,17 @@ Parser::newObjectBox(JSObject *obj)
     objbox->object = obj;
     objbox->isFunctionBox = false;
     return objbox;
 }
 
 FunctionBox *
 Parser::newFunctionBox(JSObject *obj, ParseNode *fn, TreeContext *tc)
 {
-    JS_ASSERT(obj && !IsPoisonedPtr(obj));
+    JS_ASSERT(obj);
     JS_ASSERT(obj->isFunction());
 
     /*
      * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
      * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
      * arenas containing the entries must be alive until we are done with
      * scanning, parsing and code generation for the whole script or top-level
      * function.
@@ -580,30 +578,30 @@ CheckStrictParameters(JSContext *cx, Tre
 }
 
 static bool
 BindLocalVariable(JSContext *cx, TreeContext *tc, ParseNode *pn, BindingKind kind)
 {
     JS_ASSERT(kind == VARIABLE || kind == CONSTANT);
 
     unsigned index = tc->bindings.numVars();
-    if (!tc->bindings.add(cx, RootedVarAtom(cx, pn->pn_atom), kind))
+    if (!tc->bindings.add(cx, pn->pn_atom, kind))
         return false;
 
     pn->pn_cookie.set(tc->staticLevel, index);
     pn->pn_dflags |= PND_BOUND;
     return true;
 }
 
 ParseNode *
 Parser::functionBody(FunctionBodyType type)
 {
     JS_ASSERT(tc->inFunction());
 
-    StmtInfo stmtInfo(context);
+    StmtInfo stmtInfo;
     PushStatement(tc, &stmtInfo, STMT_BLOCK, -1);
     stmtInfo.flags = SIF_BODY_BLOCK;
 
     unsigned oldflags = tc->flags;
     tc->flags &= ~(TCF_RETURN_EXPR | TCF_RETURN_VOID);
 
     ParseNode *pn;
     if (type == StatementListBody) {
@@ -643,17 +641,17 @@ Parser::functionBody(FunctionBodyType ty
 
     /*
      * Check CheckStrictParameters before arguments logic below adds
      * 'arguments' to bindings.
      */
     if (!CheckStrictParameters(context, tc))
         return NULL;
 
-    RootedVar<PropertyName*> const arguments(context, context->runtime->atomState.argumentsAtom);
+    PropertyName * const arguments = context->runtime->atomState.argumentsAtom;
 
     /*
      * Non-top-level functions use JSOP_DEFFUN which is a dynamic scope
      * operation which means it aliases any bindings with the same name.
      * Due to the implicit declaration mechanism (below), 'arguments' will not
      * have decls and, even if it did, they will not be noted as closed in the
      * emitter. Thus, in the corner case of function-statement-overridding-
      * arguments, flag the whole scope as dynamic.
@@ -1351,17 +1349,17 @@ Parser::functionArguments(TreeContext &f
                 }
                 list->append(item);
                 break;
               }
 #endif /* JS_HAS_DESTRUCTURING */
 
               case TOK_NAME:
               {
-                RootedVar<PropertyName*> name(context, tokenStream.currentToken().name());
+                PropertyName *name = tokenStream.currentToken().name();
 
 #ifdef JS_HAS_DESTRUCTURING
                 /*
                  * ECMA-262 requires us to support duplicate parameter names,
                  * but if the parameter list includes destructuring, we
                  * consider the code to have "opted in" to higher standards and
                  * forbid duplicates. We may see a destructuring parameter
                  * later, so always note duplicates now.
@@ -1411,17 +1409,17 @@ Parser::functionArguments(TreeContext &f
             return false;
         }
     }
 
     return true;
 }
 
 ParseNode *
-Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSyntaxKind kind)
+Parser::functionDef(PropertyName *funName, FunctionType type, FunctionSyntaxKind kind)
 {
     JS_ASSERT_IF(kind == Statement, funName);
 
     /* Make a TOK_FUNCTION node. */
     ParseNode *pn = FunctionNode::create(PNK_FUNCTION, tc);
     if (!pn)
         return NULL;
     pn->pn_body = NULL;
@@ -1534,17 +1532,17 @@ Parser::functionDef(HandlePropertyName f
     TreeContext funtc(tc->parser);
     if (!funtc.init(context))
         return NULL;
 
     FunctionBox *funbox = EnterFunction(pn, &funtc, funName, kind);
     if (!funbox)
         return NULL;
 
-    RootedVarFunction fun(context, funbox->function());
+    JSFunction *fun = funbox->function();
 
     /* Now parse formal argument list and compute fun->nargs. */
     ParseNode *prelude = NULL;
     if (!functionArguments(funtc, funbox, &prelude))
         return NULL;
 
     fun->setArgCount(funtc.bindings.numArgs());
 
@@ -1724,17 +1722,17 @@ Parser::functionDef(HandlePropertyName f
         tokenStream.setStrictMode(false);
 
     return pn;
 }
 
 ParseNode *
 Parser::functionStmt()
 {
-    RootedVarPropertyName name(context);
+    PropertyName *name = NULL;
     if (tokenStream.getToken(TSF_KEYWORD_IS_NAME) == TOK_NAME) {
         name = tokenStream.currentToken().name();
     } else {
         /* Unnamed function expressions are forbidden in statement context. */
         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_UNNAMED_FUNCTION_STMT);
         return NULL;
     }
 
@@ -1745,17 +1743,17 @@ Parser::functionStmt()
     }
 
     return functionDef(name, Normal, Statement);
 }
 
 ParseNode *
 Parser::functionExpr()
 {
-    RootedVarPropertyName name(context);
+    PropertyName *name = NULL;
     if (tokenStream.getToken(TSF_KEYWORD_IS_NAME) == TOK_NAME)
         name = tokenStream.currentToken().name();
     else
         tokenStream.ungetToken();
     return functionDef(name, Normal, Expression);
 }
 
 /*
@@ -1965,18 +1963,18 @@ ReportRedeclaration(JSContext *cx, TreeC
  */
 static JSBool
 BindLet(JSContext *cx, BindData *data, JSAtom *atom, TreeContext *tc)
 {
     ParseNode *pn = data->pn;
     if (!CheckStrictBinding(cx, tc, atom->asPropertyName(), pn))
         return false;
 
-    RootedVar<StaticBlockObject *> blockObj(cx, data->let.blockObj);
-    unsigned blockCount = blockObj->slotCount();
+    StaticBlockObject &blockObj = *data->let.blockObj;
+    unsigned blockCount = blockObj.slotCount();
     if (blockCount == JS_BIT(16)) {
         ReportCompileErrorNumber(cx, TS(tc->parser), pn,
                                  JSREPORT_ERROR, data->let.overflow);
         return false;
     }
 
     /*
      * For bindings that are hoisted to the beginning of the block/function,
@@ -2003,25 +2001,25 @@ BindLet(JSContext *cx, BindData *data, J
     pn->pn_dflags |= PND_LET | PND_BOUND;
 
     /*
      * Define the let binding's property before storing pn in the the binding's
      * slot indexed by blockCount off the class-reserved slot base.
      */
     bool redeclared;
     jsid id = ATOM_TO_JSID(atom);
-    const Shape *shape = blockObj->addVar(cx, id, blockCount, &redeclared);
+    const Shape *shape = blockObj.addVar(cx, id, blockCount, &redeclared);
     if (!shape) {
         if (redeclared)
             ReportRedeclaration(cx, tc, pn, false, atom);
         return false;
     }
 
     /* Store pn in the static block object. */
-    blockObj->setDefinitionParseNode(blockCount, reinterpret_cast<Definition *>(pn));
+    blockObj.setDefinitionParseNode(blockCount, reinterpret_cast<Definition *>(pn));
     return true;
 }
 
 template <class Op>
 static inline bool
 ForEachLetDef(TreeContext *tc, StaticBlockObject &blockObj, Op op)
 {
     for (Shape::Range r = blockObj.lastProperty()->all(); !r.empty(); r.popFront()) {
@@ -2082,22 +2080,21 @@ OuterLet(TreeContext *tc, StmtInfo *stmt
  * gets its own script and frame. The eval-from-function-code case is harder,
  * since functions do not atomize gvars and then reserve their atom indexes as
  * stack frame slots.
  */
 static bool
 DefineGlobal(ParseNode *pn, BytecodeEmitter *bce, PropertyName *name)
 {
     GlobalScope *globalScope = bce->globalScope;
-    HandleObject globalObj = globalScope->globalObj;
+    JSObject *globalObj = globalScope->globalObj;
 
     if (!bce->compileAndGo() || !globalObj || bce->compilingForEval())
         return true;
 
-    JS_ASSERT(!IsPoisonedPtr(name));
     AtomIndexAddPtr p = globalScope->names.lookupForAdd(name);
     if (!p) {
         JSContext *cx = bce->parser->context;
 
         JSObject *holder;
         JSProperty *prop;
         if (!globalObj->lookupProperty(cx, name, &holder, &prop))
             return false;
@@ -2125,18 +2122,16 @@ DefineGlobal(ParseNode *pn, BytecodeEmit
             def = GlobalScope::GlobalDef(shape->slot());
         } else {
             def = GlobalScope::GlobalDef(name, funbox);
         }
 
         if (!globalScope->defs.append(def))
             return false;
 
-        JS_ASSERT(!IsPoisonedPtr(name));
-
         jsatomid index = globalScope->names.count();
         if (!globalScope->names.add(p, name, index))
             return false;
 
         JS_ASSERT(index == globalScope->defs.length() - 1);
     } else {
         /*
          * Functions can be redeclared, and the last one takes effect. Check
@@ -2591,18 +2586,17 @@ CheckDestructuring(JSContext *cx, BindDa
     bool ok;
 
     if (left->isKind(PNK_ARRAYCOMP)) {
         ReportCompileErrorNumber(cx, TS(tc->parser), left, JSREPORT_ERROR,
                                  JSMSG_ARRAY_COMP_LEFTSIDE);
         return false;
     }
 
-    RootedVar<StaticBlockObject *> blockObj(cx);
-    blockObj = data && data->binder == BindLet ? data->let.blockObj : NULL;
+    StaticBlockObject *blockObj = data && data->binder == BindLet ? data->let.blockObj : NULL;
     uint32_t blockCountBefore = blockObj ? blockObj->slotCount() : 0;
 
     if (left->isKind(PNK_RB)) {
         for (ParseNode *pn = left->pn_head; pn; pn = pn->pn_next) {
             /* Nullary comma is an elision; binary comma is an expression.*/
             if (!pn->isArrayHole()) {
                 if (pn->isKind(PNK_RB) || pn->isKind(PNK_RC)) {
                     ok = CheckDestructuring(cx, data, pn, tc, false);
@@ -2903,17 +2897,17 @@ Parser::letBlock(LetContext letContext)
     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_LET);
 
     ParseNode *vars = variables(PNK_LET, blockObj, DontHoistVars);
     if (!vars)
         return NULL;
 
     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_LET);
 
-    StmtInfo stmtInfo(context);
+    StmtInfo stmtInfo;
     ParseNode *block = PushLetScope(context, tc, *blockObj, &stmtInfo);
     if (!block)
         return NULL;
 
     pnlet->pn_left = vars;
     pnlet->pn_right = block;
 
     ParseNode *ret;
@@ -3038,17 +3032,17 @@ Parser::switchStatement()
 
     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_SWITCH);
     MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_SWITCH);
 
     /*
      * NB: we must push stmtInfo before calling GenerateBlockIdForStmtNode
      * because that function states tc->topStmt->blockid.
      */
-    StmtInfo stmtInfo(context);
+    StmtInfo stmtInfo;
     PushStatement(tc, &stmtInfo, STMT_SWITCH, -1);
 
     /* pn2 is a list of case nodes. The default case has pn_left == NULL */
     ParseNode *pn2 = ListNode::create(PNK_STATEMENTLIST, tc);
     if (!pn2)
         return NULL;
     pn2->makeEmpty();
     if (!GenerateBlockIdForStmtNode(pn2, tc))
@@ -3160,17 +3154,17 @@ Parser::forStatement()
 {
     JS_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
 
     /* A FOR node is binary, left is loop control and right is the body. */
     ParseNode *pn = BinaryNode::create(PNK_FOR, tc);
     if (!pn)
         return NULL;
 
-    StmtInfo forStmt(context);
+    StmtInfo forStmt;
     PushStatement(tc, &forStmt, STMT_FOR_LOOP, -1);
 
     pn->setOp(JSOP_ITER);
     pn->pn_iflags = 0;
     if (tokenStream.matchToken(TOK_NAME)) {
         if (tokenStream.currentToken().name() == context->runtime->atomState.eachAtom)
             pn->pn_iflags = JSITER_FOREACH;
         else
@@ -3252,19 +3246,19 @@ Parser::forStatement()
     ParseNode *forParent = NULL;
 
     /*
      * We can be sure that it's a for/in loop if there's still an 'in'
      * keyword here, even if JavaScript recognizes 'in' as an operator,
      * as we've excluded 'in' from being parsed in RelExpr by setting
      * the TCF_IN_FOR_INIT flag in our TreeContext.
      */
-    ParseNode *forHead;        /* initialized by both branches. */
-    StmtInfo letStmt(context); /* used if blockObj != NULL. */
-    ParseNode *pn2, *pn3;      /* forHead->pn_kid1 and pn_kid2. */
+    ParseNode *forHead;     /* initialized by both branches. */
+    StmtInfo letStmt;       /* used if blockObj != NULL. */
+    ParseNode *pn2, *pn3;   /* forHead->pn_kid1 and pn_kid2. */
     bool forOf;
     if (pn1 && matchInOrOf(&forOf)) {
         /*
          * Parse the rest of the for/in or for/of head.
          *
          * Here pn1 is everything to the left of 'in' or 'of'. At the end of
          * this block, pn1 is a decl or NULL, pn2 is the assignment target that
          * receives the enumeration value each iteration, and pn3 is the rhs of
@@ -3553,17 +3547,17 @@ Parser::tryStatement()
      * finally nodes are TOK_LC statement lists.
      */
     ParseNode *pn = TernaryNode::create(PNK_TRY, tc);
     if (!pn)
         return NULL;
     pn->setOp(JSOP_NOP);
 
     MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY);
-    StmtInfo stmtInfo(context);
+    StmtInfo stmtInfo;
     if (!PushBlocklikeStatement(&stmtInfo, STMT_TRY, tc))
         return NULL;
     pn->pn_kid1 = statements();
     if (!pn->pn_kid1)
         return NULL;
     MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_TRY);
     PopStatement(tc);
 
@@ -3720,17 +3714,17 @@ Parser::withStatement()
     if (!pn2)
         return NULL;
     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_WITH);
     pn->pn_left = pn2;
 
     ParseNode *oldWith = tc->innermostWith;
     tc->innermostWith = pn;
 
-    StmtInfo stmtInfo(context);
+    StmtInfo stmtInfo;
     PushStatement(tc, &stmtInfo, STMT_WITH, -1);
     pn2 = statement();
     if (!pn2)
         return NULL;
     PopStatement(tc);
 
     pn->pn_pos.end = pn2->pn_pos.end;
     pn->pn_right = pn2;
@@ -3891,17 +3885,17 @@ Parser::expressionStatement()
                 return NULL;
             }
         }
         ForgetUse(pn2);
 
         (void) tokenStream.getToken();
 
         /* Push a label struct and parse the statement. */
-        StmtInfo stmtInfo(context);
+        StmtInfo stmtInfo;
         PushStatement(tc, &stmtInfo, STMT_LABEL, -1);
         stmtInfo.label = label;
         ParseNode *pn = statement();
         if (!pn)
             return NULL;
 
         /* Normalize empty statement to empty block for the decompiler. */
         if (pn->isKind(PNK_SEMI) && !pn->pn_kid) {
@@ -3972,17 +3966,17 @@ Parser::statement()
         /* An IF node has three kids: condition, then, and optional else. */
         pn = TernaryNode::create(PNK_IF, tc);
         if (!pn)
             return NULL;
         ParseNode *pn1 = condition();
         if (!pn1)
             return NULL;
 
-        StmtInfo stmtInfo(context);
+        StmtInfo stmtInfo;
         PushStatement(tc, &stmtInfo, STMT_IF, -1);
         ParseNode *pn2 = statement();
         if (!pn2)
             return NULL;
 
         if (pn2->isKind(PNK_SEMI) &&
             !pn2->pn_kid &&
             !reportErrorNumber(NULL, JSREPORT_WARNING | JSREPORT_STRICT, JSMSG_EMPTY_CONSEQUENT))
@@ -4011,17 +4005,17 @@ Parser::statement()
       case TOK_SWITCH:
         return switchStatement();
 
       case TOK_WHILE:
       {
         pn = BinaryNode::create(PNK_WHILE, tc);
         if (!pn)
             return NULL;
-        StmtInfo stmtInfo(context);
+        StmtInfo stmtInfo;
         PushStatement(tc, &stmtInfo, STMT_WHILE_LOOP, -1);
         ParseNode *pn2 = condition();
         if (!pn2)
             return NULL;
         pn->pn_left = pn2;
         ParseNode *pn3 = statement();
         if (!pn3)
             return NULL;
@@ -4031,17 +4025,17 @@ Parser::statement()
         return pn;
       }
 
       case TOK_DO:
       {
         pn = BinaryNode::create(PNK_DOWHILE, tc);
         if (!pn)
             return NULL;
-        StmtInfo stmtInfo(context);
+        StmtInfo stmtInfo;
         PushStatement(tc, &stmtInfo, STMT_DO_LOOP, -1);
         ParseNode *pn2 = statement();
         if (!pn2)
             return NULL;
         pn->pn_left = pn2;
         MUST_MATCH_TOKEN(TOK_WHILE, JSMSG_WHILE_AFTER_DO);
         ParseNode *pn3 = condition();
         if (!pn3)
@@ -4208,17 +4202,17 @@ Parser::statement()
         break;
 
       case TOK_LC:
       {
         unsigned oldflags;
 
         oldflags = tc->flags;
         tc->flags = oldflags & ~TCF_HAS_FUNCTION_STMT;
-        StmtInfo stmtInfo(context);
+        StmtInfo stmtInfo;
         if (!PushBlocklikeStatement(&stmtInfo, STMT_BLOCK, tc))
             return NULL;
         pn = statements();
         if (!pn)
             return NULL;
 
         MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_IN_COMPOUND);
         PopStatement(tc);
@@ -5309,17 +5303,17 @@ CompExprTransplanter::transplant(ParseNo
  * (possibly nested) for-loop, initialized by |kind, op, kid|.
  */
 ParseNode *
 Parser::comprehensionTail(ParseNode *kid, unsigned blockid, bool isGenexp,
                           ParseNodeKind kind, JSOp op)
 {
     unsigned adjust;
     ParseNode *pn, *pn2, *pn3, **pnp;
-    StmtInfo stmtInfo(context);
+    StmtInfo stmtInfo;
     BindData data;
     TokenKind tt;
 
     JS_ASSERT(tokenStream.currentToken().type == TOK_FOR);
 
     if (kind == PNK_SEMI) {
         /*
          * Generator expression desugars to an immediately applied lambda that
@@ -5758,17 +5752,17 @@ Parser::memberExpr(JSBool allowCallSynta
 #if JS_HAS_XML_SUPPORT
             else if (!tc->inStrictMode()) {
                 TokenPtr begin = lhs->pn_pos.begin;
                 if (tt == TOK_LP) {
                     /* Filters are effectively 'with', so deoptimize names. */
                     tc->flags |= TCF_FUN_HEAVYWEIGHT;
                     tc->noteBindingsAccessedDynamically();
 
-                    StmtInfo stmtInfo(context);
+                    StmtInfo stmtInfo;
                     ParseNode *oldWith = tc->innermostWith;
                     tc->innermostWith = lhs;
                     PushStatement(tc, &stmtInfo, STMT_WITH, -1);
 
                     ParseNode *filter = bracketedExpr();
                     if (!filter)
                         return NULL;
                     filter->setInParens(true);
@@ -6935,18 +6929,17 @@ Parser::primaryExpr(TokenKind tt, bool a
                             return NULL;
                         pn3->pn_atom = atom;
                         break;
                     }
 
                     pn->pn_xflags |= PNX_NONCONST;
 
                     /* NB: Getter function in { get x(){} } is unnamed. */
-                    pn2 = functionDef(RootedVarPropertyName(context, NULL),
-                                      op == JSOP_GETTER ? Getter : Setter, Expression);
+                    pn2 = functionDef(NULL, op == JSOP_GETTER ? Getter : Setter, Expression);
                     if (!pn2)
                         return NULL;
                     TokenPos pos = {begin, pn2->pn_pos.end};
                     pn2 = new_<BinaryNode>(PNK_COLON, op, pos, pn3, pn2);
                     goto skip;
                 }
               case TOK_STRING: {
                 atom = tokenStream.currentToken().atom();
@@ -7149,17 +7142,17 @@ Parser::primaryExpr(TokenKind tt, bool a
         if (!pn)
             return NULL;
 
         const jschar *chars = tokenStream.getTokenbuf().begin();
         size_t length = tokenStream.getTokenbuf().length();
         RegExpFlag flags = tokenStream.currentToken().regExpFlags();
         RegExpStatics *res = context->regExpStatics();
 
-        RootedVar<RegExpObject*> reobj(context);
+        RegExpObject *reobj;
         if (context->hasfp())
             reobj = RegExpObject::create(context, res, chars, length, flags, &tokenStream);
         else
             reobj = RegExpObject::createNoStatics(context, chars, length, flags, &tokenStream);
 
         if (!reobj)
             return NULL;
 
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -238,17 +238,17 @@ struct Parser : private AutoGCRooter
     ParseNode *parenExpr(JSBool *genexp = NULL);
 
     /*
      * Additional JS parsers.
      */
     enum FunctionType { Getter, Setter, Normal };
     bool functionArguments(TreeContext &funtc, FunctionBox *funbox, ParseNode **list);
 
-    ParseNode *functionDef(HandlePropertyName name, FunctionType type, FunctionSyntaxKind kind);
+    ParseNode *functionDef(PropertyName *name, FunctionType type, FunctionSyntaxKind kind);
 
     ParseNode *unaryOpExpr(ParseNodeKind kind, JSOp op);
 
     ParseNode *condition();
     ParseNode *comprehensionTail(ParseNode *kid, unsigned blockid, bool isGenexp,
                                  ParseNodeKind kind = PNK_SEMI, JSOp op = JSOP_NOP);
     ParseNode *generatorExpr(ParseNode *kid);
     JSBool argumentList(ParseNode *listNode);
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -149,18 +149,17 @@ js::IsIdentifier(JSLinearString *str)
 
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable:4351)
 #endif
 
 /* Initialize members that aren't initialized in |init|. */
 TokenStream::TokenStream(JSContext *cx, JSPrincipals *prin, JSPrincipals *originPrin)
-  : tokens(), tokensRoot(cx, &tokens),
-    cursor(), lookahead(), flags(), userbufRoot(cx, &userbuf), listenerTSData(), tokenbuf(cx),
+  : tokens(), cursor(), lookahead(), flags(), listenerTSData(), tokenbuf(cx),
     cx(cx), originPrincipals(JSScript::normalizeOriginPrincipals(prin, originPrin))
 {
     if (originPrincipals)
         JS_HoldPrincipals(originPrincipals);
 }
 
 #ifdef _MSC_VER
 #pragma warning(pop)
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -331,34 +331,30 @@ struct Token {
 
     /*
      * FIXME: Init type early enough such that all mutators can assert
      *        type-safety.  See bug 697000.
      */
 
     void setName(JSOp op, PropertyName *name) {
         JS_ASSERT(op == JSOP_NAME);
-        JS_ASSERT(!IsPoisonedPtr(name));
         u.s.op = op;
         u.s.n.name = name;
     }
 
     void setAtom(JSOp op, JSAtom *atom) {
         JS_ASSERT(op == JSOP_STRING || op == JSOP_XMLCOMMENT || JSOP_XMLCDATA);
-        JS_ASSERT(!IsPoisonedPtr(atom));
         u.s.op = op;
         u.s.n.atom = atom;
     }
 
     void setProcessingInstruction(PropertyName *target, JSAtom *data) {
         JS_ASSERT(target);
         JS_ASSERT(data);
         JS_ASSERT(!target->empty());
-        JS_ASSERT(!IsPoisonedPtr(target));
-        JS_ASSERT(!IsPoisonedPtr(data));
         u.xmlpi.target = target;
         u.xmlpi.data = data;
     }
 
     void setRegExpFlags(js::RegExpFlag flags) {
         JS_ASSERT((flags & AllFlags) == flags);
         u.reflags = flags;
     }
@@ -807,25 +803,23 @@ class TokenStream
         while (--n >= 0)
             getChar();
     }
 
     void updateLineInfoForEOL();
     void updateFlagsForEOL();
 
     Token               tokens[ntokens];/* circular token buffer */
-    JS::SkipRoot        tokensRoot;     /* prevent overwriting of token buffer */
-    unsigned            cursor;         /* index of last parsed token */
-    unsigned            lookahead;      /* count of lookahead tokens */
-    unsigned            lineno;         /* current line number */
-    unsigned            flags;          /* flags -- see above */
+    unsigned               cursor;         /* index of last parsed token */
+    unsigned               lookahead;      /* count of lookahead tokens */
+    unsigned               lineno;         /* current line number */
+    unsigned               flags;          /* flags -- see above */
     const jschar        *linebase;      /* start of current line;  points into userbuf */
     const jschar        *prevLinebase;  /* start of previous line;  NULL if on the first line */
     TokenBuf            userbuf;        /* user input buffer */
-    JS::SkipRoot        userbufRoot;    /* prevent overwriting of char pointers within userbuf */
     const char          *filename;      /* input filename or null */
     jschar              *sourceMap;     /* source map's filename or null */
     void                *listenerTSData;/* listener data for this TokenStream */
     CharBuffer          tokenbuf;       /* current token string buffer */
     int8_t              oneCharTokens[128];  /* table of one-char tokens */
     bool                maybeEOL[256];       /* probabilistic EOL lookup table */
     bool                maybeStrSpecial[256];/* speeds up string scanning */
     JSVersion           version;        /* (i.e. to identify keywords) */
--- a/js/src/gc/Barrier-inl.h
+++ b/js/src/gc/Barrier-inl.h
@@ -119,17 +119,16 @@ HeapValue::init(const Value &v)
     JS_ASSERT(!IsPoisonedValue(v));
     value = v;
     post();
 }
 
 inline void
 HeapValue::init(JSCompartment *comp, const Value &v)
 {
-    JS_ASSERT(!IsPoisonedValue(v));
     value = v;
     post(comp);
 }
 
 inline HeapValue &
 HeapValue::operator=(const Value &v)
 {
     pre();
--- a/js/src/gc/Root.h
+++ b/js/src/gc/Root.h
@@ -35,23 +35,20 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jsgc_root_h__
 #define jsgc_root_h__
 
-#include "jspubtd.h"
-
-#include "js/Utility.h"
+#include "jsapi.h"
+#include "jsprvtd.h"
 
-#ifdef __cplusplus
-
-namespace JS {
+namespace js {
 
 /*
  * Moving GC Stack Rooting
  *
  * A moving GC may change the physical location of GC allocated things, even
  * when they are rooted, updating all pointers to the thing to refer to its new
  * location. The GC must therefore know about all live pointers to a thing,
  * not just one of them, in order to behave correctly.
@@ -90,65 +87,43 @@ namespace JS {
  *   should generally replace those arguments with handles and avoid any
  *   explicit rooting. This has two benefits. First, when several such
  *   functions call each other then redundant rooting of multiple copies of the
  *   GC thing can be avoided. Second, if the caller does not pass a rooted
  *   value a compile error will be generated, which is quicker and easier to
  *   fix than when relying on a separate rooting analysis.
  */
 
-template <typename T> class Root;
-template <typename T> class RootedVar;
-
-template <typename T>
-struct RootMethods { };
-
-/*
- * Reference to a stack location rooted for GC. See "Moving GC Stack Rooting"
- * comment in jscntxt.h.
- */
-template <typename T>
-class Handle
+template <> struct RootMethods<const jsid>
 {
-  public:
-    /* Copy handles of different types, with implicit coercion. */
-    template <typename S> Handle(Handle<S> handle) {
-        testAssign<S>();
-        ptr = reinterpret_cast<const T *>(handle.address());
-    }
+    static jsid initial() { return JSID_VOID; }
+    static ThingRootKind kind() { return THING_ROOT_ID; }
+    static bool poisoned(jsid id) { return IsPoisonedId(id); }
+};
 
-    /* Get a handle from a rooted stack location, with implicit coercion. */
-    template <typename S> inline Handle(const Root<S> &root);
-    template <typename S> inline Handle(const RootedVar<S> &root);
-
-    const T *address() { return ptr; }
-
-    operator T () { return value(); }
-    T operator ->() { return value(); }
-
-  private:
-    const T *ptr;
-    T value() { return *ptr; }
-
-    template <typename S>
-    void testAssign() {
-#ifdef DEBUG
-        T a = RootMethods<T>::initial();
-        S b = RootMethods<S>::initial();
-        a = b;
-        (void)a;
-#endif
-    }
+template <> struct RootMethods<jsid>
+{
+    static jsid initial() { return JSID_VOID; }
+    static ThingRootKind kind() { return THING_ROOT_ID; }
+    static bool poisoned(jsid id) { return IsPoisonedId(id); }
 };
 
-typedef Handle<JSObject*>    HandleObject;
-typedef Handle<JSFunction*>  HandleFunction;
-typedef Handle<JSString*>    HandleString;
-typedef Handle<jsid>         HandleId;
-typedef Handle<Value>        HandleValue;
+template <> struct RootMethods<const Value>
+{
+    static Value initial() { return UndefinedValue(); }
+    static ThingRootKind kind() { return THING_ROOT_VALUE; }
+    static bool poisoned(const Value &v) { return IsPoisonedValue(v); }
+};
+
+template <> struct RootMethods<Value>
+{
+    static Value initial() { return UndefinedValue(); }
+    static ThingRootKind kind() { return THING_ROOT_VALUE; }
+    static bool poisoned(const Value &v) { return IsPoisonedValue(v); }
+};
 
 template <typename T>
 struct RootMethods<T *>
 {
     static T *initial() { return NULL; }
     static ThingRootKind kind() { return T::rootKind(); }
     static bool poisoned(T *v) { return IsPoisonedPtr(v); }
 };
@@ -162,22 +137,20 @@ struct RootMethods<T *>
  * initialized, as otherwise the GC may try to use the the uninitialized value.
  * It is generally preferable to use either RootedVar for local variables, or
  * Handle for arguments.
  */
 template <typename T>
 class Root
 {
   public:
-    Root(JSContext *cx_, const T *ptr
+    Root(JSContext *cx, const T *ptr
          JS_GUARD_OBJECT_NOTIFIER_PARAM)
     {
 #ifdef JSGC_ROOT_ANALYSIS
-        ContextFriendFields *cx = ContextFriendFields::get(cx_);
-
         ThingRootKind kind = RootMethods<T>::kind();
         this->stack = reinterpret_cast<Root<T>**>(&cx->thingGCRooters[kind]);
         this->prev = *stack;
         *stack = this;
 #endif
 
         JS_ASSERT(!RootMethods<T>::poisoned(*ptr));
 
@@ -213,138 +186,115 @@ class Root
 template<typename T> template <typename S>
 inline
 Handle<T>::Handle(const Root<S> &root)
 {
     testAssign<S>();
     ptr = reinterpret_cast<const T *>(root.address());
 }
 
-typedef Root<JSObject*>    RootObject;
-typedef Root<JSFunction*>  RootFunction;
-typedef Root<JSString*>    RootString;
-typedef Root<jsid>         RootId;
-typedef Root<Value>        RootValue;
+typedef Root<JSObject*>          RootObject;
+typedef Root<JSFunction*>        RootFunction;
+typedef Root<Shape*>             RootShape;
+typedef Root<BaseShape*>         RootBaseShape;
+typedef Root<types::TypeObject*> RootTypeObject;
+typedef Root<JSString*>          RootString;
+typedef Root<JSAtom*>            RootAtom;
+typedef Root<jsid>               RootId;
+typedef Root<Value>              RootValue;
 
-/*
- * Mark a stack location as a root for the rooting analysis, without actually
- * rooting it in release builds. This should only be used for stack locations
- * of GC things that cannot be relocated by a garbage collection, and that
- * are definitely reachable via another path.
- */
-class SkipRoot
+/* Mark a stack location as a root for a rooting analysis. */
+class CheckRoot
 {
 #if defined(DEBUG) && defined(JSGC_ROOT_ANALYSIS)
 
-    SkipRoot **stack, *prev;
-    const uint8_t *start;
-    const uint8_t *end;
+    CheckRoot **stack, *prev;
+    const uint8_t *ptr;
 
   public:
     template <typename T>
-    SkipRoot(JSContext *cx_, const T *ptr
+    CheckRoot(JSContext *cx, const T *ptr
               JS_GUARD_OBJECT_NOTIFIER_PARAM)
     {
-        ContextFriendFields *cx = ContextFriendFields::get(cx_);
-
-        this->stack = &cx->skipGCRooters;
+        this->stack = &cx->checkGCRooters;
         this->prev = *stack;
         *stack = this;
-        this->start = (const uint8_t *) ptr;
-        this->end = this->start + sizeof(T);
+        this->ptr = static_cast<const uint8_t*>(ptr);
         JS_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
-    ~SkipRoot()
+    ~CheckRoot()
     {
         JS_ASSERT(*stack == this);
         *stack = prev;
     }
 
-    SkipRoot *previous() { return prev; }
+    CheckRoot *previous() { return prev; }
 
     bool contains(const uint8_t *v, size_t len) {
-        return v >= start && v + len <= end;
+        return ptr >= v && ptr < v + len;
     }
 
 #else /* DEBUG && JSGC_ROOT_ANALYSIS */
 
   public:
     template <typename T>
-    SkipRoot(JSContext *cx, const T *ptr
+    CheckRoot(JSContext *cx, const T *ptr
               JS_GUARD_OBJECT_NOTIFIER_PARAM)
     {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
 #endif /* DEBUG && JSGC_ROOT_ANALYSIS */
 
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 /* Make a local variable which stays rooted throughout its lifetime. */
 template <typename T>
 class RootedVar
 {
   public:
     RootedVar(JSContext *cx)
-      : ptr(RootMethods<T>::initial()), root(cx, &ptr)
+        : ptr(RootMethods<T>::initial()), root(cx, &ptr)
     {}
 
     RootedVar(JSContext *cx, T initial)
-      : ptr(initial), root(cx, &ptr)
+        : ptr(initial), root(cx, &ptr)
     {}
 
-    operator T () const { return ptr; }
-    T operator ->() const { return ptr; }
+    operator T () { return ptr; }
+    T operator ->() { return ptr; }
     T * address() { return &ptr; }
     const T * address() const { return &ptr; }
-    T & reference() { return ptr; }
     T raw() { return ptr; }
 
-    /*
-     * This method is only necessary due to an obscure C++98 requirement (that
-     * there be an accessible, usable copy constructor when passing a temporary
-     * to an implicitly-called constructor for use with a const-ref parameter).
-     * (Head spinning yet?)  We can remove this when we build the JS engine
-     * with -std=c++11.
-     */
-    operator Handle<T> () const { return Handle<T>(*this); }
-
     T & operator =(T value)
     {
         JS_ASSERT(!RootMethods<T>::poisoned(value));
         ptr = value;
         return ptr;
     }
 
-    T & operator =(const RootedVar &value)
-    {
-        ptr = value;
-        return ptr;
-    }
-
   private:
     T ptr;
     Root<T> root;
-
-    RootedVar() MOZ_DELETE;
-    RootedVar(const RootedVar &) MOZ_DELETE;
 };
 
 template <typename T> template <typename S>
 inline
 Handle<T>::Handle(const RootedVar<S> &root)
 {
     ptr = reinterpret_cast<const T *>(root.address());
 }
 
-typedef RootedVar<JSObject*>    RootedVarObject;
-typedef RootedVar<JSFunction*>  RootedVarFunction;
-typedef RootedVar<JSString*>    RootedVarString;
-typedef RootedVar<jsid>         RootedVarId;
-typedef RootedVar<Value>        RootedVarValue;
+typedef RootedVar<JSObject*>          RootedVarObject;
+typedef RootedVar<JSFunction*>        RootedVarFunction;
+typedef RootedVar<Shape*>             RootedVarShape;
+typedef RootedVar<BaseShape*>         RootedVarBaseShape;
+typedef RootedVar<types::TypeObject*> RootedVarTypeObject;
+typedef RootedVar<JSString*>          RootedVarString;
+typedef RootedVar<JSAtom*>            RootedVarAtom;
+typedef RootedVar<jsid>               RootedVarId;
+typedef RootedVar<Value>              RootedVarValue;
 
-}  /* namespace JS */
-
-#endif  /* __cplusplus */
-
+}  /* namespace js */
 #endif  /* jsgc_root_h___ */
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3075,17 +3075,17 @@ JS_ResolveStub(JSContext *cx, JSObject *
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
 {
     JS_ASSERT(type != JSTYPE_OBJECT && type != JSTYPE_FUNCTION);
     JS_ASSERT(obj);
-    return DefaultValue(cx, RootedVarObject(cx, obj), type, vp);
+    return DefaultValue(cx, obj, type, vp);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
              JSClass *clasp, JSNative constructor, unsigned nargs,
              JSPropertySpec *ps, JSFunctionSpec *fs,
              JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
 {
@@ -3615,17 +3615,17 @@ JS_PUBLIC_API(JSBool)
 JS_AlreadyHasOwnUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
                            JSBool *foundp)
 {
     JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
     return atom && JS_AlreadyHasOwnPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
 }
 
 static JSBool
-DefinePropertyById(JSContext *cx, HandleObject obj, jsid id, const Value &value,
+DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, const Value &value,
                    PropertyOp getter, StrictPropertyOp setter, unsigned attrs,
                    unsigned flags, int tinyid)
 {
     /*
      * JSPROP_READONLY has no meaning when accessors are involved. Ideally we'd
      * throw if this happens, but we've accepted it for long enough that it's
      * not worth trying to make callers change their ways. Just flip it off on
      * its way through the API layer so that we can enforce this internally.
@@ -3675,46 +3675,44 @@ DefinePropertyById(JSContext *cx, Handle
     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);
 }
 
 JS_PUBLIC_API(JSBool)
-JS_DefinePropertyById(JSContext *cx, JSObject *obj_, jsid id, jsval value,
+JS_DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value,
                       JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs)
 {
-    RootedVarObject obj(cx, obj_);
     return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, 0, 0);
 }
 
 JS_PUBLIC_API(JSBool)
-JS_DefineElement(JSContext *cx, JSObject *obj_, uint32_t index, jsval value,
+JS_DefineElement(JSContext *cx, JSObject *obj, uint32_t index, jsval value,
                  JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs)
 {
-    RootedVarObject obj(cx, obj_);
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     jsid id;
     if (!IndexToId(cx, index, &id))
         return false;
     return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, 0, 0);
 }
 
 static JSBool
-DefineProperty(JSContext *cx, JSObject *obj_, const char *name, const Value &value_,
+DefineProperty(JSContext *cx, JSObject *obj, const char *name, const Value &value,
                PropertyOp getter, StrictPropertyOp setter, unsigned attrs,
                unsigned flags, int tinyid)
 {
     jsid id;
     JSAtom *atom;
 
-    RootedVarObject obj(cx, obj_);
-    RootedVarValue value(cx, value_);
+    RootObject objRoot(cx, &obj);
+    RootValue valueRoot(cx, &value);
 
     if (attrs & JSPROP_INDEX) {
         id = INT_TO_JSID(intptr_t(name));
         atom = NULL;
         attrs &= ~JSPROP_INDEX;
     } else {
         atom = js_Atomize(cx, name, strlen(name));
         if (!atom)
@@ -3735,21 +3733,20 @@ JS_DefineProperty(JSContext *cx, JSObjec
 JS_PUBLIC_API(JSBool)
 JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name, int8_t tinyid,
                             jsval value, PropertyOp getter, JSStrictPropertyOp setter, unsigned attrs)
 {
     return DefineProperty(cx, obj, name, value, getter, setter, attrs, Shape::HAS_SHORTID, tinyid);
 }
 
 static JSBool
-DefineUCProperty(JSContext *cx, JSObject *obj_, const jschar *name, size_t namelen,
+DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
                  const Value &value, PropertyOp getter, StrictPropertyOp setter, unsigned attrs,
                  unsigned flags, int tinyid)
 {
-    RootObject obj(cx, &obj_);
     JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
     return atom && DefinePropertyById(cx, obj, ATOM_TO_JSID(atom), value, getter, setter, attrs,
                                       flags, tinyid);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
                     jsval value, JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs)
@@ -3767,17 +3764,17 @@ JS_DefineUCPropertyWithTinyId(JSContext 
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, JSBool *bp)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id, descriptor);
-    return js_DefineOwnProperty(cx, RootedVarObject(cx, obj), RootedVarId(cx, id), descriptor, bp);
+    return js_DefineOwnProperty(cx, obj, id, descriptor, bp);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *jsclasp,
                 JSObject *proto, unsigned attrs)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
@@ -3796,20 +3793,18 @@ JS_DefineObject(JSContext *cx, JSObject 
 
     if (!DefineProperty(cx, obj, name, ObjectValue(*nobj), NULL, NULL, attrs, 0, 0))
         return NULL;
 
     return nobj;
 }
 
 JS_PUBLIC_API(JSBool)
-JS_DefineConstDoubles(JSContext *cx, JSObject *obj_, JSConstDoubleSpec *cds)
-{
-    RootedVarObject obj(cx, obj_);
-
+JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds)
+{
     JSBool ok;
     unsigned attrs;
 
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     for (ok = JS_TRUE; cds->name; cds++) {
         Value value = DoubleValue(cds->dval);
         attrs = cds->flags;
@@ -3946,17 +3941,17 @@ JS_GetUCPropertyAttrsGetterAndSetter(JSC
                                                           attrsp, foundp, getterp, setterp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
-    return GetOwnPropertyDescriptor(cx, RootedVarObject(cx, obj), RootedVarId(cx, id), vp);
+    return GetOwnPropertyDescriptor(cx, obj, id, vp);
 }
 
 static JSBool
 SetPropertyAttributesById(JSContext *cx, JSObject *obj, jsid id, unsigned attrs, JSBool *foundp)
 {
     JSObject *obj2;
     JSProperty *prop;
 
@@ -4006,17 +4001,17 @@ JS_ForwardGetPropertyTo(JSContext *cx, J
     assertSameCompartment(cx, onBehalfOf);
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
     return obj->getGeneric(cx, onBehalfOf, id, vp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetPropertyByIdDefault(JSContext *cx, JSObject *obj, jsid id, jsval def, jsval *vp)
 {
-    return GetPropertyDefault(cx, RootedVarObject(cx, obj), RootedVarId(cx, id), def, vp);
+    return GetPropertyDefault(cx, obj, id, def, vp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetElement(JSContext *cx, JSObject *obj, uint32_t index, jsval *vp)
 {
     return JS_ForwardGetElementTo(cx, obj, index, obj, vp);
 }
 
@@ -4066,17 +4061,17 @@ JS_GetUCProperty(JSContext *cx, JSObject
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, jsval *vp)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
-    if (!js_GetMethod(cx, RootedVarObject(cx, obj), id, 0, vp))
+    if (!js_GetMethod(cx, obj, id, 0, vp))
         return JS_FALSE;
     if (objp)
         *objp = obj;
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp, jsval *vp)
@@ -4521,24 +4516,21 @@ JS_NewFunctionById(JSContext *cx, JSNati
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, parent);
 
     RootObject parentRoot(cx, &parent);
     return js_NewFunction(cx, NULL, native, nargs, flags, parentRoot, JSID_TO_ATOM(id));
 }
 
 JS_PUBLIC_API(JSObject *)
-JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent_)
-{
-    AssertNoGC(cx);
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, parent_);  // XXX no funobj for now
-
-    RootedVarObject parent(cx, parent_);
-
+JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
+{
+    AssertNoGC(cx);
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, parent);  // XXX no funobj for now
     if (!parent) {
         if (cx->hasfp())
             parent = &cx->fp()->scopeChain();
         if (!parent)
             parent = cx->globalObject;
         JS_ASSERT(parent);
     }
 
@@ -4547,17 +4539,17 @@ JS_CloneFunctionObject(JSContext *cx, JS
          * We cannot clone this object, so fail (we used to return funobj, bad
          * idea, but we changed incompatibly to teach any abusers a lesson!).
          */
         Value v = ObjectValue(*funobj);
         js_ReportIsNotFunction(cx, &v, 0);
         return NULL;
     }
 
-    RootedVarFunction fun(cx, funobj->toFunction());
+    JSFunction *fun = funobj->toFunction();
     if (fun->isInterpreted() && fun->script()->compileAndGo) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_BAD_CLONE_FUNOBJ_SCOPE);
         return NULL;
     }
 
 
     return CloneFunctionObject(cx, fun, parent, fun->getAllocKind());
@@ -5065,27 +5057,29 @@ CompileUCFunctionForPrincipalsCommon(JSC
     RootObject objRoot(cx, &obj);
 
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, principals);
     AutoLastFrameCheck lfc(cx);
 
-    RootedVarAtom funAtom(cx);
-    if (name) {
+    JSAtom *funAtom;
+    if (!name) {
+        funAtom = NULL;
+    } else {
         funAtom = js_Atomize(cx, name, strlen(name));
         if (!funAtom)
             return NULL;
     }
 
     Bindings bindings(cx);
     for (unsigned i = 0; i < nargs; i++) {
         uint16_t dummy;
-        RootedVarAtom argAtom(cx, js_Atomize(cx, argnames[i], strlen(argnames[i])));
+        JSAtom *argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]));
         if (!argAtom || !bindings.addArgument(cx, argAtom, &dummy))
             return NULL;
     }
 
     JSFunction *fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, objRoot, funAtom);
     if (!fun)
         return NULL;
 
@@ -5256,26 +5250,24 @@ JS_PUBLIC_API(JSBool)
 JS_ExecuteScriptVersion(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval,
                         JSVersion version)
 {
     AutoVersionAPI ava(cx, version);
     return JS_ExecuteScript(cx, obj, script, rval);
 }
 
 bool
-EvaluateUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj_,
+EvaluateUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj,
                                     JSPrincipals *principals, JSPrincipals *originPrincipals,
                                     const jschar *chars, unsigned length,
                                     const char *filename, unsigned lineno,
                                     jsval *rval, JSVersion compileVersion)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
 
-    RootedVarObject obj(cx, obj_);
-
     uint32_t flags = TCF_COMPILE_N_GO | TCF_NEED_SCRIPT_GLOBAL;
     if (!rval)
         flags |= TCF_NO_SCRIPT_RVAL;
 
     CHECK_REQUEST(cx);
     AutoLastFrameCheck lfc(cx);
     JSScript *script = frontend::CompileScript(cx, obj, NULL, principals, originPrincipals,
                                                flags, chars, length, filename, lineno,
@@ -5377,27 +5369,25 @@ JS_CallFunction(JSContext *cx, JSObject 
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, fun, JSValueArray(argv, argc));
     AutoLastFrameCheck lfc(cx);
 
     return Invoke(cx, ObjectOrNullValue(obj), ObjectValue(*fun), argc, argv, rval);
 }
 
 JS_PUBLIC_API(JSBool)
-JS_CallFunctionName(JSContext *cx, JSObject *obj_, const char *name, unsigned argc, jsval *argv,
+JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, unsigned argc, jsval *argv,
                     jsval *rval)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
-    assertSameCompartment(cx, obj_, JSValueArray(argv, argc));
+    assertSameCompartment(cx, obj, JSValueArray(argv, argc));
     AutoLastFrameCheck lfc(cx);
 
-    RootedVarObject obj(cx, obj_);
-
     Value v;
     JSAtom *atom = js_Atomize(cx, name, strlen(name));
     return atom &&
            js_GetMethod(cx, obj, ATOM_TO_JSID(atom), 0, &v) &&
            Invoke(cx, ObjectOrNullValue(obj), v, argc, argv, rval);
 }
 
 JS_PUBLIC_API(JSBool)
@@ -5761,17 +5751,17 @@ JS_NewDependentString(JSContext *cx, JSS
     return js_NewDependentString(cx, str, start, length);
 }
 
 JS_PUBLIC_API(JSString *)
 JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
-    return js_ConcatStrings(cx, RootedVarString(cx, left), RootedVarString(cx, right));
+    return js_ConcatStrings(cx, left, right);
 }
 
 JS_PUBLIC_API(const jschar *)
 JS_UndependString(JSContext *cx, JSString *str)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     return str->getCharsZ(cx);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -49,17 +49,16 @@
 #include <stddef.h>
 #include <stdio.h>
 #include "js-config.h"
 #include "jspubtd.h"
 #include "jsutil.h"
 #include "jsval.h"
 
 #include "js/Utility.h"
-#include "gc/Root.h"
 
 #ifdef __cplusplus
 #include "jsalloc.h"
 #include "js/Vector.h"
 #include "mozilla/Attributes.h"
 #endif
 
 /************************************************************************/
@@ -212,16 +211,46 @@ inline Anchor<T>::~Anchor()
      * NB: there is a Anchor<Value>::~Anchor() specialization below.
      */
     volatile T sink;
     sink = hold;
 }
 #endif  /* defined(__GNUC__) */
 
 /*
+ * Methods for poisoning GC heap pointer words and checking for poisoned words.
+ * These are in this file for use in Value methods and so forth.
+ *
+ * If the moving GC hazard analysis is in use and detects a non-rooted stack
+ * pointer to a GC thing, one byte of that pointer is poisoned to refer to an
+ * invalid location. For both 32 bit and 64 bit systems, the fourth byte of the
+ * pointer is overwritten, to reduce the likelihood of accidentally changing
+ * a live integer value.
+ */
+
+inline void PoisonPtr(uintptr_t *v)
+{
+#if defined(JSGC_ROOT_ANALYSIS) && defined(DEBUG)
+    uint8_t *ptr = (uint8_t *) v + 3;
+    *ptr = JS_FREE_PATTERN;
+#endif
+}
+
+template <typename T>
+inline bool IsPoisonedPtr(T *v)
+{
+#if defined(JSGC_ROOT_ANALYSIS) && defined(DEBUG)
+    uint32_t mask = uintptr_t(v) & 0xff000000;
+    return mask == uint32_t(JS_FREE_PATTERN << 24);
+#else
+    return false;
+#endif
+}
+
+/*
  * JS::Value is the C++ interface for a single JavaScript Engine value.
  * A few general notes on JS::Value:
  *
  * - JS::Value has setX() and isX() members for X in
  *
  *     { Int32, Double, String, Boolean, Undefined, Null, Object, Magic }
  *
  *   JS::Value also contains toX() for each of the non-singleton types.
@@ -735,30 +764,16 @@ PrivateUint32Value(uint32_t ui)
 }
 
 JS_ALWAYS_INLINE bool
 SameType(const Value &lhs, const Value &rhs)
 {
     return JSVAL_SAME_TYPE_IMPL(lhs.data, rhs.data);
 }
 
-template <> struct RootMethods<const Value>
-{
-    static Value initial() { return UndefinedValue(); }
-    static ThingRootKind kind() { return THING_ROOT_VALUE; }
-    static bool poisoned(const Value &v) { return IsPoisonedValue(v); }
-};
-
-template <> struct RootMethods<Value>
-{
-    static Value initial() { return UndefinedValue(); }
-    static ThingRootKind kind() { return THING_ROOT_VALUE; }
-    static bool poisoned(const Value &v) { return IsPoisonedValue(v); }
-};
-
 /************************************************************************/
 
 #ifndef __GNUC__
 
 /*
  * The default assignment operator for |struct C| has the signature:
  *
  *   C& C::operator=(const C&)
@@ -1032,17 +1047,17 @@ class AutoEnumStateRooter : private Auto
 };
 
 template<class T>
 class AutoVectorRooter : protected AutoGCRooter
 {
   public:
     explicit AutoVectorRooter(JSContext *cx, ptrdiff_t tag
                               JS_GUARD_OBJECT_NOTIFIER_PARAM)
-      : AutoGCRooter(cx, tag), vector(cx), vectorRoot(cx, &vector)
+        : AutoGCRooter(cx, tag), vector(cx)
     {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     size_t length() const { return vector.length(); }
 
     bool append(const T &v) { return vector.append(v); }
 
@@ -1095,20 +1110,16 @@ class AutoVectorRooter : protected AutoG
     void makeRangeGCSafe(size_t oldLength) {
         T *t = vector.begin() + oldLength;
         for (size_t i = oldLength; i < vector.length(); ++i, ++t)
             memset(t, 0, sizeof(T));
     }
 
     typedef js::Vector<T, 8> VectorImpl;
     VectorImpl vector;
-
-    /* Prevent overwriting of inline elements in vector. */
-    SkipRoot vectorRoot;
-
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 class AutoValueVector : public AutoVectorRooter<Value>
 {
   public:
     explicit AutoValueVector(JSContext *cx
                              JS_GUARD_OBJECT_NOTIFIER_PARAM)
@@ -2441,44 +2452,26 @@ extern JS_PUBLIC_API(JSBool)
 JS_IsInRequest(JSRuntime *rt);
 
 extern JS_PUBLIC_API(JSBool)
 JS_IsInSuspendedRequest(JSRuntime *rt);
 
 #ifdef __cplusplus
 JS_END_EXTERN_C
 
-namespace JS {
-
 inline bool
 IsPoisonedId(jsid iden)
 {
     if (JSID_IS_STRING(iden))
         return JS::IsPoisonedPtr(JSID_TO_STRING(iden));
     if (JSID_IS_OBJECT(iden))
         return JS::IsPoisonedPtr(JSID_TO_OBJECT(iden));
     return false;
 }
 
-template <> struct RootMethods<const jsid>
-{
-    static jsid initial() { return JSID_VOID; }
-    static ThingRootKind kind() { return THING_ROOT_ID; }
-    static bool poisoned(jsid id) { return IsPoisonedId(id); }
-};
-
-template <> struct RootMethods<jsid>
-{
-    static jsid initial() { return JSID_VOID; }
-    static ThingRootKind kind() { return THING_ROOT_ID; }
-    static bool poisoned(jsid id) { return IsPoisonedId(id); }
-};
-
-} /* namespace JS */
-
 class JSAutoRequest {
   public:
     JSAutoRequest(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM)
         : mContext(cx), mSaveDepth(0) {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
         JS_BeginRequest(mContext);
     }
     ~JSAutoRequest() {
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -476,17 +476,17 @@ GetElements(JSContext *cx, JSObject *aob
 }
 
 }
 
 /*
  * Set the value of the property at the given index to v assuming v is rooted.
  */
 static JSBool
-SetArrayElement(JSContext *cx, HandleObject obj, double index, const Value &v)
+SetArrayElement(JSContext *cx, JSObject *obj, double index, const Value &v)
 {
     JS_ASSERT(index >= 0);
 
     if (obj->isDenseArray()) {
         /* Predicted/prefetched code should favor the remains-dense case. */
         JSObject::EnsureDenseResult result = JSObject::ED_SPARSE;
         do {
             if (index > uint32_t(-1))
@@ -499,17 +499,17 @@ SetArrayElement(JSContext *cx, HandleObj
                 obj->setDenseArrayLength(idx + 1);
             obj->setDenseArrayElementWithType(cx, idx, v);
             return true;
         } while (false);
 
         if (result == JSObject::ED_FAILED)
             return false;
         JS_ASSERT(result == JSObject::ED_SPARSE);
-        if (!JSObject::makeDenseArraySlow(cx, obj))
+        if (!obj->makeDenseArraySlow(cx))
             return JS_FALSE;
     }
 
     AutoIdRooter idr(cx);
 
     if (!IndexToId(cx, obj, index, NULL, idr.addr(), JS_TRUE))
         return JS_FALSE;
     JS_ASSERT(!JSID_IS_VOID(idr.id()));
@@ -527,17 +527,17 @@ SetArrayElement(JSContext *cx, HandleObj
  *
  * - Return 0 if the deletion fails because the property is not
  *   configurable (that is, [[Delete]] would return false). Note that if
  *   |strict| is true we will throw, not return zero.
  *
  * - Return -1 if an exception occurs (that is, [[Delete]] would throw).
  */
 static int
-DeleteArrayElement(JSContext *cx, HandleObject obj, double index, bool strict)
+DeleteArrayElement(JSContext *cx, JSObject *obj, double index, bool strict)
 {
     JS_ASSERT(index >= 0);
     JS_ASSERT(floor(index) == index);
 
     if (obj->isDenseArray()) {
         if (index <= UINT32_MAX) {
             uint32_t idx = uint32_t(index);
             if (idx < obj->getDenseArrayInitializedLength()) {
@@ -562,17 +562,17 @@ DeleteArrayElement(JSContext *cx, Handle
     return v.isTrue() ? 1 : 0;
 }
 
 /*
  * When hole is true, delete the property at the given index. Otherwise set
  * its value to v assuming v is rooted.
  */
 static JSBool
-SetOrDeleteArrayElement(JSContext *cx, HandleObject obj, double index,
+SetOrDeleteArrayElement(JSContext *cx, JSObject *obj, double index,
                         JSBool hole, const Value &v)
 {
     if (hole) {
         JS_ASSERT(v.isUndefined());
         return DeleteArrayElement(cx, obj, index, true) >= 0;
     }
     return SetArrayElement(cx, obj, index, v);
 }
@@ -601,20 +601,18 @@ array_length_getter(JSContext *cx, JSObj
             vp->setNumber(obj->getArrayLength());
             return JS_TRUE;
         }
     } while ((obj = obj->getProto()) != NULL);
     return JS_TRUE;
 }
 
 static JSBool
-array_length_setter(JSContext *cx, JSObject *obj_, jsid id, JSBool strict, Value *vp)
+array_length_setter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
 {
-    RootedVarObject obj(cx, obj_);
-
     if (!obj->isArray()) {
         return obj->defineProperty(cx, cx->runtime->atomState.lengthAtom, *vp,
                                    NULL, NULL, JSPROP_ENUMERATE);
     }
 
     uint32_t newlen;
     if (!ToUint32(cx, *vp, &newlen))
         return false;
@@ -800,44 +798,32 @@ array_getProperty(JSContext *cx, JSObjec
     }
 
     if (name == cx->runtime->atomState.protoAtom) {
         vp->setObjectOrNull(obj->getProto());
         return true;
     }
 
     if (!obj->isDenseArray())
-    {
-        return js_GetProperty(cx,
-                              RootedVarObject(cx, obj),
-                              RootedVarObject(cx, receiver),
-                              ATOM_TO_JSID(name),
-                              vp);
-    }
+        return js_GetProperty(cx, obj, receiver, ATOM_TO_JSID(name), vp);
 
     JSObject *proto = obj->getProto();
     if (!proto) {
         vp->setUndefined();
         return true;
     }
 
     return proto->getProperty(cx, receiver, name, vp);
 }
 
 static JSBool
 array_getElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index, Value *vp)
 {
     if (!obj->isDenseArray())
-    {
-        return js_GetElement(cx,
-                             RootedVarObject(cx, obj),
-                             RootedVarObject(cx, receiver),
-                             index,
-                             vp);
-    }
+        return js_GetElement(cx, obj, receiver, index, vp);
 
     if (index < obj->getDenseArrayInitializedLength()) {
         *vp = obj->getDenseArrayElement(index);
         if (!vp->isMagic(JS_ARRAY_HOLE)) {
             /* Type information for dense array elements must be correct. */
             JS_ASSERT_IF(!obj->hasSingletonType(),
                          js::types::TypeHasProperty(cx, obj->type(), JSID_VOID, *vp));
 
@@ -857,21 +843,17 @@ array_getElement(JSContext *cx, JSObject
 static JSBool
 array_getSpecial(JSContext *cx, JSObject *obj, JSObject *receiver, SpecialId sid, Value *vp)
 {
     if (obj->isDenseArray() && !obj->getProto()) {
         vp->setUndefined();
         return true;
     }
 
-    return js_GetProperty(cx,
-                          RootedVarObject(cx, obj),
-                          RootedVarObject(cx, receiver),
-                          SPECIALID_TO_JSID(sid),
-                          vp);
+    return js_GetProperty(cx, obj, receiver, SPECIALID_TO_JSID(sid), vp);
 }
 
 static JSBool
 array_getGeneric(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
 {
     Value idval = IdToValue(id);
 
     uint32_t index;
@@ -907,29 +889,27 @@ slowarray_addProperty(JSContext *cx, JSO
 
 static JSType
 array_typeOf(JSContext *cx, JSObject *obj)
 {
     return JSTYPE_OBJECT;
 }
 
 static JSBool
-array_setGeneric(JSContext *cx, JSObject *obj_, jsid id_, Value *vp, JSBool strict)
+array_setGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
 {
-    RootedVarObject obj(cx, obj_);
-    RootedVarId id(cx, id_);
+    uint32_t i;
 
     if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
         return array_length_setter(cx, obj, id, strict, vp);
 
     if (!obj->isDenseArray())
         return js_SetPropertyHelper(cx, obj, id, 0, vp, strict);
 
     do {
-        uint32_t i;
         if (!js_IdIsIndex(id, &i))
             break;
         if (js_PrototypeHasIndexedProperties(cx, obj))
             break;
 
         JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, i, 1);
         if (result != JSObject::ED_OK) {
             if (result == JSObject::ED_FAILED)
@@ -939,32 +919,30 @@ array_setGeneric(JSContext *cx, JSObject
         }
 
         if (i >= obj->getArrayLength())
             obj->setDenseArrayLength(i + 1);
         obj->setDenseArrayElementWithType(cx, i, *vp);
         return true;
     } while (false);
 
-    if (!JSObject::makeDenseArraySlow(cx, obj))
+    if (!obj->makeDenseArraySlow(cx))
         return false;
     return js_SetPropertyHelper(cx, obj, id, 0, vp, strict);
 }
 
 static JSBool
 array_setProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict)
 {
     return array_setGeneric(cx, obj, ATOM_TO_JSID(name), vp, strict);
 }
 
 static JSBool
-array_setElement(JSContext *cx, JSObject *obj_, uint32_t index, Value *vp, JSBool strict)
+array_setElement(JSContext *cx, JSObject *obj, uint32_t index, Value *vp, JSBool strict)
 {
-    RootedVarObject obj(cx, obj_);
-
     jsid id;
     if (!IndexToId(cx, index, &id))
         return false;
 
     if (!obj->isDenseArray())
         return js_SetPropertyHelper(cx, obj, id, 0, vp, strict);
 
     do {
@@ -986,17 +964,17 @@ array_setElement(JSContext *cx, JSObject
         }
 
         if (index >= obj->getArrayLength())
             obj->setDenseArrayLength(index + 1);
         obj->setDenseArrayElementWithType(cx, index, *vp);
         return true;
     } while (false);
 
-    if (!JSObject::makeDenseArraySlow(cx, obj))
+    if (!obj->makeDenseArraySlow(cx))
         return false;
     return js_SetPropertyHelper(cx, obj, id, 0, vp, strict);
 }
 
 static JSBool
 array_setSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool strict)
 {
     return array_setGeneric(cx, obj, SPECIALID_TO_JSID(sid), vp, strict);
@@ -1020,21 +998,19 @@ js_PrototypeHasIndexedProperties(JSConte
             return JS_TRUE;
         if (obj->isIndexed())
             return JS_TRUE;
     }
     return JS_FALSE;
 }
 
 static JSBool
-array_defineGeneric(JSContext *cx, JSObject *obj_, jsid id, const Value *value,
+array_defineGeneric(JSContext *cx, JSObject *obj, jsid id, const Value *value,
                     JSPropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
-    RootedVarObject obj(cx, obj_);
-
     if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
         return JS_TRUE;
 
     if (!obj->isDenseArray())
         return js_DefineProperty(cx, obj, id, value, getter, setter, attrs);
 
     do {
         uint32_t i = 0;       // init to shut GCC up
@@ -1051,37 +1027,35 @@ array_defineGeneric(JSContext *cx, JSObj
         }
 
         if (i >= obj->getArrayLength())
             obj->setDenseArrayLength(i + 1);
         obj->setDenseArrayElementWithType(cx, i, *value);
         return true;
     } while (false);
 
-    if (!JSObject::makeDenseArraySlow(cx, obj))
+    if (!obj->makeDenseArraySlow(cx))
         return false;
     return js_DefineProperty(cx, obj, id, value, getter, setter, attrs);
 }
 
 static JSBool
 array_defineProperty(JSContext *cx, JSObject *obj, PropertyName *name, const Value *value,
                      JSPropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
     return array_defineGeneric(cx, obj, ATOM_TO_JSID(name), value, getter, setter, attrs);
 }
 
 namespace js {
 
 /* non-static for direct definition of array elements within the engine */
 JSBool
-array_defineElement(JSContext *cx, JSObject *obj_, uint32_t index, const Value *value,
+array_defineElement(JSContext *cx, JSObject *obj, uint32_t index, const Value *value,
                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
-    RootedVarObject obj(cx, obj_);
-
     if (!obj->isDenseArray())
         return js_DefineElement(cx, obj, index, value, getter, setter, attrs);
 
     jsid id;
     if (!IndexToId(cx, index, &id))
         return false;
 
     do {
@@ -1101,17 +1075,17 @@ array_defineElement(JSContext *cx, JSObj
         }
 
         if (index >= obj->getArrayLength())
             obj->setDenseArrayLength(index + 1);
         obj->setDenseArrayElementWithType(cx, index, *value);
         return true;
     } while (false);
 
-    if (!JSObject::makeDenseArraySlow(cx, obj))
+    if (!obj->makeDenseArraySlow(cx))
         return false;
     return js_DefineElement(cx, obj, index, value, getter, setter, attrs);
 }
 
 } // namespace js
 
 static JSBool
 array_defineSpecial(JSContext *cx, JSObject *obj, SpecialId sid, const Value *value,
@@ -1232,27 +1206,25 @@ array_trace(JSTracer *trc, JSObject *obj
 {
     JS_ASSERT(obj->isDenseArray());
 
     uint32_t initLength = obj->getDenseArrayInitializedLength();
     MarkArraySlots(trc, initLength, obj->getDenseArrayElements(), "element");
 }
 
 static JSBool
-array_fix(JSContext *cx, JSObject *obj_, bool *success, AutoIdVector *props)
+array_fix(JSContext *cx, JSObject *obj, bool *success, AutoIdVector *props)
 {
-    RootedVarObject obj(cx, obj_);
-
     JS_ASSERT(obj->isDenseArray());
 
     /*
      * We must slowify dense arrays; otherwise, we'd need to detect assignments to holes,
      * since that is effectively adding a new property to the array.
      */
-    if (!JSObject::makeDenseArraySlow(cx, obj) ||
+    if (!obj->makeDenseArraySlow(cx) ||
         !GetPropertyNames(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY, props))
         return false;
 
     *success = true;
     return true;
 }
 
 Class js::ArrayClass = {
@@ -1375,100 +1347,100 @@ AddLengthProperty(JSContext *cx, JSObjec
 
     return obj->addProperty(cx, lengthId, array_length_getter, array_length_setter,
                             SHAPE_INVALID_SLOT, JSPROP_PERMANENT | JSPROP_SHARED, 0, 0);
 }
 
 /*
  * Convert an array object from fast-and-dense to slow-and-flexible.
  */
-/* static */ bool
-JSObject::makeDenseArraySlow(JSContext *cx, HandleObject obj)
+JSBool
+JSObject::makeDenseArraySlow(JSContext *cx)
 {
-    JS_ASSERT(obj->isDenseArray());
-
-    MarkTypeObjectFlags(cx, obj,
+    JS_ASSERT(isDenseArray());
+
+    MarkTypeObjectFlags(cx, this,
                         OBJECT_FLAG_NON_PACKED_ARRAY |
                         OBJECT_FLAG_NON_DENSE_ARRAY);
 
-    uint32_t arrayCapacity = obj->getDenseArrayCapacity();
-    uint32_t arrayInitialized = obj->getDenseArrayInitializedLength();
+    uint32_t arrayCapacity = getDenseArrayCapacity();
+    uint32_t arrayInitialized = getDenseArrayInitializedLength();
 
     /*
      * Get an allocated array of the existing elements, evicting from the fixed
      * slots if necessary.
      */
-    if (!obj->hasDynamicElements()) {
-        if (!obj->growElements(cx, arrayCapacity))
+    if (!hasDynamicElements()) {
+        if (!growElements(cx, arrayCapacity))
             return false;
-        JS_ASSERT(obj->hasDynamicElements());
+        JS_ASSERT(hasDynamicElements());
     }
 
     /*
      * Save old map now, before calling InitScopeForObject. We'll have to undo
      * on error. This is gross, but a better way is not obvious. Note: the
      * exact contents of the array are not preserved on error.
      */
-    js::Shape *oldShape = obj->lastProperty();
+    js::Shape *oldShape = lastProperty();
 
     /* Create a native scope. */
-    gc::AllocKind kind = obj->getAllocKind();
-    Shape *shape = EmptyShape::getInitialShape(cx, &SlowArrayClass, obj->getProto(),
+    gc::AllocKind kind = getAllocKind();
+    Shape *shape = EmptyShape::getInitialShape(cx, &SlowArrayClass, getProto(),
                                                oldShape->getObjectParent(), kind);
     if (!shape)
         return false;
-    obj->shape_ = shape;
+    this->shape_ = shape;
 
     /* Take ownership of the dense elements, reset to an empty dense array. */
-    HeapSlot *elems = obj->elements;
-    obj->elements = emptyObjectElements;
+    HeapSlot *elems = elements;
+    elements = emptyObjectElements;
 
     /* Root all values in the array during conversion. */
     AutoValueArray autoArray(cx, (Value *) elems, arrayInitialized);
 
     /*
      * Begin with the length property to share more of the property tree.
      * The getter/setter here will directly access the object's private value.
      */
-    if (!AddLengthProperty(cx, obj)) {
-        obj->shape_ = oldShape;
-        if (obj->elements != emptyObjectElements)
-            cx->free_(obj->getElementsHeader());
-        obj->elements = elems;
+    if (!AddLengthProperty(cx, this)) {
+        this->shape_ = oldShape;
+        if (elements != emptyObjectElements)
+            cx->free_(getElementsHeader());
+        elements = elems;
         return false;
     }
 
     /*
      * Create new properties pointing to existing elements. Pack the array to
      * remove holes, so that shapes use successive slots (as for other objects).
      */
     uint32_t next = 0;
     for (uint32_t i = 0; i < arrayInitialized; i++) {
         /* Dense array indexes can always fit in a jsid. */
         jsid id;
         JS_ALWAYS_TRUE(ValueToId(cx, Int32Value(i), &id));
 
         if (elems[i].isMagic(JS_ARRAY_HOLE))
             continue;
 
-        if (!obj->addDataProperty(cx, id, next, JSPROP_ENUMERATE)) {
-            obj->shape_ = oldShape;
-            cx->free_(obj->getElementsHeader());
-            obj->elements = elems;
+        if (!addDataProperty(cx, id, next, JSPROP_ENUMERATE)) {
+            this->shape_ = oldShape;
+            cx->free_(getElementsHeader());
+            elements = elems;
             return false;
         }
 
-        obj->initSlot(next, elems[i]);
+        initSlot(next, elems[i]);
 
         next++;
     }
 
     ObjectElements *oldheader = ObjectElements::fromElements(elems);
 
-    obj->getElementsHeader()->length = oldheader->length;
+    getElementsHeader()->length = oldheader->length;
     cx->free_(oldheader);
 
     return true;
 }
 
 #if JS_HAS_TOSOURCE
 class ArraySharpDetector
 {
@@ -1729,17 +1701,17 @@ array_toString_sub(JSContext *cx, JSObje
 
 /* ES5 15.4.4.2. NB: The algorithm here differs from the one in ES3. */
 static JSBool
 array_toString(JSContext *cx, unsigned argc, Value *vp)
 {
     JS_CHECK_RECURSION(cx, return false);
 
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedVarObject obj(cx, ToObject(cx, &args.thisv()));
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
 
     Value join = args.calleev();
     if (!obj->getProperty(cx, cx->runtime->atomState.joinAtom, &join))
         return false;
 
     if (!js_IsCallable(join)) {
@@ -1803,17 +1775,17 @@ InitArrayTypes(JSContext *cx, TypeObject
 
 enum ShouldUpdateTypes
 {
     UpdateTypes = true,
     DontUpdateTypes = false
 };
 
 static bool
-InitArrayElements(JSContext *cx, HandleObject obj, uint32_t start, uint32_t count, const Value *vector, ShouldUpdateTypes updateTypes)
+InitArrayElements(JSContext *cx, JSObject *obj, uint32_t start, uint32_t count, const Value *vector, ShouldUpdateTypes updateTypes)
 {
     JS_ASSERT(count <= MAX_ARRAY_INDEX);
 
     if (count == 0)
         return true;
 
     if (updateTypes && !InitArrayTypes(cx, obj->getType(cx), vector, count))
         return false;
@@ -1852,17 +1824,17 @@ InitArrayElements(JSContext *cx, HandleO
             return false;
         }
     }
 
     if (vector == end)
         return true;
 
     /* Finish out any remaining elements past the max array index. */
-    if (obj->isDenseArray() && !JSObject::makeDenseArraySlow(cx, obj))
+    if (obj->isDenseArray() && !obj->makeDenseArraySlow(cx))
         return false;
 
     JS_ASSERT(start == MAX_ARRAY_INDEX + 1);
     AutoValueRooter tvr(cx);
     AutoIdRooter idr(cx);
     Value idval = DoubleValue(MAX_ARRAY_INDEX + 1);
     do {
         *tvr.addr() = *vector++;
@@ -1931,17 +1903,17 @@ array_join(JSContext *cx, unsigned argc,
         return false;
     return array_toString_sub(cx, obj, JS_FALSE, str, args);
 }
 
 static JSBool
 array_reverse(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedVarObject obj(cx, ToObject(cx, &args.thisv()));
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
 
     uint32_t len;
     if (!js_GetLengthProperty(cx, obj, &len))
         return false;
 
     do {
@@ -2235,17 +2207,17 @@ js::array_sort(JSContext *cx, unsigned a
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_SORT_ARG);
             return false;
         }
         fval = args[0];     /* non-default compare function */
     } else {
         fval.setNull();
     }
 
-    RootedVarObject obj(cx, ToObject(cx, &args.thisv()));
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
 
     uint32_t len;
     if (!js_GetLengthProperty(cx, obj, &len))
         return false;
     if (len == 0) {
         args.rval().setObject(*obj);
@@ -2401,43 +2373,43 @@ js::array_sort(JSContext *cx, unsigned a
     args.rval().setObject(*obj);
     return true;
 }
 
 /*
  * Perl-inspired push, pop, shift, unshift, and splice methods.
  */
 static bool
-array_push_slowly(JSContext *cx, HandleObject obj, CallArgs &args)
+array_push_slowly(JSContext *cx, JSObject *obj, CallArgs &args)
 {
     uint32_t length;
 
     if (!js_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);
 }
 
 static bool
-array_push1_dense(JSContext* cx, HandleObject obj, CallArgs &args)
+array_push1_dense(JSContext* cx, JSObject* obj, CallArgs &args)
 {
     JS_ASSERT(args.length() == 1);
 
     uint32_t length = obj->getArrayLength();
     JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, length, 1);
     if (result != JSObject::ED_OK) {
         if (result == JSObject::ED_FAILED)
             return false;
         JS_ASSERT(result == JSObject::ED_SPARSE);
-        if (!JSObject::makeDenseArraySlow(cx, obj))
+        if (!obj->makeDenseArraySlow(cx))
             return false;
         return array_push_slowly(cx, obj, args);
     }
 
     obj->setDenseArrayLength(length + 1);
     obj->setDenseArrayElementWithType(cx, length, args[0]);
     args.rval().setNumber(obj->getArrayLength());
     return true;
@@ -2473,29 +2445,29 @@ js_NewbornArrayPush(JSContext *cx, JSObj
 {
     return NewbornArrayPushImpl(cx, obj, vp);
 }
 
 JSBool
 js::array_push(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedVarObject obj(cx, ToObject(cx, &args.thisv()));
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
 
     /* Insist on one argument and obj of the expected class. */
     if (args.length() != 1 || !obj->isDenseArray())
         return array_push_slowly(cx, obj, args);
 
     return array_push1_dense(cx, obj, args);
 }
 
 static JSBool
-array_pop_slowly(JSContext *cx, HandleObject obj, CallArgs &args)
+array_pop_slowly(JSContext *cx, JSObject* obj, CallArgs &args)
 {
     uint32_t index;
     if (!js_GetLengthProperty(cx, obj, &index))
         return false;
 
     if (index == 0) {
         args.rval().setUndefined();
         return js_SetLengthProperty(cx, obj, index);
@@ -2511,17 +2483,17 @@ array_pop_slowly(JSContext *cx, HandleOb
     if (!hole && DeleteArrayElement(cx, obj, index, true) < 0)
         return false;
 
     args.rval() = elt;
     return js_SetLengthProperty(cx, obj, index);
 }
 
 static JSBool
-array_pop_dense(JSContext *cx, HandleObject obj, CallArgs &args)
+array_pop_dense(JSContext *cx, JSObject* obj, CallArgs &args)
 {
     uint32_t index = obj->getArrayLength();
     if (index == 0) {
         args.rval().setUndefined();
         return JS_TRUE;
     }
 
     index--;
@@ -2541,17 +2513,17 @@ array_pop_dense(JSContext *cx, HandleObj
     args.rval() = elt;
     return JS_TRUE;
 }
 
 JSBool
 js::array_pop(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedVarObject obj(cx, ToObject(cx, &args.thisv()));
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
     if (obj->isDenseArray())
         return array_pop_dense(cx, obj, args);
     return array_pop_slowly(cx, obj, args);
 }
 
 #ifdef JS_METHODJIT
@@ -2570,17 +2542,17 @@ mjit::stubs::ArrayShift(VMFrame &f)
     obj->moveDenseArrayElementsUnbarriered(0, 1, initlen);
 }
 #endif /* JS_METHODJIT */
 
 JSBool
 js::array_shift(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedVarObject obj(cx, ToObject(cx, &args.thisv()));
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return JS_FALSE;
 
     uint32_t length;
     if (!js_GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
 
     if (length == 0) {
@@ -2622,17 +2594,17 @@ js::array_shift(JSContext *cx, unsigned 
     }
     return js_SetLengthProperty(cx, obj, length);
 }
 
 static JSBool
 array_unshift(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedVarObject obj(cx, ToObject(cx, &args.thisv()));
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
 
     uint32_t length;
     if (!js_GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
 
     double newlen = length;
@@ -2744,17 +2716,17 @@ CanOptimizeForDenseStorage(JSObject *arr
 
 /* ES5 15.4.4.12. */
 static JSBool
 array_splice(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
-    RootedVarObject obj(cx, ToObject(cx, &args.thisv()));
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
 
     /* Steps 3-4. */
     uint32_t len;
     if (!js_GetLengthProperty(cx, obj, &len))
         return false;
 
@@ -2875,17 +2847,17 @@ array_splice(JSContext *cx, unsigned arg
         if (obj->isDenseArray()) {
             JSObject::EnsureDenseResult res =
                 obj->ensureDenseArrayElements(cx, obj->getArrayLength(),
                                               itemCount - actualDeleteCount);
             if (res == JSObject::ED_FAILED)
                 return false;
 
             if (res == JSObject::ED_SPARSE) {
-                if (!JSObject::makeDenseArraySlow(cx, obj))
+                if (!obj->makeDenseArraySlow(cx))
                     return false;
             } else {
                 JS_ASSERT(res == JSObject::ED_OK);
             }
         }
 
         if (CanOptimizeForDenseStorage(obj, len, itemCount - actualDeleteCount, cx)) {
             obj->moveDenseArrayElements(actualStart + itemCount,
@@ -2967,21 +2939,21 @@ mjit::stubs::ArrayConcatTwoArrays(VMFram
  */
 JSBool
 js::array_concat(JSContext *cx, unsigned argc, Value *vp)
 {
     /* Treat our |this| object as the first argument; see ECMA 15.4.4.4. */
     Value *p = JS_ARGV(cx, vp) - 1;
 
     /* Create a new Array object and root it using *vp. */
-    RootedVarObject aobj(cx, ToObject(cx, &vp[1]));
+    JSObject *aobj = ToObject(cx, &vp[1]);
     if (!aobj)
         return false;
 
-    RootedVarObject nobj(cx);
+    JSObject *nobj;
     uint32_t length;
     if (aobj->isDenseArray()) {
         length = aobj->getArrayLength();
         const Value *vector = aobj->getDenseArrayElements();
         uint32_t initlen = aobj->getDenseArrayInitializedLength();
         nobj = NewDenseCopiedArray(cx, initlen, vector);
         if (!nobj)
             return JS_FALSE;
@@ -3035,16 +3007,17 @@ js::array_concat(JSContext *cx, unsigned
     }
 
     return js_SetLengthProperty(cx, nobj, length);
 }
 
 static JSBool
 array_slice(JSContext *cx, unsigned argc, Value *vp)
 {
+    JSObject *nobj;
     uint32_t length, begin, end, slot;
     JSBool hole;
 
     CallArgs args = CallArgsFromVp(argc, vp);
 
     JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
@@ -3079,18 +3052,16 @@ array_slice(JSContext *cx, unsigned argc
             }
             end = (uint32_t)d;
         }
     }
 
     if (begin > end)
         begin = end;
 
-    RootedVarObject nobj(cx);
-
     if (obj->isDenseArray() && end <= obj->getDenseArrayInitializedLength() &&
         !js_PrototypeHasIndexedProperties(cx, obj)) {
         nobj = NewDenseCopiedArray(cx, end - begin, obj->getDenseArrayElements() + begin);
         if (!nobj)
             return JS_FALSE;
         TryReuseArrayType(obj, nobj);
         args.rval().setObject(*nobj);
         return JS_TRUE;
@@ -3360,17 +3331,17 @@ array_map(JSContext *cx, unsigned argc, 
     JSObject *callable = js_ValueToCallableObject(cx, &args[0], JSV2F_SEARCH_STACK);
     if (!callable)
         return false;
 
     /* Step 5. */
     Value thisv = args.length() >= 2 ? args[1] : UndefinedValue();
 
     /* Step 6. */
-    RootedVarObject arr(cx, NewDenseAllocatedArray(cx, len));
+    JSObject *arr = NewDenseAllocatedArray(cx, len);
     if (!arr)
         return false;
     TypeObject *newtype = GetTypeCallerInitObject(cx, JSProto_Array);
     if (!newtype)
         return false;
     arr->setType(newtype);
 
     /* Step 7. */
@@ -3436,17 +3407,17 @@ array_filter(JSContext *cx, unsigned arg
     JSObject *callable = js_ValueToCallableObject(cx, &args[0], JSV2F_SEARCH_STACK);
     if (!callable)
         return false;
 
     /* Step 5. */
     Value thisv = args.length() >= 2 ? args[1] : UndefinedValue();
 
     /* Step 6. */
-    RootedVarObject arr(cx, NewDenseAllocatedArray(cx, 0));
+    JSObject *arr = NewDenseAllocatedArray(cx, 0);
     if (!arr)
         return false;
     TypeObject *newtype = GetTypeCallerInitObject(cx, JSProto_Array);
     if (!newtype)
         return false;
     arr->setType(newtype);
 
     /* Step 7. */
@@ -3675,17 +3646,17 @@ static JSFunctionSpec array_static_metho
     JS_FS_END
 };
 
 /* ES5 15.4.2 */
 JSBool
 js_Array(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedVarTypeObject type(cx, GetTypeCallerInitObject(cx, JSProto_Array));
+    TypeObject *type = GetTypeCallerInitObject(cx, JSProto_Array);
     if (!type)
         return JS_FALSE;
 
     if (args.length() != 1 || !args[0].isNumber()) {
         if (!InitArrayTypes(cx, type, args.array(), args.length()))
             return false;
         JSObject *obj = (args.length() == 0)
                         ? NewDenseEmptyArray(cx)
@@ -3816,17 +3787,17 @@ NewArray(JSContext *cx, uint32_t length,
         /* Fixup the elements pointer and length, which may be incorrect. */
         obj->setFixedElements();
         obj->setArrayLength(cx, length);
         if (allocateCapacity && !EnsureNewArrayElements(cx, obj, length))
             return NULL;
         return obj;
     }
 
-    JS::Root<GlobalObject*> parentRoot(cx, &parent);
+    Root<GlobalObject*> parentRoot(cx, &parent);
 
     if (!proto && !FindProto(cx, &ArrayClass, parentRoot, &proto))
         return NULL;
 
     RootObject protoRoot(cx, &proto);
     RootedVarTypeObject type(cx);
 
     type = proto->getNewType(cx);
@@ -3909,17 +3880,17 @@ NewDenseCopiedArray(JSContext *cx, uint3
         obj->initDenseArrayElements(0, vp, length);
 
     return obj;
 }
 
 JSObject *
 NewSlowEmptyArray(JSContext *cx)
 {
-    RootedVarObject obj(cx, NewBuiltinClassInstance(cx, &SlowArrayClass));
+    JSObject *obj = NewBuiltinClassInstance(cx, &SlowArrayClass);
     if (!obj || !AddLengthProperty(cx, obj))
         return NULL;
 
     obj->setArrayLength(cx, 0);
     return obj;
 }
 
 }
--- a/js/src/jsarray.h
+++ b/js/src/jsarray.h
@@ -68,16 +68,38 @@ js_IdIsIndex(jsid id, uint32_t *indexp)
     }
 
     if (JS_UNLIKELY(!JSID_IS_STRING(id)))
         return JS_FALSE;
 
     return js::StringIsArrayIndex(JSID_TO_ATOM(id), indexp);
 }
 
+/*
+ * Dense arrays are not native -- aobj->isNative() for a dense array aobj
+ * results in false, meaning aobj->map does not point to a js::Shape.
+ *
+ * But Array methods are called via aobj.sort(), e.g., and the interpreter and
+ * the trace recorder must consult the property cache in order to perform well.
+ * The cache works only for native objects.
+ *
+ * Therefore the interpreter (js_Interpret in JSOP_GETPROP and JSOP_CALLPROP)
+ * and js_GetPropertyHelper use this inline function to skip up one link in the
+ * prototype chain when obj is a dense array, in order to find a native object
+ * (to wit, Array.prototype) in which to probe for cached methods.
+ *
+ * Note that setting aobj.__proto__ for a dense array aobj turns aobj into a
+ * slow array, avoiding the neede to skip.
+ *
+ * Callers of js_GetProtoIfDenseArray must take care to use the original object
+ * (obj) for the |this| value of a getter, setter, or method call (bug 476447).
+ */
+inline JSObject *
+js_GetProtoIfDenseArray(JSObject *obj);
+
 extern JSObject *
 js_InitArrayClass(JSContext *cx, JSObject *obj);
 
 extern bool
 js_InitContextBusyArrayTable(JSContext *cx);
 
 namespace js {
 
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -151,25 +151,24 @@ Boolean(JSContext *cx, unsigned argc, Va
     return true;
 }
 
 JSObject *
 js_InitBooleanClass(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isNative());
 
-    RootedVar<GlobalObject*> global(cx, &obj->asGlobal());
+    GlobalObject *global = &obj->asGlobal();
 
-    RootedVarObject booleanProto (cx, global->createBlankPrototype(cx, &BooleanClass));
+    JSObject *booleanProto = global->createBlankPrototype(cx, &BooleanClass);
     if (!booleanProto)
         return NULL;
     booleanProto->setFixedSlot(BooleanObject::PRIMITIVE_VALUE_SLOT, BooleanValue(false));
 
-    RootedVarFunction ctor(cx);
-    ctor = global->createConstructor(cx, Boolean, CLASS_ATOM(cx, Boolean), 1);
+    JSFunction *ctor = global->createConstructor(cx, Boolean, CLASS_ATOM(cx, Boolean), 1);
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, booleanProto))
         return NULL;
 
     if (!DefinePropertiesAndBrand(cx, booleanProto, NULL, boolean_methods))
         return NULL;
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -601,26 +601,26 @@ JSStructuredCloneWriter::startWrite(cons
 
 bool
 JSStructuredCloneWriter::write(const Value &v)
 {
     if (!startWrite(v))
         return false;
 
     while (!counts.empty()) {
-        RootedVarObject obj(context(), &objs.back().toObject());
+        JSObject *obj = &objs.back().toObject();
 
         // The objects in |obj| can live in other compartments.
         AutoEnterCompartmentAndPushPrincipal ac;
         if (!ac.enter(context(), obj))
             return false;
 
         if (counts.back()) {
             counts.back()--;
-            RootedVarId id(context(), ids.back());
+            jsid id = ids.back();
             ids.popBack();
             checkStack();
             if (JSID_IS_STRING(id) || JSID_IS_INT(id)) {
                 /*
                  * If obj still has an own property named id, write it out.
                  * The cost of re-checking could be avoided by using
                  * NativeIterators.
                  */
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -960,17 +960,17 @@ JSContext::JSContext(JSRuntime *rt)
 #ifdef DEBUG
     , stackIterAssertionEnabled(true)
 #endif
 {
     PodZero(&link);
 #ifdef JSGC_ROOT_ANALYSIS
     PodArrayZero(thingGCRooters);
 #ifdef DEBUG
-    skipGCRooters = NULL;
+    checkGCRooters = NULL;
 #endif
 #endif
 }
 
 JSContext::~JSContext()
 {
     /* Free the stuff hanging off of cx. */
     if (parseMapPool_)
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -740,16 +740,19 @@ struct JSArgumentFormatMap {
     size_t              length;
     JSArgumentFormatter formatter;
     JSArgumentFormatMap *next;
 };
 #endif
 
 namespace js {
 
+template <typename T> class Root;
+class CheckRoot;
+
 struct AutoResolving;
 
 static inline bool
 OptionsHasXML(uint32_t options)
 {
     return !!(options & JSOPTION_XML);
 }
 
@@ -1016,16 +1019,39 @@ struct JSContext : js::ContextFriendFiel
     inline js::LifoAlloc &typeLifoAlloc();
 
 #ifdef JS_THREADSAFE
     unsigned            outstandingRequests;/* number of JS_BeginRequest calls
                                                without the corresponding
                                                JS_EndRequest. */
 #endif
 
+
+#ifdef JSGC_ROOT_ANALYSIS
+
+    /*
+     * Stack allocated GC roots for stack GC heap pointers, which may be
+     * overwritten if moved during a GC.
+     */
+    js::Root<js::gc::Cell*> *thingGCRooters[js::THING_ROOT_COUNT];
+
+#ifdef DEBUG
+    /*
+     * Stack allocated list of stack locations which hold non-relocatable
+     * GC heap pointers (where the target is rooted somewhere else) or integer
+     * values which may be confused for GC heap pointers. These are used to
+     * suppress false positives which occur when a rooting analysis treats the
+     * location as holding a relocatable pointer, but have no other effect on
+     * GC behavior.
+     */
+    js::CheckRoot *checkGCRooters;
+#endif
+
+#endif /* JSGC_ROOT_ANALYSIS */
+
     /* Stored here to avoid passing it around as a parameter. */
     unsigned               resolveFlags;
 
     /* Random number generator state, used by jsmath.cpp. */
     int64_t             rngSeed;
 
     /* Location to stash the iteration value between JSOP_MOREITER and JSOP_ITERNEXT. */
     js::Value           iterValue;
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -321,17 +321,17 @@ CallJSNative(JSContext *cx, Native nativ
 
 extern JSBool CallOrConstructBoundFunction(JSContext *, unsigned, js::Value *);
 
 STATIC_PRECONDITION(ubound(args.argv_) >= argc)
 JS_ALWAYS_INLINE bool
 CallJSNativeConstructor(JSContext *cx, Native native, const CallArgs &args)
 {
 #ifdef DEBUG
-    RootedVarObject callee(cx, &args.callee());
+    JSObject &callee = args.callee();
 #endif
 
     JS_ASSERT(args.thisv().isMagic());
     if (!CallJSNative(cx, native, args))
         return false;
 
     /*
      * Native constructors must return non-primitive values on success.
@@ -346,18 +346,18 @@ CallJSNativeConstructor(JSContext *cx, N
      * CallOrConstructBoundFunction is an exception as well because we
      * might have used bind on a proxy function.
      *
      * (new Object(Object)) returns the callee.
      */
     JS_ASSERT_IF(native != FunctionProxyClass.construct &&
                  native != CallableObjectClass.construct &&
                  native != js::CallOrConstructBoundFunction &&
-                 (!callee->isFunction() || callee->toFunction()->native() != js_Object),
-                 !args.rval().isPrimitive() && callee != &args.rval().toObject());
+                 (!callee.isFunction() || callee.toFunction()->native() != js_Object),
+                 !args.rval().isPrimitive() && callee != args.rval().toObject());
 
     return true;
 }
 
 JS_ALWAYS_INLINE bool
 CallJSPropertyOp(JSContext *cx, PropertyOp op, JSObject *receiver, jsid id, Value *vp)
 {
     assertSameCompartment(cx, receiver, id, *vp);
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -497,18 +497,17 @@ msFromTime(double t)
  */
 
 static JSBool
 date_convert(JSContext *cx, JSObject *obj, JSType hint, Value *vp)
 {
     JS_ASSERT(hint == JSTYPE_NUMBER || hint == JSTYPE_STRING || hint == JSTYPE_VOID);
     JS_ASSERT(obj->isDate());
 
-    return DefaultValue(cx, RootedVarObject(cx, obj),
-                        (hint == JSTYPE_VOID) ? JSTYPE_STRING : hint, vp);
+    return DefaultValue(cx, obj, (hint == JSTYPE_VOID) ? JSTYPE_STRING : hint, vp);
 }
 
 /*
  * Other Support routines and definitions
  */
 
 Class js::DateClass = {
     js_Date_str,
@@ -2660,25 +2659,24 @@ js_Date(JSContext *cx, unsigned argc, Va
 JSObject *
 js_InitDateClass(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isNative());
 
     /* Set the static LocalTZA. */
     LocalTZA = -(PRMJ_LocalGMTDifference() * msPerSecond);
 
-    RootedVar<GlobalObject*> global(cx, &obj->asGlobal());
-
-    RootedVarObject dateProto(cx, global->createBlankPrototype(cx, &DateClass));
+    GlobalObject *global = &obj->asGlobal();
+
+    JSObject *dateProto = global->createBlankPrototype(cx, &DateClass);
     if (!dateProto)
         return NULL;
     SetDateToNaN(cx, dateProto);
 
-    RootedVarFunction ctor(cx);
-    ctor = global->createConstructor(cx, js_Date, CLASS_ATOM(cx, Date), MAXARGS);
+    JSFunction *ctor = global->createConstructor(cx, js_Date, CLASS_ATOM(cx, Date), MAXARGS);
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, dateProto))
         return NULL;
 
     if (!DefinePropertiesAndBrand(cx, ctor, NULL, date_static_methods))
         return NULL;
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -792,25 +792,23 @@ JS_PropertyIterator(JSObject *obj, JSSco
         JS_ASSERT(shape->isEmptyShape());
         shape = NULL;
     }
 
     return *iteratorp = reinterpret_cast<JSScopeProperty *>(const_cast<Shape *>(shape));
 }
 
 JS_PUBLIC_API(JSBool)
-JS_GetPropertyDesc(JSContext *cx, JSObject *obj_, JSScopeProperty *sprop,
+JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop,
                    JSPropertyDesc *pd)
 {
-    assertSameCompartment(cx, obj_);
+    assertSameCompartment(cx, obj);
     Shape *shape = (Shape *) sprop;
     pd->id = IdToJsval(shape->propid());
 
-    RootedVarObject obj(cx, obj_);
-
     JSBool wasThrowing = cx->isExceptionPending();
     Value lastException = UndefinedValue();
     if (wasThrowing)
         lastException = cx->getPendingException();
     cx->clearPendingException();
 
     if (!js_GetProperty(cx, obj, shape->propid(), &pd->value)) {
         if (!cx->isExceptionPending()) {
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -276,18 +276,18 @@ struct SuppressErrorsGuard
         JS_SetErrorReporter(cx, prevReporter);
     }
 };
 
 static void
 SetExnPrivate(JSContext *cx, JSObject *exnObject, JSExnPrivate *priv);
 
 static bool
-InitExnPrivate(JSContext *cx, HandleObject exnObject, HandleString message,
-               HandleString filename, unsigned lineno, JSErrorReport *report, int exnType)
+InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
+               JSString *filename, unsigned lineno, JSErrorReport *report, int exnType)
 {
     JS_ASSERT(exnObject->isError());
     JS_ASSERT(!exnObject->getPrivate());
 
     JSCheckAccessOp checkAccess = cx->runtime->securityCallbacks->checkObjectAccess;
 
     Vector<JSStackTraceStackElem> frames(cx);
     {
@@ -418,29 +418,27 @@ exn_finalize(FreeOp *fop, JSObject *obj)
                 JS_DropPrincipals(fop->runtime(), prin);
             fop->free_(report);
         }
         fop->free_(priv);
     }
 }
 
 static JSBool
-exn_resolve(JSContext *cx, JSObject *obj_, jsid id, unsigned flags,
+exn_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
             JSObject **objp)
 {
     JSExnPrivate *priv;
     JSString *str;
     JSAtom *atom;
     JSString *stack;
     const char *prop;
     jsval v;
     unsigned attrs;
 
-    RootedVarObject obj(cx, obj_);
-
     *objp = NULL;
     priv = GetExnPrivate(obj);
     if (priv && JSID_IS_ATOM(id)) {
         str = JSID_TO_STRING(id);
 
         atom = cx->runtime->atomState.messageAtom;
         if (str == atom) {
             prop = js_message_str;
@@ -639,38 +637,38 @@ Exception(JSContext *cx, unsigned argc, 
         return false;
 
     if (!protov.isObject()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PROTOTYPE, "Error");
         return false;
     }
 
     JSObject *errProto = &protov.toObject();
-    RootedVarObject obj(cx, NewObjectWithGivenProto(cx, &ErrorClass, errProto, NULL));
+    JSObject *obj = NewObjectWithGivenProto(cx, &ErrorClass, errProto, NULL);
     if (!obj)
         return false;
 
     /* Set the 'message' property. */
-    RootedVarString message(cx);
+    JSString *message;
     if (args.hasDefined(0)) {
         message = ToString(cx, args[0]);
         if (!message)
             return false;
         args[0].setString(message);
     } else {
         message = NULL;
     }
 
     /* Find the scripted caller. */
     FrameRegsIter iter(cx);
     while (!iter.done() && !iter.fp()->isScriptFrame())
         ++iter;
 
     /* Set the 'fileName' property. */
-    RootedVarString filename(cx);
+    JSString *filename;
     if (args.length() > 1) {
         filename = ToString(cx, args[1]);
         if (!filename)
             return false;
         args[1].setString(filename);
     } else {
         if (!iter.done()) {
             filename = FilenameToString(cx, iter.fp()->script()->filename);
@@ -715,17 +713,17 @@ exn_toString(JSContext *cx, unsigned arg
     JSObject &obj = args.thisv().toObject();
 
     /* Step 3. */
     Value nameVal;
     if (!obj.getProperty(cx, cx->runtime->atomState.nameAtom, &nameVal))
         return false;
 
     /* Step 4. */
-    RootedVarString name(cx);
+    JSString *name;
     if (nameVal.isUndefined()) {
         name = CLASS_ATOM(cx, Error);
     } else {
         name = ToString(cx, nameVal);
         if (!name)
             return false;
     }
 
@@ -868,45 +866,44 @@ JS_STATIC_ASSERT(JSProto_Error + JSEXN_I
 JS_STATIC_ASSERT(JSProto_Error + JSEXN_EVALERR      == JSProto_EvalError);
 JS_STATIC_ASSERT(JSProto_Error + JSEXN_RANGEERR     == JSProto_RangeError);
 JS_STATIC_ASSERT(JSProto_Error + JSEXN_REFERENCEERR == JSProto_ReferenceError);
 JS_STATIC_ASSERT(JSProto_Error + JSEXN_SYNTAXERR    == JSProto_SyntaxError);
 JS_STATIC_ASSERT(JSProto_Error + JSEXN_TYPEERR      == JSProto_TypeError);
 JS_STATIC_ASSERT(JSProto_Error + JSEXN_URIERR       == JSProto_URIError);
 
 static JSObject *
-InitErrorClass(JSContext *cx, Handle<GlobalObject*> global, int type, HandleObject proto)
+InitErrorClass(JSContext *cx, GlobalObject *global, int type, JSObject &proto)
 {
     JSProtoKey key = GetExceptionProtoKey(type);
-    RootedVarAtom name(cx, cx->runtime->atomState.classAtoms[key]);
-    RootedVarObject errorProto(cx, global->createBlankPrototypeInheriting(cx, &ErrorClass, *proto));
+    JSAtom *name = cx->runtime->atomState.classAtoms[key];
+    JSObject *errorProto = global->createBlankPrototypeInheriting(cx, &ErrorClass, proto);
     if (!errorProto)
         return NULL;
 
-    RootedVarValue empty(cx, StringValue(cx->runtime->emptyString));
-    RootedVarId nameId(cx, ATOM_TO_JSID(cx->runtime->atomState.nameAtom));
-    RootedVarId messageId(cx, ATOM_TO_JSID(cx->runtime->atomState.messageAtom));
-    RootedVarId fileNameId(cx, ATOM_TO_JSID(cx->runtime->atomState.fileNameAtom));
-    RootedVarId lineNumberId(cx, ATOM_TO_JSID(cx->runtime->atomState.lineNumberAtom));
+    Value empty = StringValue(cx->runtime->emptyString);
+    jsid nameId = ATOM_TO_JSID(cx->runtime->atomState.nameAtom);
+    jsid messageId = ATOM_TO_JSID(cx->runtime->atomState.messageAtom);
+    jsid fileNameId = ATOM_TO_JSID(cx->runtime->atomState.fileNameAtom);
+    jsid lineNumberId = ATOM_TO_JSID(cx->runtime->atomState.lineNumberAtom);
     if (!DefineNativeProperty(cx, errorProto, nameId, StringValue(name),
                               JS_PropertyStub, JS_StrictPropertyStub, 0, 0, 0) ||
         !DefineNativeProperty(cx, errorProto, messageId, empty,
                               JS_PropertyStub, JS_StrictPropertyStub, 0, 0, 0) ||
         !DefineNativeProperty(cx, errorProto, fileNameId, empty,
                               JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE, 0, 0) ||
         !DefineNativeProperty(cx, errorProto, lineNumberId, Int32Value(0),
                               JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE, 0, 0))
     {
         return NULL;
     }
 
     /* Create the corresponding constructor. */
-    RootedVarFunction ctor(cx);
-    ctor = global->createConstructor(cx, Exception, name, 1,
-                                     JSFunction::ExtendedFinalizeKind);
+    JSFunction *ctor = global->createConstructor(cx, Exception, name, 1,
+                                                 JSFunction::ExtendedFinalizeKind);
     if (!ctor)
         return NULL;
     ctor->setExtendedSlot(0, Int32Value(int32_t(type)));
 
     if (!LinkConstructorAndPrototype(cx, ctor, errorProto))
         return NULL;
 
     if (!DefineConstructorAndPrototype(cx, global, key, ctor, errorProto))
@@ -918,35 +915,34 @@ InitErrorClass(JSContext *cx, Handle<Glo
 }
 
 JSObject *
 js_InitExceptionClasses(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isGlobal());
     JS_ASSERT(obj->isNative());
 
-    RootedVar<GlobalObject*> global(cx, &obj->asGlobal());
+    GlobalObject *global = &obj->asGlobal();
 
-    RootedVarObject objectProto(cx, global->getOrCreateObjectPrototype(cx));
+    JSObject *objectProto = global->getOrCreateObjectPrototype(cx);
     if (!objectProto)
         return NULL;
 
     /* Initialize the base Error class first. */
-    RootedVarObject errorProto(cx);
-    errorProto = InitErrorClass(cx, global, JSEXN_ERR, objectProto);
+    JSObject *errorProto = InitErrorClass(cx, global, JSEXN_ERR, *objectProto);
     if (!errorProto)
         return NULL;
 
     /* |Error.prototype| alone has method properties. */
     if (!DefinePropertiesAndBrand(cx, errorProto, NULL, exception_methods))
         return NULL;
 
     /* Define all remaining *Error constructors. */
     for (int i = JSEXN_ERR + 1; i < JSEXN_LIMIT; i++) {
-        if (!InitErrorClass(cx, global, i, errorProto))
+        if (!InitErrorClass(cx, global, i, *errorProto))
             return NULL;
     }
 
     return errorProto;
 }
 
 const JSErrorFormatString*
 js_GetLocalizedErrorMessage(JSContext* cx, void *userRef, const char *locale,
@@ -989,43 +985,26 @@ GetErrorTypeNameFromNumber(JSContext* cx
 static struct exnname { char *name; char *exception; } errortoexnname[] = {
 #define MSG_DEF(name, number, count, exception, format) \
     {#name, #exception},
 #include "js.msg"
 #undef MSG_DEF
 };
 #endif /* DEBUG */
 
-struct AutoSetGeneratingError
-{
-    JSContext *cx;
-
-    AutoSetGeneratingError(JSContext *cx)
-        : cx(cx)
-    {
-        JS_ASSERT(!cx->generatingError);
-        cx->generatingError = true;
-    }
-
-    ~AutoSetGeneratingError()
-    {
-        JS_ASSERT(cx->generatingError);
-        cx->generatingError = false;
-    }
-};
-
 JSBool
 js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp,
                     JSErrorCallback callback, void *userRef)
 {
     JSErrNum errorNumber;
     const JSErrorFormatString *errorString;
     JSExnType exn;
     jsval tv[4];
-    JSObject *errProto;
+    JSObject *errProto, *errObject;
+    JSString *messageStr, *filenameStr;
 
     /*
      * Tell our caller to report immediately if this report is just a warning.
      */
     JS_ASSERT(reportp);
     if (JSREPORT_IS_WARNING(reportp->flags))
         return false;
 
@@ -1065,28 +1044,25 @@ js_ErrorToException(JSContext *cx, const
      * Try to get an appropriate prototype by looking up the corresponding
      * exception constructor name in the scope chain of the current context's
      * top stack frame, or in the global object if no frame is active.
      */
     if (!js_GetClassPrototype(cx, NULL, GetExceptionProtoKey(exn), &errProto))
         return false;
     tv[0] = OBJECT_TO_JSVAL(errProto);
 
-    RootedVarObject errObject(cx, NewObjectWithGivenProto(cx, &ErrorClass, errProto, NULL));
-    if (!errObject)
+    if (!(errObject = NewObjectWithGivenProto(cx, &ErrorClass, errProto, NULL)))
         return false;
     tv[1] = OBJECT_TO_JSVAL(errObject);
 
-    RootedVarString messageStr(cx, JS_NewStringCopyZ(cx, message));
-    if (!messageStr)
+    if (!(messageStr = JS_NewStringCopyZ(cx, message)))
         return false;
     tv[2] = STRING_TO_JSVAL(messageStr);
 
-    RootedVarString filenameStr(cx, JS_NewStringCopyZ(cx, reportp->filename));
-    if (!filenameStr)
+    if (!(filenameStr = JS_NewStringCopyZ(cx, reportp->filename)))
         return false;
     tv[3] = STRING_TO_JSVAL(filenameStr);
 
     if (!InitExnPrivate(cx, errObject, messageStr, filenameStr,
                         reportp->lineno, reportp, exn)) {
         return false;
     }
 
@@ -1117,26 +1093,26 @@ IsDuckTypedErrorObject(JSContext *cx, JS
 
     *filename_strp = filename_str;
     return true;
 }
 
 JSBool
 js_ReportUncaughtException(JSContext *cx)
 {
+    jsval exn;
     JSObject *exnObject;
     jsval roots[6];
     JSErrorReport *reportp, report;
     JSString *str;
 
     if (!JS_IsExceptionPending(cx))
         return true;
 
-    RootedVarValue exn(cx);
-    if (!JS_GetPendingException(cx, exn.address()))
+    if (!JS_GetPendingException(cx, &exn))
         return false;
 
     PodArrayZero(roots);
     AutoArrayRooter tvr(cx, ArrayLength(roots), roots);
 
     /*
      * Because ToString below could error and an exception object could become
      * unrooted, we must root exnObject.  Later, if exnObject is non-null, we
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -184,16 +184,27 @@ JS_DefineFunctionsWithHelp(JSContext *cx
 #endif
 
 JS_END_EXTERN_C
 
 #ifdef __cplusplus
 
 namespace js {
 
+struct ContextFriendFields {
+    JSRuntime *const    runtime;
+
+    ContextFriendFields(JSRuntime *rt)
+      : runtime(rt) { }
+
+    static const ContextFriendFields *get(const JSContext *cx) {
+        return reinterpret_cast<const ContextFriendFields *>(cx);
+    }
+};
+
 struct RuntimeFriendFields {
     /*
      * If non-zero, we were been asked to call the operation callback as soon
      * as possible.
      */
     volatile int32_t    interrupt;
 
     /* Limit pointer for checking native stack consumption. */
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -239,17 +239,17 @@ fun_enumerate(JSContext *cx, JSObject *o
         if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED))
             return false;
     }
 
     return true;
 }
 
 static JSObject *
-ResolveInterpretedFunctionPrototype(JSContext *cx, HandleObject obj)
+ResolveInterpretedFunctionPrototype(JSContext *cx, JSObject *obj)
 {
 #ifdef DEBUG
     JSFunction *fun = obj->toFunction();
     JS_ASSERT(fun->isInterpreted());
     JS_ASSERT(!fun->isFunctionPrototype());
 #endif
 
     /*
@@ -262,17 +262,17 @@ 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;
-    RootedVarObject proto(cx, NewObjectWithGivenProto(cx, &ObjectClass, objProto, NULL));
+    JSObject *proto = NewObjectWithGivenProto(cx, &ObjectClass, objProto, NULL);
     if (!proto || !proto->setSingletonType(cx))
         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.
@@ -1073,17 +1073,17 @@ Function(JSContext *cx, unsigned argc, V
                 /*
                  * Check that it's a name.  This also implicitly guards against
                  * TOK_ERROR, which was already reported.
                  */
                 if (tt != TOK_NAME)
                     return OnBadFormal(cx, tt);
 
                 /* Check for a duplicate parameter name. */
-                RootedVar<PropertyName*> name(cx, ts.currentToken().name());
+                PropertyName *name = ts.currentToken().name();
                 if (bindings.hasBinding(cx, name)) {
                     JSAutoByteString bytes;
                     if (!js_AtomToPrintableString(cx, name, &bytes))
                         return false;
                     if (!ReportCompileErrorNumber(cx, &ts, NULL,
                                                   JSREPORT_WARNING | JSREPORT_STRICT,
                                                   JSMSG_DUPLICATE_FORMAL, bytes.ptr()))
                     {
@@ -1145,51 +1145,48 @@ Function(JSContext *cx, unsigned argc, V
 
 bool
 IsBuiltinFunctionConstructor(JSFunction *fun)
 {
     return fun->maybeNative() == Function;
 }
 
 const Shape *
-LookupInterpretedFunctionPrototype(JSContext *cx, RootedVarObject funobj)
+LookupInterpretedFunctionPrototype(JSContext *cx, JSObject *funobj)
 {
 #ifdef DEBUG
     JSFunction *fun = funobj->toFunction();
     JS_ASSERT(fun->isInterpreted());
     JS_ASSERT(!fun->isFunctionPrototype());
     JS_ASSERT(!funobj->isBoundFunction());
 #endif
 
     jsid id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
-    RootedVar<const Shape*> shape(cx, funobj->nativeLookup(cx, id));
+    const Shape *shape = funobj->nativeLookup(cx, id);
     if (!shape) {
         if (!ResolveInterpretedFunctionPrototype(cx, funobj))
             return NULL;
-        id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
         shape = funobj->nativeLookup(cx, id);
     }
     JS_ASSERT(!shape->configurable());
     JS_ASSERT(shape->isDataDescriptor());
     JS_ASSERT(shape->hasSlot());
     return shape;
 }
 
 } /* namespace js */
 
 JSFunction *
 js_NewFunction(JSContext *cx, JSObject *funobj, Native native, unsigned nargs,
-               unsigned flags, HandleObject parent, JSAtom *atom_, js::gc::AllocKind kind)
+               unsigned flags, HandleObject parent, JSAtom *atom, js::gc::AllocKind kind)
 {
     JS_ASSERT(kind == JSFunction::FinalizeKind || kind == JSFunction::ExtendedFinalizeKind);
     JS_ASSERT(sizeof(JSFunction) <= gc::Arena::thingSize(JSFunction::FinalizeKind));
     JS_ASSERT(sizeof(FunctionExtended) <= gc::Arena::thingSize(JSFunction::ExtendedFinalizeKind));
 
-    RootedVarAtom atom(cx, atom_);
-
     JSFunction *fun;
 
     if (funobj) {
         JS_ASSERT(funobj->isFunction());
         JS_ASSERT(funobj->getParent() == parent);
     } else {
         funobj = NewObjectWithClassProto(cx, &FunctionClass, NULL, SkipScopeParent(parent), kind);
         if (!funobj)
@@ -1216,18 +1213,18 @@ js_NewFunction(JSContext *cx, JSObject *
 
     if (native && !fun->setSingletonType(cx))
         return NULL;
 
     return fun;
 }
 
 JSFunction * JS_FASTCALL
-js_CloneFunctionObject(JSContext *cx, HandleFunction fun, HandleObject parent,
-                       HandleObject proto, gc::AllocKind kind)
+js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
+                       JSObject *proto, gc::AllocKind kind)
 {
     JS_ASSERT(parent);
     JS_ASSERT(proto);
 
     JSObject *cloneobj = NewObjectWithClassProto(cx, &FunctionClass, NULL, SkipScopeParent(parent), kind);
     if (!cloneobj)
         return NULL;
     JSFunction *clone = static_cast<JSFunction *>(cloneobj);
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -240,18 +240,17 @@ extern JSString *
 fun_toStringHelper(JSContext *cx, JSObject *obj, unsigned indent);
 
 extern JSFunction *
 js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, unsigned nargs,
                unsigned flags, js::HandleObject parent, JSAtom *atom,
                js::gc::AllocKind kind = JSFunction::FinalizeKind);
 
 extern JSFunction * JS_FASTCALL
-js_CloneFunctionObject(JSContext *cx, js::HandleFunction fun,
-                       js::HandleObject parent, js::HandleObject proto,
+js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent, JSObject *proto,
                        js::gc::AllocKind kind = JSFunction::FinalizeKind);
 
 extern JSFunction *
 js_DefineFunction(JSContext *cx, js::HandleObject obj, jsid id, JSNative native,
                   unsigned nargs, unsigned flags,
                   js::gc::AllocKind kind = JSFunction::FinalizeKind);
 
 /*
--- a/js/src/jsfuninlines.h
+++ b/js/src/jsfuninlines.h
@@ -140,23 +140,23 @@ IsNativeFunction(const js::Value &v, JSN
  * When we have an object of a builtin class, we don't quite know what its
  * valueOf/toString methods are, since these methods may have been overwritten
  * or shadowed. However, we can still do better than the general case by
  * hard-coding the necessary properties for us to find the native we expect.
  *
  * TODO: a per-thread shape-based cache would be faster and simpler.
  */
 static JS_ALWAYS_INLINE bool
-ClassMethodIsNative(JSContext *cx, HandleObject obj, Class *clasp, HandleId methodid, JSNative native)
+ClassMethodIsNative(JSContext *cx, JSObject *obj, Class *clasp, jsid methodid, JSNative native)
 {
     JS_ASSERT(obj->getClass() == clasp);
 
     Value v;
     if (!HasDataProperty(cx, obj, methodid, &v)) {
-        RootedVarObject proto(cx, obj->getProto());
+        JSObject *proto = obj->getProto();
         if (!proto || proto->getClass() != clasp || !HasDataProperty(cx, proto, methodid, &v))
             return false;
     }
 
     return js::IsNativeFunction(v, native);
 }
 
 extern JS_ALWAYS_INLINE bool
@@ -200,40 +200,55 @@ GetFunctionNameBytes(JSContext *cx, JSFu
 extern JSFunctionSpec function_methods[];
 
 extern JSBool
 Function(JSContext *cx, unsigned argc, Value *vp);
 
 extern bool
 IsBuiltinFunctionConstructor(JSFunction *fun);
 
+/*
+ * Preconditions: funobj->isInterpreted() && !funobj->isFunctionPrototype() &&
+ * !funobj->isBoundFunction(). This is sufficient to establish that funobj has
+ * a non-configurable non-method .prototype data property, thought it might not
+ * have been resolved yet, and its value could be anything.
+ *
+ * Return the shape of the .prototype property of funobj, resolving it if
+ * needed. On error, return NULL.
+ *
+ * This is not safe to call on trace because it defines properties, which can
+ * trigger lookups that could reenter.
+ */
+const Shape *
+LookupInterpretedFunctionPrototype(JSContext *cx, JSObject *funobj);
+
 static inline JSObject *
 SkipScopeParent(JSObject *parent)
 {
     if (!parent)
         return NULL;
     while (parent->isScope())
         parent = &parent->asScope().enclosingScope();
     return parent;
 }
 
 inline JSFunction *
-CloneFunctionObject(JSContext *cx, HandleFunction fun, HandleObject parent,
+CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
                     gc::AllocKind kind = JSFunction::FinalizeKind)
 {
     JS_ASSERT(parent);
-    RootedVarObject proto(cx, parent->global().getOrCreateFunctionPrototype(cx));
+    JSObject *proto = parent->global().getOrCreateFunctionPrototype(cx);
     if (!proto)
         return NULL;
 
     return js_CloneFunctionObject(cx, fun, parent, proto, kind);
 }
 
 inline JSFunction *
-CloneFunctionObjectIfNotSingleton(JSContext *cx, HandleFunction fun, HandleObject parent)
+CloneFunctionObjectIfNotSingleton(JSContext *cx, JSFunction *fun, JSObject *parent)
 {
     /*
      * For attempts to clone functions at a function definition opcode,
      * don't perform the clone if the function has singleton type. This
      * was called pessimistically, and we need to preserve the type's
      * property that if it is singleton there is only a single object
      * with its type in existence.
      */
@@ -243,33 +258,31 @@ CloneFunctionObjectIfNotSingleton(JSCont
         fun->setEnvironment(parent);
         return fun;
     }
 
     return CloneFunctionObject(cx, fun, parent);
 }
 
 inline JSFunction *
-CloneFunctionObject(JSContext *cx, HandleFunction fun)
+CloneFunctionObject(JSContext *cx, JSFunction *fun)
 {
     /*
      * Variant which makes an exact clone of fun, preserving parent and proto.
      * Calling the above version CloneFunctionObject(cx, fun, fun->getParent())
      * is not equivalent: API clients, including XPConnect, can reparent
      * objects so that fun->global() != fun->getProto()->global().
      * See ReparentWrapperIfFound.
      */
     JS_ASSERT(fun->getParent() && fun->getProto());
 
     if (fun->hasSingletonType())
         return fun;
 
-    return js_CloneFunctionObject(cx, fun,
-                                  RootedVarObject(cx, fun->environment()),
-                                  RootedVarObject(cx, fun->getProto()),
+    return js_CloneFunctionObject(cx, fun, fun->environment(), fun->getProto(),
                                   JSFunction::ExtendedFinalizeKind);
 }
 
 } /* namespace js */
 
 inline void
 JSFunction::setScript(JSScript *script_)
 {
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -3944,37 +3944,35 @@ SetDeterministicGC(JSContext *cx, bool e
 static void
 CheckStackRoot(JSTracer *trc, uintptr_t *w)
 {
     /* Mark memory as defined for valgrind, as in MarkWordConservatively. */
 #ifdef JS_VALGRIND
     VALGRIND_MAKE_MEM_DEFINED(&w, sizeof(w));
 #endif
 
-    ConservativeGCTest test = MarkIfGCThingWord(trc, *w);
+    ConservativeGCTest test = MarkIfGCThingWord(trc, *w, DONT_MARK_THING);
 
     if (test == CGCT_VALID) {
         JSContext *iter = NULL;
         bool matched = false;
         JSRuntime *rt = trc->runtime;
-        for (ContextIter cx(rt); !cx.done(); cx.next()) {
-            for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) {
-                Root<void*> *rooter = cx->thingGCRooters[i];
-                while (rooter) {
-                    if (rooter->address() == static_cast<void*>(w))
-                        matched = true;
-                    rooter = rooter->previous();
-                }
+        for (unsigned i = 0; i < THING_ROOT_COUNT; i++) {
+            Root<Cell*> *rooter = rt->thingGCRooters[i];
+            while (rooter) {
+                if (rooter->address() == (Cell **) w)
+                    matched = true;
+                rooter = rooter->previous();
             }
-            SkipRoot *skip = cx->skipGCRooters;
-            while (skip) {
-                if (skip->contains(reinterpret_cast<uint8_t*>(w), sizeof(w)))
-                    matched = true;
-                skip = skip->previous();
-            }
+        }
+        CheckRoot *check = rt->checkGCRooters;
+        while (check) {
+            if (check->contains(static_cast<uint8_t*>(w), sizeof(w)))
+                matched = true;
+            check = check->previous();
         }
         if (!matched) {
             /*
              * Only poison the last byte in the word. It is easy to get
              * accidental collisions when a value that does not occupy a full
              * word is used to overwrite a now-dead GC thing pointer. In this
              * case we want to avoid damaging the smaller value.
              */
@@ -4002,27 +4000,27 @@ CheckStackRoots(JSContext *cx)
     ThreadData *td = JS_THREAD_DATA(cx);
 
     ConservativeGCThreadData *ctd = &td->conservativeGC;
     ctd->recordStackTop();
 
     JS_ASSERT(ctd->hasStackToScan());
     uintptr_t *stackMin, *stackEnd;
 #if JS_STACK_GROWTH_DIRECTION > 0
-    stackMin = rt->nativeStackBase;
-    stackEnd = cgcd->nativeStackTop;
+    stackMin = td->nativeStackBase;
+    stackEnd = ctd->nativeStackTop;
 #else
-    stackMin = cgcd->nativeStackTop + 1;
-    stackEnd = reinterpret_cast<uintptr_t *>(rt->nativeStackBase);
+    stackMin = ctd->nativeStackTop + 1;
+    stackEnd = td->nativeStackBase;
 #endif
 
     JS_ASSERT(stackMin <= stackEnd);
     CheckStackRootsRange(&checker, stackMin, stackEnd);
-    CheckStackRootsRange(&checker, cgcd->registerSnapshot.words,
-                         ArrayEnd(cgcd->registerSnapshot.words));
+    CheckStackRootsRange(&checker, ctd->registerSnapshot.words,
+                         ArrayEnd(ctd->registerSnapshot.words));
 }
 
 #endif /* DEBUG && JSGC_ROOT_ANALYSIS && !JS_THREADSAFE */
 
 #ifdef JS_GC_ZEAL
 
 /*
  * Write barrier verification
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -1692,31 +1692,30 @@ public:
         if (source->isOwnProperty(configurable)) {
             updated = true;
             cx->compartment->types.addPendingRecompile(cx, info);
         }
     }
 };
 
 static void
-CheckNewScriptProperties(JSContext *cx, HandleTypeObject type, JSFunction *fun);
+CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun);
 
 bool
 TypeSet::isOwnProperty(JSContext *cx, TypeObject *object, bool configurable)
 {
     /*
      * Everywhere compiled code depends on definite properties associated with
      * a type object's newScript, we need to make sure there are constraints
      * in place which will mark those properties as configured should the
      * definite properties be invalidated.
      */
     if (object->flags & OBJECT_FLAG_NEW_SCRIPT_REGENERATE) {
         if (object->newScript) {
-            CheckNewScriptProperties(cx, RootedVarTypeObject(cx, object),
-                                     object->newScript->fun);
+            CheckNewScriptProperties(cx, object, object->newScript->fun);
         } else {
             JS_ASSERT(object->flags & OBJECT_FLAG_NEW_SCRIPT_CLEARED);
             object->flags &= ~OBJECT_FLAG_NEW_SCRIPT_REGENERATE;
         }
     }
 
     if (isOwnProperty(configurable))
         return true;
@@ -4378,17 +4377,17 @@ AnalyzeNewScriptProperties(JSContext *cx
         /* Only handle 'this' values popped in unconditional code. */
         Bytecode *poppedCode = analysis->maybeCode(uses->offset);
         if (!poppedCode || !poppedCode->unconditional)
             return false;
 
         pc = script->code + uses->offset;
         op = JSOp(*pc);
 
-        RootedVarObject obj(cx, *pbaseobj);
+        JSObject *obj = *pbaseobj;
 
         if (op == JSOP_SETPROP && uses->u.which == 1) {
             /*
              * Don't use GetAtomId here, we need to watch for SETPROP on
              * integer properties and bail out. We can't mark the aggregate
              * JSID_VOID type property as being in a definite slot.
              */
             jsid id = ATOM_TO_JSID(script->getAtom(GET_UINT32_INDEX(pc)));
@@ -4528,32 +4527,31 @@ AnalyzeNewScriptProperties(JSContext *cx
 }
 
 /*
  * Either make the newScript information for type when it is constructed
  * by the specified script, or regenerate the constraints for an existing
  * newScript on the type after they were cleared by a GC.
  */
 static void
-CheckNewScriptProperties(JSContext *cx, HandleTypeObject type, JSFunction *fun)
+CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun)
 {
     if (type->unknownProperties() || fun->script()->isInnerFunction)
         return;
 
     /* Strawman object to add properties to and watch for duplicates. */
-    RootedVarObject baseobj(cx);
-    baseobj = NewBuiltinClassInstance(cx, &ObjectClass, gc::FINALIZE_OBJECT16);
+    JSObject *baseobj = NewBuiltinClassInstance(cx, &ObjectClass, gc::FINALIZE_OBJECT16);
     if (!baseobj) {
         if (type->newScript)
             type->clearNewScript(cx);
         return;
     }
 
     Vector<TypeNewScript::Initializer> initializerList(cx);
-    AnalyzeNewScriptProperties(cx, type, fun, baseobj.address(), &initializerList);
+    AnalyzeNewScriptProperties(cx, type, fun, &baseobj, &initializerList);
     if (!baseobj || baseobj->slotSpan() == 0 || !!(type->flags & OBJECT_FLAG_NEW_SCRIPT_CLEARED)) {
         if (type->newScript)
             type->clearNewScript(cx);
         return;
     }
 
     /*
      * If the type already has a new script, we are just regenerating the type
@@ -5362,22 +5360,20 @@ JSScript::makeAnalysis(JSContext *cx)
 
     AutoEnterAnalysis enter(cx);
 
     types->analysis = cx->typeLifoAlloc().new_<ScriptAnalysis>(this);
 
     if (!types->analysis)
         return false;
 
-    RootedVar<JSScript*> self(cx, this);
-
     types->analysis->analyzeBytecode(cx);
 
-    if (self->types->analysis->OOM()) {
-        self->types->analysis = NULL;
+    if (types->analysis->OOM()) {
+        types->analysis = NULL;
         return false;
     }
 
     return true;
 }
 
 bool
 JSScript::typeSetFunction(JSContext *cx, JSFunction *fun, bool singleton)
@@ -5653,22 +5649,22 @@ JSObject::getNewType(JSContext *cx, JSFu
 
     RootedVarObject self(cx, this);
 
     if (!setDelegate(cx))
         return NULL;
 
     bool markUnknown = self->lastProperty()->hasObjectFlag(BaseShape::NEW_TYPE_UNKNOWN);
 
-    RootedVarTypeObject type(cx);
-    type = cx->compartment->types.newTypeObject(cx, NULL, JSProto_Object, self, markUnknown);
+    TypeObject *type = cx->compartment->types.newTypeObject(cx, NULL,
+                                                            JSProto_Object, self, markUnknown);
     if (!type)
         return NULL;
 
-    if (!table.relookupOrAdd(p, self, type.raw()))
+    if (!table.relookupOrAdd(p, self, type))
         return NULL;
 
     if (!cx->typeInferenceEnabled())
         return type;
 
     AutoEnterTypeInference enter(cx);
 
     /*
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -1422,21 +1422,21 @@ JSScript::ensureHasTypes(JSContext *cx)
 {
     return types || makeTypes(cx);
 }
 
 inline bool
 JSScript::ensureRanAnalysis(JSContext *cx, JSObject *scope)
 {
     JSScript *self = this;
-    JS::SkipRoot root(cx, &self);
 
     if (!self->ensureHasTypes(cx))
         return false;
     if (!self->types->hasScope()) {
+        js::CheckRoot root(cx, &self);
         js::RootObject objRoot(cx, &scope);
         if (!js::types::TypeScript::SetScope(cx, self, scope))
             return false;
     }
     if (!self->hasAnalysis() && !self->makeAnalysis(cx))
         return false;
     JS_ASSERT(self->analysis()->ranBytecode());
     return true;
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -203,46 +203,46 @@ js::GetScopeChain(JSContext *cx, StackFr
     }
 
     /*
      * Special-case cloning the innermost block; this doesn't have enough in
      * common with subsequent steps to include in the loop.
      *
      * create() leaves the clone's enclosingScope unset. We set it below.
      */
-    RootedVar<ClonedBlockObject *> innermostNewChild(cx);
-    innermostNewChild = ClonedBlockObject::create(cx, *sharedBlock, fp);
+    ClonedBlockObject *innermostNewChild = ClonedBlockObject::create(cx, *sharedBlock, fp);
     if (!innermostNewChild)
         return NULL;
 
     /*
      * Clone our way towards outer scopes until we reach the innermost
      * enclosing function, or the innermost block we've already cloned.
      */
-    RootedVar<ClonedBlockObject *> newChild(cx, innermostNewChild);
+    ClonedBlockObject *newChild = innermostNewChild;
     for (;;) {
         JS_ASSERT(newChild->getProto() == sharedBlock);
         sharedBlock = sharedBlock->enclosingBlock();
 
         /* Sometimes limitBlock will be NULL, so check that first.  */
         if (sharedBlock == limitBlock || !sharedBlock)
             break;
 
         /* As in the call above, we don't know the real parent yet.  */
-        RootedVar<ClonedBlockObject *> clone(cx, ClonedBlockObject::create(cx, *sharedBlock, fp));
+        ClonedBlockObject *clone = ClonedBlockObject::create(cx, *sharedBlock, fp);
         if (!clone)
             return NULL;
 
-        if (!newChild->setEnclosingScope(cx, clone))
+        if (!newChild->setEnclosingScope(cx, *clone))
             return NULL;
         newChild = clone;
     }
-    if (!newChild->setEnclosingScope(cx, RootedVarObject(cx, &fp->scopeChain())))
+    if (!newChild->setEnclosingScope(cx, fp->scopeChain()))
         return NULL;
 
+
     /*
      * If we found a limit block belonging to this frame, then we should have
      * found it in blockChain.
      */
     JS_ASSERT_IF(limitBlock &&
                  limitBlock->isClonedBlock() &&
                  limitClone->getPrivate() == js_FloatingFrameIfGenerator(cx, fp),
                  sharedBlock);
@@ -360,37 +360,37 @@ Class js_NoSuchMethodClass = {
  *
  *   this.__noSuchMethod__(id, args)
  *
  * where id is the name of the method that this invocation attempted to
  * call by name, and args is an Array containing this invocation's actual
  * parameters.
  */
 bool
-js::OnUnknownMethod(JSContext *cx, HandleObject obj, Value idval, Value *vp)
+js::OnUnknownMethod(JSContext *cx, JSObject *obj, Value idval, Value *vp)
 {
     jsid id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom);
     AutoValueRooter tvr(cx);
     if (!js_GetMethod(cx, obj, id, 0, tvr.addr()))
         return false;
     TypeScript::MonitorUnknown(cx, cx->fp()->script(), cx->regs().pc);
 
     if (tvr.value().isPrimitive()) {
         *vp = tvr.value();
     } else {
 #if JS_HAS_XML_SUPPORT
         /* Extract the function name from function::name qname. */
         if (idval.isObject()) {
-            JSObject *obj = &idval.toObject();
+            obj = &idval.toObject();
             if (js_GetLocalNameFromFunctionQName(obj, &id, cx))
                 idval = IdToValue(id);
         }
 #endif
 
-        JSObject *obj = NewObjectWithClassProto(cx, &js_NoSuchMethodClass, NULL, NULL);
+        obj = NewObjectWithClassProto(cx, &js_NoSuchMethodClass, NULL, NULL);
         if (!obj)
             return false;
 
         obj->setSlot(JSSLOT_FOUND_FUNCTION, tvr.value());
         obj->setSlot(JSSLOT_SAVED_ID, idval);
         vp->setObject(*obj);
     }
     return true;
@@ -639,17 +639,17 @@ js::InvokeGetterOrSetter(JSContext *cx, 
 }
 
 bool
 js::ExecuteKernel(JSContext *cx, JSScript *script, JSObject &scopeChain, const Value &thisv,
                   ExecuteType type, StackFrame *evalInFrame, Value *result)
 {
     JS_ASSERT_IF(evalInFrame, type == EXECUTE_DEBUG);
 
-    JS::Root<JSScript*> scriptRoot(cx, &script);
+    Root<JSScript*> scriptRoot(cx, &script);
 
     if (script->isEmpty()) {
         if (result)
             result->setUndefined();
         return true;
     }
 
     ExecuteFrameGuard efg;
@@ -919,31 +919,31 @@ js::ValueToId(JSContext *cx, const Value
 static bool
 EnterWith(JSContext *cx, int stackIndex)
 {
     StackFrame *fp = cx->fp();
     Value *sp = cx->regs().sp;
     JS_ASSERT(stackIndex < 0);
     JS_ASSERT(fp->base() <= sp + stackIndex);
 
-    RootedVarObject obj(cx);
+    JSObject *obj;
     if (sp[-1].isObject()) {
         obj = &sp[-1].toObject();
     } else {
         obj = js_ValueToNonNullObject(cx, sp[-1]);
         if (!obj)
             return JS_FALSE;
         sp[-1].setObject(*obj);
     }
 
-    RootedVarObject parent(cx, GetScopeChain(cx, fp));
+    JSObject *parent = GetScopeChain(cx, fp);
     if (!parent)
         return JS_FALSE;
 
-    JSObject *withobj = WithObject::create(cx, fp, obj, parent,
+    JSObject *withobj = WithObject::create(cx, fp, *obj, *parent,
                                            sp + stackIndex - fp->base());
     if (!withobj)
         return JS_FALSE;
 
     fp->setScopeChainNoCallObj(*withobj);
     return JS_TRUE;
 }
 
@@ -1217,30 +1217,29 @@ inline InterpreterFrames::InterpreterFra
     cx->runtime->interpreterFrames = this;
 }
  
 inline InterpreterFrames::~InterpreterFrames()
 {
     context->runtime->interpreterFrames = older;
 }
 
-#if defined(DEBUG) && !defined(JS_THREADSAFE) && !defined(JSGC_ROOT_ANALYSIS)
+#if defined(DEBUG) && !defined(JS_THREADSAFE)
 void
 js::AssertValidPropertyCacheHit(JSContext *cx,
-                                JSObject *start_, JSObject *found,
+                                JSObject *start, JSObject *found,
                                 PropertyCacheEntry *entry)
 {
     jsbytecode *pc;
     cx->stack.currentScript(&pc);
 
     uint64_t sample = cx->runtime->gcNumber;
     PropertyCacheEntry savedEntry = *entry;
 
-    RootedVarPropertyName name(cx, GetNameFromBytecode(cx, pc, JSOp(*pc), js_CodeSpec[*pc]));
-    RootedVarObject start(cx, start_);
+    PropertyName *name = GetNameFromBytecode(cx, pc, JSOp(*pc), js_CodeSpec[*pc]);
 
     JSObject *obj, *pobj;
     JSProperty *prop;
     JSBool ok;
 
     if (JOF_OPMODE(*pc) == JOF_NAME)
         ok = FindProperty(cx, name, start, &obj, &pobj, &prop);
     else
@@ -1290,17 +1289,17 @@ IteratorMore(JSContext *cx, JSObject *it
 {
     if (iterobj->isIterator()) {
         NativeIterator *ni = iterobj->getNativeIterator();
         if (ni->isKeyIter()) {
             *cond = (ni->props_cursor < ni->props_end);
             return true;
         }
     }
-    if (!js_IteratorMore(cx, RootedVarObject(cx, iterobj), rval))
+    if (!js_IteratorMore(cx, iterobj, rval))
         return false;
     *cond = rval->isTrue();
     return true;
 }
 
 static inline bool
 IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
 {
@@ -1540,35 +1539,21 @@ js::Interpret(JSContext *cx, StackFrame 
     /*
      * Help Debugger find frames running scripts that it has put in
      * single-step mode.
      */
     InterpreterFrames interpreterFrame(cx, &regs, interruptEnabler);
 
     /* Copy in hot values that change infrequently. */
     JSRuntime *const rt = cx->runtime;
-    RootedVar<JSScript*> script(cx);
+    JSScript *script;
     SET_SCRIPT(regs.fp()->script());
     Value *argv = regs.fp()->maybeFormalArgs();
     CHECK_INTERRUPT_HANDLER();
 
-    /*
-     * Pool of rooters for use in this interpreter frame. References to these
-     * are used for local variables within interpreter cases. This avoids
-     * creating new rooters each time an interpreter case is entered, and also
-     * correctness pitfalls due to incorrect compilation of destructor calls
-     * around computed gotos.
-     */
-    RootedVarValue rootValue0(cx), rootValue1(cx);
-    RootedVarString rootString0(cx), rootString1(cx);
-    RootedVarObject rootObject0(cx), rootObject1(cx);
-    RootedVarFunction rootFunction0(cx);
-    RootedVarTypeObject rootType0(cx);
-    RootedVarPropertyName rootName0(cx);
-
     if (rt->profilingScripts)
         ENABLE_INTERRUPTS();
 
     if (!entryFrame)
         entryFrame = regs.fp();
 
     /*
      * Initialize the index segment register used by LOAD_ATOM and
@@ -2491,25 +2476,21 @@ BEGIN_CASE(JSOP_POS)
     if (!ToNumber(cx, &regs.sp[-1]))
         goto error;
     if (!regs.sp[-1].isInt32())
         TypeScript::MonitorOverflow(cx, script, regs.pc);
 END_CASE(JSOP_POS)
 
 BEGIN_CASE(JSOP_DELNAME)
 {
-    RootedVarPropertyName &name = rootName0;
+    PropertyName *name;
     LOAD_NAME(0, name);
-
-    RootedVarObject &scopeObj = rootObject0;
-    scopeObj = cx->stack.currentScriptedScopeChain();
-
     JSObject *obj, *obj2;
     JSProperty *prop;
-    if (!FindProperty(cx, name, scopeObj, &obj, &obj2, &prop))
+    if (!FindProperty(cx, name, cx->stack.currentScriptedScopeChain(), &obj, &obj2, &prop))
         goto error;
 
     /* 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) {
@@ -2738,20 +2719,20 @@ BEGIN_CASE(JSOP_NEW)
 BEGIN_CASE(JSOP_CALL)
 BEGIN_CASE(JSOP_FUNCALL)
 {
     CallArgs args = CallArgsFromSp(GET_ARGC(regs.pc), regs.sp);
     JS_ASSERT(args.base() >= regs.fp()->base());
 
     bool construct = (*regs.pc == JSOP_NEW);
 
-    RootedVarFunction &fun = rootFunction0;
+    JSFunction *fun;
 
     /* Don't bother trying to fast-path calls to scripted non-constructors. */
-    if (!IsFunctionObject(args.calleev(), fun.address()) || !fun->isInterpretedConstructor()) {
+    if (!IsFunctionObject(args.calleev(), &fun) || !fun->isInterpretedConstructor()) {
         if (construct) {
             if (!InvokeConstructorKernel(cx, args))
                 goto error;
         } else {
             if (!InvokeKernel(cx, args))
                 goto error;
         }
         Value *newsp = args.spAfterCall();
@@ -2835,42 +2816,38 @@ BEGIN_CASE(JSOP_SETCALL)
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_LEFTSIDE_OF_ASS);
     goto error;
 }
 END_CASE(JSOP_SETCALL)
 
 BEGIN_CASE(JSOP_IMPLICITTHIS)
 {
-    RootedVarPropertyName &name = rootName0;
+    PropertyName *name;
     LOAD_NAME(0, name);
 
-    RootedVarObject &scopeObj = rootObject0;
-    scopeObj = cx->stack.currentScriptedScopeChain();
-
     JSObject *obj, *obj2;
     JSProperty *prop;
-    if (!FindPropertyHelper(cx, name, false, scopeObj, &obj, &obj2, &prop))
+    if (!FindPropertyHelper(cx, name, false, cx->stack.currentScriptedScopeChain(), &obj, &obj2, &prop))
         goto error;
 
     Value v;
     if (!ComputeImplicitThis(cx, obj, &v))
         goto error;
     PUSH_COPY(v);
 }
 END_CASE(JSOP_IMPLICITTHIS)
 
 BEGIN_CASE(JSOP_GETGNAME)
 BEGIN_CASE(JSOP_CALLGNAME)
 BEGIN_CASE(JSOP_NAME)
 BEGIN_CASE(JSOP_CALLNAME)
 {
-    RootedVarValue &rval = rootValue0;
-
-    if (!NameOperation(cx, regs.pc, rval.address()))
+    Value rval;
+    if (!NameOperation(cx, regs.pc, &rval))
         goto error;
 
     PUSH_COPY(rval);
     TypeScript::Monitor(cx, script, regs.pc, rval);
 }
 END_CASE(JSOP_NAME)
 
 BEGIN_CASE(JSOP_UINT16)
@@ -3133,37 +3110,35 @@ BEGIN_CASE(JSOP_DEFVAR)
     /* ES5 10.5 step 8 (with subsequent errata). */
     unsigned attrs = JSPROP_ENUMERATE;
     if (!regs.fp()->isEvalFrame())
         attrs |= JSPROP_PERMANENT;
     if (op == JSOP_DEFCONST)
         attrs |= JSPROP_READONLY;
 
     /* Step 8b. */
-    RootedVarObject &obj = rootObject0;
-    obj = &regs.fp()->varObj();
+    JSObject &obj = regs.fp()->varObj();
 
     if (!DefVarOrConstOperation(cx, obj, dn, attrs))
         goto error;
 }
 END_CASE(JSOP_DEFVAR)
 
 BEGIN_CASE(JSOP_DEFFUN)
 {
     /*
      * A top-level function defined in Global or Eval code (see ECMA-262
      * Ed. 3), or else a SpiderMonkey extension: a named function statement in
      * a compound statement (not at the top statement level of global code, or
      * at the top level of a function body).
      */
-    RootedVarFunction &fun = rootFunction0;
-    fun = script->getFunction(GET_UINT32_INDEX(regs.pc));
+    JSFunction *fun = script->getFunction(GET_UINT32_INDEX(regs.pc));
     JSObject *obj = fun;
 
-    RootedVarObject &obj2 = rootObject0;
+    JSObject *obj2;
     if (fun->isNullClosure()) {
         /*
          * Even a null closure needs a parent for principals finding.
          * FIXME: bug 476950, although debugger users may also demand some kind
          * of scope link for debugger-assisted eval-in-frame.
          */
         obj2 = &regs.fp()->scopeChain();
     } else {
@@ -3258,23 +3233,22 @@ BEGIN_CASE(JSOP_DEFFUN)
             goto error;
     } while (false);
 }
 END_CASE(JSOP_DEFFUN)
 
 BEGIN_CASE(JSOP_LAMBDA)
 {
     /* Load the specified function object literal. */
-    RootedVarFunction &fun = rootFunction0;
-    fun = script->getFunction(GET_UINT32_INDEX(regs.pc));
+    JSFunction *fun = script->getFunction(GET_UINT32_INDEX(regs.pc));
     JSObject *obj = fun;
 
     /* do-while(0) so we can break instead of using a goto. */
     do {
-        RootedVarObject &parent = rootObject0;
+        JSObject *parent;
         if (fun->isNullClosure()) {
             parent = &regs.fp()->scopeChain();
         } else {
             parent = GetScopeChain(cx, regs.fp());
             if (!parent)
                 goto error;
         }
 
@@ -3426,21 +3400,19 @@ BEGIN_CASE(JSOP_NEWARRAY)
 
     PUSH_OBJECT(*obj);
     CHECK_INTERRUPT_HANDLER();
 }
 END_CASE(JSOP_NEWARRAY)
 
 BEGIN_CASE(JSOP_NEWOBJECT)
 {
-    RootedVarObject &baseobj = rootObject0;
-    baseobj = script->getObject(GET_UINT32_INDEX(regs.pc));
-
-    RootedVarObject &obj = rootObject1;
-    obj = CopyInitializerObject(cx, baseobj);
+    JSObject *baseobj = script->getObject(GET_UINT32_INDEX(regs.pc));
+
+    JSObject *obj = CopyInitializerObject(cx, baseobj);
     if (!obj || !SetInitializerObjectType(cx, script, regs.pc, obj))
         goto error;
 
     PUSH_OBJECT(*obj);
     CHECK_INTERRUPT_HANDLER();
 }
 END_CASE(JSOP_NEWOBJECT)
 
@@ -3454,18 +3426,17 @@ END_CASE(JSOP_ENDINIT)
 
 BEGIN_CASE(JSOP_INITPROP)
 {
     /* Load the property's initial value into rval. */
     JS_ASSERT(regs.sp - regs.fp()->base() >= 2);
     Value rval = regs.sp[-1];
 
     /* Load the object being initialized into lval/obj. */
-    RootedVarObject &obj = rootObject0;
-    obj = &regs.sp[-2].toObject();
+    JSObject *obj = &regs.sp[-2].toObject();
     JS_ASSERT(obj->isObject());
 
     JSAtom *atom;
     LOAD_ATOM(0, atom);
     jsid id = ATOM_TO_JSID(atom);
 
     if (JS_UNLIKELY(atom == cx->runtime->atomState.protoAtom)
         ? !js_SetPropertyHelper(cx, obj, id, 0, &rval, script->strictModeCode)
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -317,17 +317,17 @@ UnwindScope(JSContext *cx, uint32_t stac
 /*
  * Unwind for an uncatchable exception. This means not running finalizers, etc;
  * just preserving the basic engine stack invariants.
  */
 extern void
 UnwindForUncatchableException(JSContext *cx, const FrameRegs &regs);
 
 extern bool
-OnUnknownMethod(JSContext *cx, HandleObject obj, Value idval, Value *vp);
+OnUnknownMethod(JSContext *cx, JSObject *obj, Value idval, Value *vp);
 
 extern bool
 IsActiveWithOrBlock(JSContext *cx, JSObject &obj, uint32_t stackDepth);
 
 class TryNoteIter
 {
     const FrameRegs &regs;
     JSScript *script;
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -166,29 +166,29 @@ NativeGet(JSContext *cx, JSObject *obj, 
         *vp = pobj->nativeGetSlot(shape->slot());
     } else {
         if (!js_NativeGet(cx, obj, pobj, shape, getHow, vp))
             return false;
     }
     return true;
 }
 
-#if defined(DEBUG) && !defined(JS_THREADSAFE) && !defined(JSGC_ROOT_ANALYSIS)
+#if defined(DEBUG) && !defined(JS_THREADSAFE)
 extern void
 AssertValidPropertyCacheHit(JSContext *cx, JSObject *start, JSObject *found,
                             PropertyCacheEntry *entry);
 #else
 inline void
 AssertValidPropertyCacheHit(JSContext *cx, JSObject *start, JSObject *found,
                             PropertyCacheEntry *entry)
 {}
 #endif
 
 inline bool
-GetPropertyGenericMaybeCallXML(JSContext *cx, JSOp op, HandleObject obj, jsid id, Value *vp)
+GetPropertyGenericMaybeCallXML(JSContext *cx, JSOp op, JSObject *obj, jsid id, Value *vp)
 {
     /*
      * 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);
@@ -250,34 +250,32 @@ GetPropertyOperation(JSContext *cx, jsby
     JS_PROPERTY_CACHE(cx).test(cx, pc, obj, obj2, entry, name);
     if (!name) {
         AssertValidPropertyCacheHit(cx, obj, obj2, entry);
         if (!NativeGet(cx, obj, obj2, entry->prop, JSGET_CACHE_RESULT, vp))
             return false;
         return true;
     }
 
-    RootObject objRoot(cx, &obj);
-
     jsid id = ATOM_TO_JSID(name);
 
     if (obj->getOps()->getProperty) {
-        if (!GetPropertyGenericMaybeCallXML(cx, op, objRoot, id, vp))
+        if (!GetPropertyGenericMaybeCallXML(cx, op, obj, id, vp))
             return false;
     } else {
-        if (!GetPropertyHelper(cx, objRoot, id, JSGET_CACHE_RESULT, vp))
+        if (!GetPropertyHelper(cx, obj, id, JSGET_CACHE_RESULT, vp))
             return false;
     }
 
 #if JS_HAS_NO_SUCH_METHOD
     if (op == JSOP_CALLPROP &&
         JS_UNLIKELY(vp->isPrimitive()) &&
         lval.isObject())
     {
-        if (!OnUnknownMethod(cx, objRoot, IdToValue(id), vp))
+        if (!OnUnknownMethod(cx, obj, IdToValue(id), vp))
             return false;
     }
 #endif
 
     return true;
 }
 
 inline bool
@@ -305,19 +303,19 @@ SetPropertyOperation(JSContext *cx, jsby
         const Shape *shape = entry->prop;
         JS_ASSERT_IF(shape->isDataDescriptor(), shape->writable());
         JS_ASSERT_IF(shape->hasSlot(), entry->isOwnPropertyHit());
 
         if (entry->isOwnPropertyHit() ||
             ((obj2 = obj->getProto()) && obj2->lastProperty() == entry->pshape)) {
 #ifdef DEBUG
             if (entry->isOwnPropertyHit()) {
-                JS_ASSERT(obj->nativeLookupNoAllocation(cx, shape->propid()) == shape);
+                JS_ASSERT(obj->nativeContains(cx, *shape));
             } else {
-                JS_ASSERT(obj2->nativeLookupNoAllocation(cx, shape->propid()) == shape);
+                JS_ASSERT(obj2->nativeContains(cx, *shape));
                 JS_ASSERT(entry->isPrototypePropertyHit());
                 JS_ASSERT(entry->kshape != entry->pshape);
                 JS_ASSERT(!shape->hasSlot());
             }
 #endif
 
             if (shape->hasDefaultSetter() && shape->hasSlot()) {
                 /* Fast path for, e.g., plain Object instance properties. */
@@ -330,31 +328,29 @@ SetPropertyOperation(JSContext *cx, jsby
             }
             return true;
         }
 
         GET_NAME_FROM_BYTECODE(cx->stack.currentScript(), pc, 0, name);
     }
 
     bool strict = cx->stack.currentScript()->strictModeCode;
-    RootedVarValue rref(cx, rval);
+    Value rref = rval;
 
     JSOp op = JSOp(*pc);
 
-    RootObject objRoot(cx, &obj);
-
     jsid id = ATOM_TO_JSID(name);
     if (JS_LIKELY(!obj->getOps()->setProperty)) {
         unsigned defineHow = (op == JSOP_SETNAME)
                              ? DNP_CACHE_RESULT | DNP_UNQUALIFIED
                              : DNP_CACHE_RESULT;
-        if (!js_SetPropertyHelper(cx, objRoot, id, defineHow, rref.address(), strict))
+        if (!js_SetPropertyHelper(cx, obj, id, defineHow, &rref, strict))
             return false;
     } else {
-        if (!obj->setGeneric(cx, id, rref.address(), strict))
+        if (!obj->setGeneric(cx, id, &rref, strict))
             return false;
     }
 
     return true;
 }
 
 inline bool
 NameOperation(JSContext *cx, jsbytecode *pc, Value *vp)
@@ -381,21 +377,18 @@ NameOperation(JSContext *cx, jsbytecode 
         AssertValidPropertyCacheHit(cx, obj, obj2, entry);
         if (!NativeGet(cx, obj, obj2, entry->prop, 0, vp))
             return false;
         return true;
     }
 
     jsid id = ATOM_TO_JSID(name);
 
-    RootPropertyName nameRoot(cx, &name);
-    RootObject objRoot(cx, &obj);
-
     JSProperty *prop;
-    if (!FindPropertyHelper(cx, nameRoot, true, objRoot, &obj, &obj2, &prop))
+    if (!FindPropertyHelper(cx, name, true, obj, &obj, &obj2, &prop))
         return false;
     if (!prop) {
         /* Kludge to allow (typeof foo == "undefined") tests. */
         JSOp op2 = JSOp(pc[JSOP_NAME_LENGTH]);
         if (op2 == JSOP_TYPEOF) {
             vp->setUndefined();
             return true;
         }
@@ -417,40 +410,40 @@ NameOperation(JSContext *cx, jsbytecode 
         if (!NativeGet(cx, normalized, obj2, shape, 0, vp))
             return false;
     }
 
     return true;
 }
 
 inline bool
-DefVarOrConstOperation(JSContext *cx, HandleObject varobj, PropertyName *dn, unsigned attrs)
+DefVarOrConstOperation(JSContext *cx, JSObject &varobj, PropertyName *dn, unsigned attrs)
 {
-    JS_ASSERT(varobj->isVarObj());
-    JS_ASSERT(!varobj->getOps()->defineProperty);
+    JS_ASSERT(varobj.isVarObj());
+    JS_ASSERT(!varobj.getOps()->defineProperty);
 
     JSProperty *prop;
     JSObject *obj2;
-    if (!varobj->lookupProperty(cx, dn, &obj2, &prop))
+    if (!varobj.lookupProperty(cx, dn, &obj2, &prop))
         return false;
 
     /* Steps 8c, 8d. */
-    if (!prop || (obj2 != varobj && varobj->isGlobal())) {
-        if (!DefineNativeProperty(cx, varobj, dn, UndefinedValue(),
+    if (!prop || (obj2 != &varobj && varobj.isGlobal())) {
+        if (!DefineNativeProperty(cx, &varobj, dn, UndefinedValue(),
                                   JS_PropertyStub, JS_StrictPropertyStub, attrs, 0, 0))
         {
             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 (!varobj.getPropertyAttributes(cx, 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)
@@ -480,17 +473,17 @@ FunctionNeedsPrologue(JSContext *cx, JSF
 }
 
 inline bool
 ScriptPrologue(JSContext *cx, StackFrame *fp, bool newType)
 {
     JS_ASSERT_IF(fp->isNonEvalFunctionFrame() && fp->fun()->isHeavyweight(), fp->hasCallObj());
 
     if (fp->isConstructing()) {
-        JSObject *obj = js_CreateThisForFunction(cx, RootedVarObject(cx, &fp->callee()), newType);
+        JSObject *obj = js_CreateThisForFunction(cx, &fp->callee(), newType);
         if (!obj)
             return false;
         fp->functionThis().setObject(*obj);
     }
 
     Probes::enterJSFun(cx, fp->maybeFun(), fp->script());
 
     return true;
@@ -534,67 +527,65 @@ InterpreterFrames::enableInterruptsIfRun
 {
     if (script == regs->fp()->script())
         enabler.enableInterrupts();
 }
 
 static JS_ALWAYS_INLINE bool
 AddOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res)
 {
-    if (lhs.isInt32() && rhs.isInt32()) {
-        int32_t l = lhs.toInt32(), r = rhs.toInt32();
+    Value lval = lhs;
+    Value rval = rhs;
+
+    if (lval.isInt32() && rval.isInt32()) {
+        int32_t l = lval.toInt32(), r = rval.toInt32();
         int32_t sum = l + r;
         if (JS_UNLIKELY(bool((l ^ sum) & (r ^ sum) & 0x80000000))) {
             res->setDouble(double(l) + double(r));
             types::TypeScript::MonitorOverflow(cx);
         } else {
             res->setInt32(sum);
         }
     } else
 #if JS_HAS_XML_SUPPORT
-    if (IsXML(lhs) && IsXML(rhs)) {
-        if (!js_ConcatenateXML(cx, &lhs.toObject(), &rhs.toObject(), res))
+    if (IsXML(lval) && IsXML(rval)) {
+        if (!js_ConcatenateXML(cx, &lval.toObject(), &rval.toObject(), res))
             return false;
         types::TypeScript::MonitorUnknown(cx);
     } else
 #endif
     {
-        RootedVarValue lval_(cx, lhs);
-        RootedVarValue rval_(cx, rhs);
-        Value &lval = lval_.reference();
-        Value &rval = rval_.reference();
-
         /*
          * If either operand is an object, any non-integer result must be
          * reported to inference.
          */
         bool lIsObject = lval.isObject(), rIsObject = rval.isObject();
 
         if (!ToPrimitive(cx, &lval))
             return false;
         if (!ToPrimitive(cx, &rval))
             return false;
         bool lIsString, rIsString;
         if ((lIsString = lval.isString()) | (rIsString = rval.isString())) {
-            RootedVarString lstr(cx), rstr(cx);
+            js::AutoStringRooter lstr(cx), rstr(cx);
             if (lIsString) {
-                lstr = lval.toString();
+                lstr.setString(lval.toString());
             } else {
-                lstr = ToString(cx, lval);
-                if (!lstr)
+                lstr.setString(ToString(cx, lval));
+                if (!lstr.string())
                     return false;
             }
             if (rIsString) {
-                rstr = rval.toString();
+                rstr.setString(rval.toString());
             } else {
-                rstr = ToString(cx, rval);
-                if (!rstr)
+                rstr.setString(ToString(cx, rval));
+                if (!rstr.string())
                     return false;
             }
-            JSString *str = js_ConcatStrings(cx, lstr, rstr);
+            JSString *str = js_ConcatStrings(cx, lstr.string(), rstr.string());
             if (!str)
                 return false;
             if (lIsObject || rIsObject)
                 types::TypeScript::MonitorString(cx);
             res->setString(str);
         } else {
             double l, r;
             if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))
@@ -697,17 +688,17 @@ ToIdOperation(JSContext *cx, const Value
         return false;
 
     if (!res->isInt32())
         types::TypeScript::MonitorUnknown(cx);
     return true;
 }
 
 static JS_ALWAYS_INLINE bool
-GetObjectElementOperation(JSContext *cx, JSOp op, HandleObject obj, const Value &rref, Value *res)
+GetObjectElementOperation(JSContext *cx, JSOp op, JSObject *obj, const Value &rref, Value *res)
 {
 #if JS_HAS_XML_SUPPORT
     if (op == JSOP_CALLELEM && JS_UNLIKELY(obj->isXML())) {
         jsid id;
         if (!FetchElementId(cx, obj, rref, id, res))
             return false;
         return js_GetXMLMethod(cx, obj, id, res);
     }
@@ -777,17 +768,17 @@ GetElementOperation(JSContext *cx, JSOp 
             return true;
         }
     }
 
     if (lref.isMagic(JS_OPTIMIZED_ARGUMENTS))
         return NormalArgumentsObject::optimizedGetElem(cx, cx->fp(), rref, res);
 
     bool isObject = lref.isObject();
-    RootedVarObject obj(cx, ValueToObject(cx, lref));
+    JSObject *obj = ValueToObject(cx, lref);
     if (!obj)
         return false;
     if (!GetObjectElementOperation(cx, op, obj, rref, res))
         return false;
 
 #if JS_HAS_NO_SUCH_METHOD
     if (op == JSOP_CALLELEM && JS_UNLIKELY(res->isPrimitive()) && isObject) {
         if (!OnUnknownMethod(cx, obj, rref, res))
@@ -821,18 +812,18 @@ SetObjectElementOperation(JSContext *cx,
                 types::TypeScript::GetPcScript(cx, &script, &pc);
 
                 if (script->hasAnalysis())
                     script->analysis()->getCode(pc).arrayWriteHole = true;
             }
         }
     } while (0);
 
-    RootedVarValue tmp(cx, value);
-    return obj->setGeneric(cx, id, tmp.address(), strict);
+    Value tmp = value;
+    return obj->setGeneric(cx, id, &tmp, strict);
 }
 
 #define RELATIONAL_OP(OP)                                                     \
     JS_BEGIN_MACRO                                                            \
         Value lval = lhs;                                                     \
         Value rval = rhs;                                                     \
         /* Optimize for two int-tagged operands (typical loop control). */    \
         if (lval.isInt32() && rval.isInt32()) {                               \
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -438,17 +438,17 @@ JS_FRIEND_API(bool)
 js::GetPropertyNames(JSContext *cx, JSObject *obj, unsigned flags, AutoIdVector *props)
 {
     return Snapshot(cx, obj, flags & (JSITER_OWNONLY | JSITER_HIDDEN), props);
 }
 
 size_t sCustomIteratorCount = 0;
 
 static inline bool
-GetCustomIterator(JSContext *cx, HandleObject obj, unsigned flags, Value *vp)
+GetCustomIterator(JSContext *cx, JSObject *obj, unsigned flags, Value *vp)
 {
     JS_CHECK_RECURSION(cx, return false);
 
     /*
      * for-of iteration does not fall back on __iterator__ or property
      * enumeration. This is more conservative than the current proposed spec.
      */
     if (flags == JSITER_FOR_OF) {
@@ -579,28 +579,28 @@ RegisterEnumerator(JSContext *cx, JSObje
         cx->enumerators = iterobj;
 
         JS_ASSERT(!(ni->flags & JSITER_ACTIVE));
         ni->flags |= JSITER_ACTIVE;
     }
 }
 
 static inline bool
-VectorToKeyIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVector &keys,
+VectorToKeyIterator(JSContext *cx, JSObject *obj, unsigned flags, AutoIdVector &keys,
                     uint32_t slength, uint32_t key, Value *vp)
 {
     JS_ASSERT(!(flags & JSITER_FOREACH));
 
     if (obj) {
         if (obj->hasSingletonType() && !obj->setIteratedSingleton(cx))
             return false;
         types::MarkTypeObjectFlags(cx, obj, types::OBJECT_FLAG_ITERATED);
     }
 
-    RootedVarObject iterobj(cx, NewIteratorObject(cx, flags));
+    JSObject *iterobj = NewIteratorObject(cx, flags);
     if (!iterobj)
         return false;
 
     NativeIterator *ni = NativeIterator::allocateIterator(cx, slength, keys);
     if (!ni)
         return false;
     ni->init(obj, flags, slength, key);
 
@@ -626,23 +626,23 @@ VectorToKeyIterator(JSContext *cx, Handl
 
     RegisterEnumerator(cx, iterobj, ni);
     return true;
 }
 
 namespace js {
 
 bool
-VectorToKeyIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVector &props, Value *vp)
+VectorToKeyIterator(JSContext *cx, JSObject *obj, unsigned flags, AutoIdVector &props, Value *vp)
 {
     return VectorToKeyIterator(cx, obj, flags, props, 0, 0, vp);
 }
 
 bool
-VectorToValueIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVector &keys,
+VectorToValueIterator(JSContext *cx, JSObject *obj, unsigned flags, AutoIdVector &keys,
                       Value *vp)
 {
     JS_ASSERT(flags & JSITER_FOREACH);
 
     if (obj) {
         if (obj->hasSingletonType() && !obj->setIteratedSingleton(cx))
             return false;
         types::MarkTypeObjectFlags(cx, obj, types::OBJECT_FLAG_ITERATED);
@@ -660,34 +660,34 @@ VectorToValueIterator(JSContext *cx, Han
     iterobj->setNativeIterator(ni);
     vp->setObject(*iterobj);
 
     RegisterEnumerator(cx, iterobj, ni);
     return true;
 }
 
 bool
-EnumeratedIdVectorToIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVector &props, Value *vp)
+EnumeratedIdVectorToIterator(JSContext *cx, JSObject *obj, unsigned flags, AutoIdVector &props, Value *vp)
 {
     if (!(flags & JSITER_FOREACH))
         return VectorToKeyIterator(cx, obj, flags, props, vp);
 
     return VectorToValueIterator(cx, obj, flags, props, vp);
 }
 
 static inline void
 UpdateNativeIterator(NativeIterator *ni, JSObject *obj)
 {
     // Update the object for which the native iterator is associated, so
     // SuppressDeletedPropertyHelper will recognize the iterator as a match.
     ni->obj = obj;
 }
 
 bool
-GetIterator(JSContext *cx, HandleObject obj, unsigned flags, Value *vp)
+GetIterator(JSContext *cx, JSObject *obj, unsigned flags, Value *vp)
 {
     Vector<const Shape *, 8> shapes(cx);
     uint32_t key = 0;
 
     bool keysOnly = (flags == JSITER_ENUMERATE);
 
     if (obj) {
         /* Enumerate Iterator.prototype directly. */
@@ -844,17 +844,17 @@ js_ThrowStopIteration(JSContext *cx)
 }
 
 static JSBool
 iterator_next(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     bool ok;
-    RootedVarObject obj(cx, NonGenericMethodGuard(cx, args, iterator_next, &IteratorClass, &ok));
+    JSObject *obj = NonGenericMethodGuard(cx, args, iterator_next, &IteratorClass, &ok);
     if (!obj)
         return ok;
 
     if (!js_IteratorMore(cx, obj, &args.rval()))
         return false;
 
     if (!args.rval().toBoolean()) {
         js_ThrowStopIteration(cx);
@@ -888,30 +888,30 @@ js::ValueToIterator(JSContext *cx, unsig
 
     /*
      * Make sure the more/next state machine doesn't get stuck. A value might be
      * left in iterValue when a trace is left due to an operation time-out after
      * JSOP_MOREITER but before the value is picked up by FOR*.
      */
     cx->iterValue.setMagic(JS_NO_ITER_VALUE);
 
-    RootedVarObject obj(cx);
+    JSObject *obj;
     if (vp->isObject()) {
         /* Common case. */
         obj = &vp->toObject();
     } else {
         /*
          * Enumerating over null and undefined gives an empty enumerator.
          * This is contrary to ECMA-262 9.9 ToObject, invoked from step 3 of
          * the first production in 12.6.4 and step 4 of the second production,
          * but it's "web JS" compatible. ES5 fixed for-in to match this de-facto
          * standard.
          */
         if ((flags & JSITER_ENUMERATE)) {
-            if (!js_ValueToObjectOrNull(cx, *vp, obj.address()))
+            if (!js_ValueToObjectOrNull(cx, *vp, &obj))
                 return false;
             /* fall through */
         } else {
             obj = js_ValueToNonNullObject(cx, *vp);
             if (!obj)
                 return false;
         }
     }
@@ -1149,17 +1149,17 @@ ElementIteratorObject::setIndex(uint32_t
 {
     setReservedSlot(IndexSlot, Int32Value(int32_t(index)));
 }
 
 bool
 ElementIteratorObject::iteratorNext(JSContext *cx, Value *vp)
 {
     uint32_t i, length;
-    RootedVarObject obj(cx, getTargetObject());
+    JSObject *obj = getTargetObject();
     if (!js_GetLengthProperty(cx, obj, &length))
         goto error;
 
     i = getIndex();
     if (i >= length) {
         setIndex(CLOSED_INDEX);
         vp->setMagic(JS_NO_ITER_VALUE);
         return true;
@@ -1181,17 +1181,17 @@ ElementIteratorObject::iteratorNext(JSCo
 inline js::ElementIteratorObject *
 JSObject::asElementIterator()
 {
     JS_ASSERT(isElementIterator());
     return static_cast<js::ElementIteratorObject *>(this);
 }
 
 JSBool
-js_IteratorMore(JSContext *cx, HandleObject iterobj, Value *rval)
+js_IteratorMore(JSContext *cx, JSObject *iterobj, Value *rval)
 {
     /* Fast path for native iterators */
     NativeIterator *ni = NULL;
     if (iterobj->isIterator()) {
         /* Key iterators are handled by fast-paths. */
         ni = iterobj->getNativeIterator();
         bool more = ni->props_cursor < ni->props_end;
         if (ni->isKeyIter() || !more) {
--- a/js/src/jsiter.h
+++ b/js/src/jsiter.h
@@ -158,42 +158,42 @@ class ElementIteratorObject : public JSO
      * If there are any more elements to visit, store the value of the next
      * element in *vp, increment the index, and return true. If not, call
      * vp->setMagic(JS_NO_ITER_VALUE) and return true. Return false on error.
      */
     bool iteratorNext(JSContext *cx, Value *vp);
 };
 
 bool
-VectorToIdArray(JSContext *cx, AutoIdVector &props, JSIdArray **idap);
+VectorToIdArray(JSContext *cx, js::AutoIdVector &props, JSIdArray **idap);
 
 bool
-GetIterator(JSContext *cx, HandleObject obj, unsigned flags, Value *vp);
+GetIterator(JSContext *cx, JSObject *obj, unsigned flags, js::Value *vp);
 
 bool
-VectorToKeyIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVector &props, Value *vp);
+VectorToKeyIterator(JSContext *cx, JSObject *obj, unsigned flags, js::AutoIdVector &props, js::Value *vp);
 
 bool
-VectorToValueIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVector &props, Value *vp);
+VectorToValueIterator(JSContext *cx, JSObject *obj, unsigned flags, js::AutoIdVector &props, js::Value *vp);
 
 /*
  * Creates either a key or value iterator, depending on flags. For a value
  * iterator, performs value-lookup to convert the given list of jsids.
  */
 bool
-EnumeratedIdVectorToIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVector &props, Value *vp);
+EnumeratedIdVectorToIterator(JSContext *cx, JSObject *obj, unsigned flags, js::AutoIdVector &props, js::Value *vp);
 
 /*
  * Convert the value stored in *vp to its iteration object. The flags should
  * contain JSITER_ENUMERATE if js::ValueToIterator is called when enumerating
  * for-in semantics are required, and when the caller can guarantee that the
  * iterator will never be exposed to scripts.
  */
 extern JSBool
-ValueToIterator(JSContext *cx, unsigned flags, Value *vp);
+ValueToIterator(JSContext *cx, unsigned flags, js::Value *vp);
 
 extern bool
 CloseIterator(JSContext *cx, JSObject *iterObj);
 
 extern bool
 UnwindIteratorForException(JSContext *cx, JSObject *obj);
 
 extern void
@@ -211,34 +211,34 @@ extern bool
 js_SuppressDeletedElements(JSContext *cx, JSObject *obj, uint32_t begin, uint32_t end);
 
 /*
  * IteratorMore() indicates whether another value is available. It might
  * internally call iterobj.next() and then cache the value until its
  * picked up by IteratorNext(). The value is cached in the current context.
  */
 extern JSBool
-js_IteratorMore(JSContext *cx, js::HandleObject iterobj, js::Value *rval);
+js_IteratorMore(JSContext *cx, JSObject *iterobj, js::Value *rval);
 
 extern JSBool
 js_IteratorNext(JSContext *cx, JSObject *iterobj, js::Value *rval);
 
 extern JSBool
 js_ThrowStopIteration(JSContext *cx);
 
 namespace js {
 
 /*
  * Get the next value from an iterator object.
  *
  * On success, store the next value in *vp and return true; if there are no
  * more values, store the magic value JS_NO_ITER_VALUE in *vp and return true.
  */
 inline bool
-Next(JSContext *cx, HandleObject iter, Value *vp)
+Next(JSContext *cx, JSObject *iter, Value *vp)
 {
     if (!js_IteratorMore(cx, iter, vp))
         return false;
     if (vp->toBoolean())
         return js_IteratorNext(cx, iter, vp);
     vp->setMagic(JS_NO_ITER_VALUE);
     return true;
 }
@@ -257,17 +257,17 @@ Next(JSContext *cx, HandleObject iter, V
  */
 template <class Op>
 bool
 ForOf(JSContext *cx, const Value &iterable, Op op)
 {
     Value iterv(iterable);
     if (!ValueToIterator(cx, JSITER_FOR_OF, &iterv))
         return false;
-    RootedVarObject iter(cx, &iterv.toObject());
+    JSObject *iter = &iterv.toObject();
 
     bool ok = true;
     while (ok) {
         Value v;
         ok = Next(cx, iter, &v);
         if (ok) {
             if (v.isMagic(JS_NO_ITER_VALUE))
                 break;
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -706,21 +706,19 @@ js_IsMathFunction(Native native)
     for (size_t i=0; math_static_methods[i].name != NULL; i++) {
         if (native == math_static_methods[i].call)
             return true;
     }
     return false;
 }
 
 JSObject *
-js_InitMathClass(JSContext *cx, JSObject *obj_)
+js_InitMathClass(JSContext *cx, JSObject *obj)
 {
-    RootedVarObject obj(cx, obj_);
-
-    RootedVarObject Math(cx, NewObjectWithClassProto(cx, &MathClass, NULL, obj));
+    JSObject *Math = NewObjectWithClassProto(cx, &MathClass, NULL, obj);
     if (!Math || !Math->setSingletonType(cx))
         return NULL;
 
     if (!JS_DefineProperty(cx, obj, js_Math_str, OBJECT_TO_JSVAL(Math),
                            JS_PropertyStub, JS_StrictPropertyStub, 0)) {
         return NULL;
     }
 
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -1009,25 +1009,24 @@ FinishRuntimeNumberState(JSRuntime *rt)
 JSObject *
 js_InitNumberClass(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isNative());
 
     /* XXX must do at least once per new thread, so do it per JSContext... */
     FIX_FPU();
 
-    RootedVar<GlobalObject*> global(cx, &obj->asGlobal());
+    GlobalObject *global = &obj->asGlobal();
 
-    RootedVarObject numberProto(cx, global->createBlankPrototype(cx, &NumberClass));
+    JSObject *numberProto = global->createBlankPrototype(cx, &NumberClass);
     if (!numberProto)
         return NULL;
     numberProto->asNumber().setPrimitiveValue(0);
 
-    RootedVarFunction ctor(cx);
-    ctor = global->createConstructor(cx, Number, CLASS_ATOM(cx, Number), 1);
+    JSFunction *ctor = global->createConstructor(cx, Number, CLASS_ATOM(cx, Number), 1);
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, numberProto))
         return NULL;
 
     /* Add numeric constants (MAX_VALUE, NaN, &c.) to the Number constructor. */
     if (!JS_DefineConstDoubles(cx, ctor, number_constants))
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -841,23 +841,23 @@ EvalCacheLookup(JSContext *cx, JSLinearS
  * with calls to JS_GetScriptObject for scripts in the eval cache (currently,
  * script->object aliases script->evalHashLink()).
  */
 class EvalScriptGuard
 {
     JSContext *cx_;
     JSLinearString *str_;
     JSScript **bucket_;
-    RootedVar<JSScript*> script_;
+    JSScript *script_;
 
   public:
     EvalScriptGuard(JSContext *cx, JSLinearString *str)
       : cx_(cx),
         str_(str),
-        script_(cx) {
+        script_(NULL) {
         bucket_ = EvalCacheHash(cx, str);
     }
 
     ~EvalScriptGuard() {
         if (script_) {
             CallDestroyScriptHook(cx_->runtime->defaultFreeOp(), script_);
             script_->isActiveEval = false;
             script_->isCachedEval = true;
@@ -904,22 +904,22 @@ enum EvalType { DIRECT_EVAL = EXECUTE_DI
  * frame, with the provided scope chain, with the semantics of either a direct
  * or indirect eval (see ES5 10.4.2).  If this is an indirect eval, scopeobj
  * must be a global object.
  *
  * On success, store the completion value in call.rval and return true.
  */
 static bool
 EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, StackFrame *caller,
-           HandleObject scopeobj)
+           JSObject &scopeobj)
 {
     JS_ASSERT((evalType == INDIRECT_EVAL) == (caller == NULL));
-    AssertInnerizedScopeChain(cx, *scopeobj);
-
-    if (!scopeobj->global().isRuntimeCodeGenEnabled(cx)) {
+    AssertInnerizedScopeChain(cx, scopeobj);
+
+    if (!scopeobj.global().isRuntimeCodeGenEnabled(cx)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CSP_BLOCKED_EVAL);
         return false;
     }
 
     /* ES5 15.1.2.1 step 1. */
     if (args.length() < 1) {
         args.rval().setUndefined();
         return true;
@@ -951,21 +951,21 @@ EvalKernel(JSContext *cx, const CallArgs
             return false;
         thisv = caller->thisValue();
 
 #ifdef DEBUG
         jsbytecode *callerPC = caller->pcQuadratic(cx);
         JS_ASSERT(callerPC && JSOp(*callerPC) == JSOP_EVAL);
 #endif
     } else {
-        JS_ASSERT(args.callee().global() == *scopeobj);
+        JS_ASSERT(args.callee().global() == scopeobj);
         staticLevel = 0;
 
         /* Use the global as 'this', modulo outerization. */
-        JSObject *thisobj = scopeobj->thisObject(cx);
+        JSObject *thisobj = scopeobj.thisObject(cx);
         if (!thisobj)
             return false;
         thisv = ObjectValue(*thisobj);
     }
 
     JSLinearString *linearStr = str->ensureLinear(cx);
     if (!linearStr)
         return false;
@@ -1015,38 +1015,38 @@ EvalKernel(JSContext *cx, const CallArgs
         }
     }
 
     EvalScriptGuard esg(cx, linearStr);
 
     JSPrincipals *principals = PrincipalsForCompiledCode(args, cx);
 
     if (evalType == DIRECT_EVAL && caller->isNonEvalFunctionFrame())
-        esg.lookupInEvalCache(caller, staticLevel, principals, *scopeobj);
+        esg.lookupInEvalCache(caller, staticLevel, principals, scopeobj);
 
     if (!esg.foundScript()) {
         unsigned lineno;
         const char *filename;
         JSPrincipals *originPrincipals;
         CurrentScriptFileLineOrigin(cx, &filename, &lineno, &originPrincipals,
                                     evalType == DIRECT_EVAL ? CALLED_FROM_JSOP_EVAL
                                                             : NOT_CALLED_FROM_JSOP_EVAL);
         uint32_t tcflags = TCF_COMPILE_N_GO | TCF_COMPILE_FOR_EVAL;
-        JSScript *compiled = frontend::CompileScript(cx, scopeobj, caller,
+        JSScript *compiled = frontend::CompileScript(cx, &scopeobj, caller,
                                                      principals, originPrincipals,
                                                      tcflags, chars, length, filename,
                                                      lineno, cx->findVersion(), linearStr,
                                                      staticLevel);
         if (!compiled)
             return false;
 
         esg.setNewScript(compiled);
     }
 
-    return ExecuteKernel(cx, esg.script(), *scopeobj, thisv, ExecuteType(evalType),
+    return ExecuteKernel(cx, esg.script(), scopeobj, thisv, ExecuteType(evalType),
                          NULL /* evalInFrame */, &args.rval());
 }
 
 /*
  * We once supported a second argument to eval to use as the scope chain
  * when evaluating the code string.  Warn when such uses are seen so that
  * authors will know that support for eval(s, o) has been removed.
  */
@@ -1081,39 +1081,38 @@ namespace js {
  *
  * NB: This method handles only indirect eval.
  */
 JSBool
 eval(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return WarnOnTooManyArgs(cx, args) &&
-           EvalKernel(cx, args, INDIRECT_EVAL, NULL,
-                      RootedVarObject(cx, &args.callee().global()));
+           EvalKernel(cx, args, INDIRECT_EVAL, NULL, args.callee().global());
 }
 
 bool
 DirectEval(JSContext *cx, const CallArgs &args)
 {
     /* Direct eval can assume it was called from an interpreted frame. */
     StackFrame *caller = cx->fp();
     JS_ASSERT(caller->isScriptFrame());
     JS_ASSERT(IsBuiltinEvalForScope(&caller->scopeChain(), args.calleev()));
     JS_ASSERT(JSOp(*cx->regs().pc) == JSOP_EVAL);
 
     AutoFunctionCallProbe callProbe(cx, args.callee().toFunction(), caller->script());
 
-    RootedVarObject scopeChain(cx, GetScopeChain(cx, caller));
+    JSObject *scopeChain = GetScopeChain(cx, caller);
     if (!scopeChain)
         return false;
 
     if (!WarnOnTooManyArgs(cx, args))
         return false;
 
-    return EvalKernel(cx, args, DIRECT_EVAL, caller, scopeChain);
+    return EvalKernel(cx, args, DIRECT_EVAL, caller, *scopeChain);
 }
 
 bool
 IsBuiltinEvalForScope(JSObject *scopeChain, const Value &v)
 {
     return scopeChain->global().getOriginalEval() == v;
 }
 
@@ -1190,28 +1189,28 @@ obj_watch(JSContext *cx, unsigned argc, 
     JSObject *callable = js_ValueToCallableObject(cx, &vp[3], 0);
     if (!callable)
         return false;
 
     jsid propid;
     if (!ValueToId(cx, vp[2], &propid))
         return false;
 
-    RootedVarObject obj(cx, ToObject(cx, &vp[1]));
+    JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return false;
 
     Value tmp;
     unsigned attrs;
     if (!CheckAccess(cx, obj, propid, JSACC_WATCH, &tmp, &attrs))
         return false;
 
     vp->setUndefined();
 
-    if (obj->isDenseArray() && !JSObject::makeDenseArraySlow(cx, obj))
+    if (obj->isDenseArray() && !obj->makeDenseArraySlow(cx))
         return false;
     return JS_SetWatchPoint(cx, obj, propid, obj_watch_handler, callable);
 }
 
 static JSBool
 obj_unwatch(JSContext *cx, unsigned argc, Value *vp)
 {
     JSObject *obj = ToObject(cx, &vp[1]);
@@ -1248,17 +1247,17 @@ obj_hasOwnProperty(JSContext *cx, unsign
 JSBool
 js_HasOwnPropertyHelper(JSContext *cx, LookupGenericOp lookup, unsigned argc,
                         Value *vp)
 {
     jsid id;
     if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), &id))
         return JS_FALSE;
 
-    RootedVarObject obj(cx, ToObject(cx, &vp[1]));
+    JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return false;
     JSObject *obj2;
     JSProperty *prop;
     if (obj->isProxy()) {
         bool has;
         if (!Proxy::hasOwn(cx, obj, id, &has))
             return false;
@@ -1267,17 +1266,17 @@ js_HasOwnPropertyHelper(JSContext *cx, L
     }
     if (!js_HasOwnProperty(cx, lookup, obj, id, &obj2, &prop))
         return JS_FALSE;
     vp->setBoolean(!!prop);
     return JS_TRUE;
 }
 
 JSBool
-js_HasOwnProperty(JSContext *cx, LookupGenericOp lookup, HandleObject obj, jsid id,
+js_HasOwnProperty(JSContext *cx, LookupGenericOp lookup, JSObject *obj, jsid id,
                   JSObject **objp, JSProperty **propp)
 {
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING);
     if (!(lookup ? lookup : js_LookupProperty)(cx, obj, id, objp, propp))
         return false;
     if (!*propp)
         return true;
 
@@ -1406,23 +1405,18 @@ DefineAccessor(JSContext *cx, unsigned a
         return false;
 
     /* enumerable: true */
     PropertyName *acc = (Type == Getter) ? state.getAtom : state.setAtom;
     if (!descObj->defineProperty(cx, acc, args[1]))
         return false;
 
     JSBool dummy;
-    if (!js_DefineOwnProperty(cx,
-                              RootedVarObject(cx, &args.thisv().toObject()),
-                              RootedVarId(cx, id),
-                              ObjectValue(*descObj), &dummy))
-    {
+    if (!js_DefineOwnProperty(cx, &args.thisv().toObject(), id, ObjectValue(*descObj), &dummy))
         return false;
-    }
     args.rval().setUndefined();
     return true;
 }
 
 JS_FRIEND_API(JSBool)
 js::obj_defineGetter(JSContext *cx, unsigned argc, Value *vp)
 {
     return DefineAccessor<Getter>(cx, argc, vp);
@@ -1584,17 +1578,17 @@ PropDesc::makeObject(JSContext *cx)
         return false;
     }
 
     pd.setObject(*obj);
     return true;
 }
 
 bool
-GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, PropertyDescriptor *desc)
+GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, PropertyDescriptor *desc)
 {
     if (obj->isProxy())
         return Proxy::getOwnPropertyDescriptor(cx, obj, id, false, desc);
 
     JSObject *pobj;
     JSProperty *prop;
     if (!js_HasOwnProperty(cx, obj->getOps()->lookupGeneric, obj, id, &pobj, &prop))
         return false;
@@ -1622,17 +1616,17 @@ GetOwnPropertyDescriptor(JSContext *cx, 
     if (doGet && !obj->getGeneric(cx, id, &desc->value))
         return false;
 
     desc->obj = obj;
     return true;
 }
 
 bool
-GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, Value *vp)
+GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     AutoPropertyDescriptorRooter desc(cx);
     return GetOwnPropertyDescriptor(cx, obj, id, &desc) &&
            NewPropertyDescriptorObject(cx, &desc, vp);
 }
 
 }
 
@@ -1658,23 +1652,23 @@ GetFirstArgumentAsObject(JSContext *cx, 
 
     *objp = &v.toObject();
     return true;
 }
 
 static JSBool
 obj_getOwnPropertyDescriptor(JSContext *cx, unsigned argc, Value *vp)
 {
-    RootedVarObject obj(cx);
-    if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.getOwnPropertyDescriptor", obj.address()))
+    JSObject *obj;
+    if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.getOwnPropertyDescriptor", &obj))
         return JS_FALSE;
-    RootedVarId id(cx);
-    if (!ValueToId(cx, argc >= 2 ? vp[3] : UndefinedValue(), id.address()))
+    AutoIdRooter nameidr(cx);
+    if (!ValueToId(cx, argc >= 2 ? vp[3] : UndefinedValue(), nameidr.addr()))
         return JS_FALSE;
-    return GetOwnPropertyDescriptor(cx, obj, id, vp);
+    return GetOwnPropertyDescriptor(cx, obj, nameidr.id(), vp);
 }
 
 static JSBool
 obj_keys(JSContext *cx, unsigned argc, Value *vp)
 {
     JSObject *obj;
     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.keys", &obj))
         return false;
@@ -1885,24 +1879,24 @@ Reject(JSContext *cx, JSObject *obj, uns
     if (throwError)
         return Throw(cx, obj, errorNumber);
 
     *rval = false;
     return JS_TRUE;
 }
 
 static JSBool
-DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropDesc &desc,
+DefinePropertyOnObject(JSContext *cx, JSObject *obj, const jsid &id, const PropDesc &desc,
                        bool throwError, bool *rval)
 {
     /* 8.12.9 step 1. */
     JSProperty *current;
-    RootedVarObject obj2(cx);
+    JSObject *obj2;
     JS_ASSERT(!obj->getOps()->lookupGeneric);
-    if (!js_HasOwnProperty(cx, NULL, obj, id, obj2.address(), &current))
+    if (!js_HasOwnProperty(cx, NULL, obj, id, &obj2, &current))
         return JS_FALSE;
 
     JS_ASSERT(!obj->getOps()->defineProperty);
 
     /* 8.12.9 steps 2-4. */
     if (!current) {
         if (!obj->isExtensible())
             return Reject(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval);
@@ -2185,27 +2179,27 @@ DefinePropertyOnObject(JSContext *cx, Ha
         if (!CallJSPropertyOp(cx, obj2->getClass()->delProperty, obj2, id, &dummy))
             return false;
     }
 
     return js_DefineProperty(cx, obj, id, &v, getter, setter, attrs);
 }
 
 static JSBool
-DefinePropertyOnArray(JSContext *cx, HandleObject obj, HandleId id, const PropDesc &desc,
+DefinePropertyOnArray(JSContext *cx, JSObject *obj, const jsid &id, const PropDesc &desc,
                       bool throwError, bool *rval)
 {
     /*
      * We probably should optimize dense array property definitions where
      * the descriptor describes a traditional array property (enumerable,
      * configurable, writable, numeric index or length without altering its
      * attributes).  Such definitions are probably unlikely, so we don't bother
      * for now.
      */
-    if (obj->isDenseArray() && !JSObject::makeDenseArraySlow(cx, obj))
+    if (obj->isDenseArray() && !obj->makeDenseArraySlow(cx))
         return JS_FALSE;
 
     uint32_t oldLen = obj->getArrayLength();
 
     if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
         /*
          * Our optimization of storage of the length property of arrays makes
          * it very difficult to properly implement defining the property.  For
@@ -2239,17 +2233,17 @@ DefinePropertyOnArray(JSContext *cx, Han
     }
 
     return DefinePropertyOnObject(cx, obj, id, desc, throwError, rval);
 }
 
 namespace js {
 
 bool
-DefineProperty(JSContext *cx, HandleObject obj, HandleId id, const PropDesc &desc, bool throwError,
+DefineProperty(JSContext *cx, JSObject *obj, const jsid &id, const PropDesc &desc, bool throwError,
                bool *rval)
 {
     if (obj->isArray())
         return DefinePropertyOnArray(cx, obj, id, desc, throwError, rval);
 
     if (obj->getOps()->lookupGeneric) {
         if (obj->isProxy())
             return Proxy::defineProperty(cx, obj, id, desc.pd);
@@ -2257,17 +2251,17 @@ DefineProperty(JSContext *cx, HandleObje
     }
 
     return DefinePropertyOnObject(cx, obj, id, desc, throwError, rval);
 }
 
 } /* namespace js */
 
 JSBool
-js_DefineOwnProperty(JSContext *cx, HandleObject obj, HandleId id, const Value &descriptor, JSBool *bp)
+js_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, const Value &descriptor, JSBool *bp)
 {
     AutoPropDescArrayRooter descs(cx);
     PropDesc *desc = descs.append();
     if (!desc || !desc->initialize(cx, descriptor))
         return false;
 
     bool rval;
     if (!DefineProperty(cx, obj, id, *desc, true, &rval))
@@ -2275,22 +2269,22 @@ js_DefineOwnProperty(JSContext *cx, Hand
     *bp = !!rval;
     return true;
 }
 
 /* ES5 15.2.3.6: Object.defineProperty(O, P, Attributes) */
 static JSBool
 obj_defineProperty(JSContext *cx, unsigned argc, Value *vp)
 {
-    RootedVarObject obj(cx);
-    if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.defineProperty", obj.address()))
+    JSObject *obj;
+    if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.defineProperty", &obj))
         return false;
 
-    RootedVarId id(cx);
-    if (!ValueToId(cx, argc >= 2 ? vp[3] : UndefinedValue(), id.address()))
+    jsid id;
+    if (!ValueToId(cx, argc >= 2 ? vp[3] : UndefinedValue(), &id))
         return JS_FALSE;
 
     const Value descval = argc >= 3 ? vp[4] : UndefinedValue();
 
     JSBool junk;
     if (!js_DefineOwnProperty(cx, obj, id, descval, &junk))
         return false;
 
@@ -2315,45 +2309,45 @@ ReadPropertyDescriptors(JSContext *cx, J
             return false;
     }
     return true;
 }
 
 } /* namespace js */
 
 static bool
-DefineProperties(JSContext *cx, HandleObject obj, JSObject *props)
+DefineProperties(JSContext *cx, JSObject *obj, JSObject *props)
 {
     AutoIdVector ids(cx);
     AutoPropDescArrayRooter descs(cx);
     if (!ReadPropertyDescriptors(cx, props, true, &ids, &descs))
         return false;
 
     bool dummy;
     for (size_t i = 0, len = ids.length(); i < len; i++) {
-        if (!DefineProperty(cx, obj, RootedVarId(cx, ids[i]), descs[i], true, &dummy))
+        if (!DefineProperty(cx, obj, ids[i], descs[i], true, &dummy))
             return false;
     }
 
     return true;
 }
 
 extern JSBool
-js_PopulateObject(JSContext *cx, HandleObject newborn, JSObject *props)
+js_PopulateObject(JSContext *cx, JSObject *newborn, JSObject *props)
 {
     return DefineProperties(cx, newborn, props);
 }
 
 /* ES5 15.2.3.7: Object.defineProperties(O, Properties) */
 static JSBool
 obj_defineProperties(JSContext *cx, unsigned argc, Value *vp)
 {
     /* Steps 1 and 7. */
-    RootedVarObject obj(cx);
-    if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.defineProperties", obj.address()))
+    JSObject *obj;
+    if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.defineProperties", &obj))
         return false;
     vp->setObject(*obj);
 
     /* Step 2. */
     if (argc < 2) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
                              "Object.defineProperties", "0", "s");
         return false;
@@ -2393,18 +2387,17 @@ obj_create(JSContext *cx, unsigned argc,
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_XML_PROTO_FORBIDDEN);
         return false;
     }
 
     /*
      * Use the callee's global as the parent of the new object to avoid dynamic
      * scoping (i.e., using the caller's global).
      */
-    RootedVarObject obj(cx);
-    obj = NewObjectWithGivenProto(cx, &ObjectClass, proto, &args.callee().global());
+    JSObject *obj = NewObjectWithGivenProto(cx, &ObjectClass, proto, &args.callee().global());
     if (!obj)
         return false;
 
     /* Don't track types or array-ness for objects created here. */
     MarkTypeObjectUnknownProperties(cx, obj->type());
 
     /* 15.2.3.5 step 4. */
     if (args.hasDefined(1)) {
@@ -2509,17 +2502,17 @@ JSObject::sealOrFreeze(JSContext *cx, Im
     } else {
         if (!GetPropertyNames(cx, this, 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()) {
+    if (isNative() && !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(),
@@ -2546,17 +2539,17 @@ JSObject::sealOrFreeze(JSContext *cx, Im
                 MarkTypePropertyConfigured(cx, self, child.propid);
 
             last = JS_PROPERTY_TREE(cx).getChild(cx, last, self->numFixedSlots(), child);
             if (!last)
                 return NULL;
         }
 
         JS_ASSERT(self->lastProperty()->slotSpan() == last->slotSpan());
-        JS_ALWAYS_TRUE(self->setLastProperty(cx, last));
+        JS_ALWAYS_TRUE(setLastProperty(cx, last));
     } else {
         for (size_t i = 0; i < props.length(); i++) {
             jsid id = props[i];
 
             unsigned attrs;
             if (!self->getGenericAttributes(cx, id, &attrs))
                 return false;
 
@@ -2860,17 +2853,17 @@ js::NewObjectWithClassProto(JSContext *c
 
     if (entry != -1 && !obj->hasDynamicSlots())
         cache.fillGlobal(entry, clasp, &parent->asGlobal(), kind, obj);
 
     return obj;
 }
 
 JSObject *
-js::NewObjectWithType(JSContext *cx, HandleTypeObject type, JSObject *parent, gc::AllocKind kind)
+js::NewObjectWithType(JSContext *cx, types::TypeObject *type, JSObject *parent, gc::AllocKind kind)
 {
     JS_ASSERT(type->proto->hasNewType(type));
     JS_ASSERT(parent);
 
     if (CanBeFinalizedInBackground(kind, &ObjectClass))
         kind = GetBackgroundAllocKind(kind);
 
     NewObjectCache &cache = cx->compartment->newObjectCache;
@@ -2887,20 +2880,20 @@ js::NewObjectWithType(JSContext *cx, Han
 
     if (entry != -1 && !obj->hasDynamicSlots())
         cache.fillType(entry, &ObjectClass, type, kind, obj);
 
     return obj;
 }
 
 JSObject *
-js::NewReshapedObject(JSContext *cx, HandleTypeObject type, JSObject *parent,
+js::NewReshapedObject(JSContext *cx, TypeObject *type, JSObject *parent,
                       gc::AllocKind kind, const Shape *shape)
 {
-    RootedVarObject res(cx, NewObjectWithType(cx, type, parent, kind));
+    JSObject *res = NewObjectWithType(cx, type, parent, kind);
     if (!res)
         return NULL;
 
     if (shape->isEmptyShape())
         return res;
 
     /* Get all the ids in the object, in order. */
     js::AutoIdVector ids(cx);
@@ -2935,17 +2928,17 @@ js_CreateThis(JSContext *cx, Class *newc
 
     JSObject *proto = protov.isObjectOrNull() ? protov.toObjectOrNull() : NULL;
     JSObject *parent = callee->getParent();
     gc::AllocKind kind = NewObjectGCKind(cx, newclasp);
     return NewObjectWithClassProto(cx, newclasp, proto, parent, kind);
 }
 
 static inline JSObject *
-CreateThisForFunctionWithType(JSContext *cx, HandleTypeObject type, JSObject *parent)
+CreateThisForFunctionWithType(JSContext *cx, types::TypeObject *type, JSObject *parent)
 {
     if (type->newScript) {
         /*
          * Make an object with the type's associated finalize kind and shape,
          * which reflects any properties that will definitely be added to the
          * object before it is read from.
          */
         gc::AllocKind kind = type->newScript->allocKind;
@@ -2955,38 +2948,38 @@ CreateThisForFunctionWithType(JSContext 
         return res;
     }
 
     gc::AllocKind kind = NewObjectGCKind(cx, &ObjectClass);
     return NewObjectWithType(cx, type, parent, kind);
 }
 
 JSObject *
-js_CreateThisForFunctionWithProto(JSContext *cx, HandleObject callee, JSObject *proto)
+js_CreateThisForFunctionWithProto(JSContext *cx, JSObject *callee, JSObject *proto)
 {
     JSObject *res;
 
     if (proto) {
-        RootedVarTypeObject type(cx, proto->getNewType(cx, callee->toFunction()));
+        types::TypeObject *type = proto->getNewType(cx, callee->toFunction());
         if (!type)
             return NULL;
         res = CreateThisForFunctionWithType(cx, type, callee->getParent());
     } else {
         gc::AllocKind kind = NewObjectGCKind(cx, &ObjectClass);
         res = NewObjectWithClassProto(cx, &ObjectClass, proto, callee->getParent(), kind);
     }
 
     if (res && cx->typeInferenceEnabled())
         TypeScript::SetThis(cx, callee->toFunction()->script(), types::Type::ObjectType(res));
 
     return res;
 }
 
 JSObject *
-js_CreateThisForFunction(JSContext *cx, HandleObject callee, bool newType)
+js_CreateThisForFunction(JSContext *cx, JSObject *callee, bool newType)
 {
     Value protov;
     if (!callee->getProperty(cx, cx->runtime->atomState.classPrototypeAtom, &protov))
         return NULL;
     JSObject *proto;
     if (protov.isObject())
         proto = &protov.toObject();
     else
@@ -3193,29 +3186,25 @@ CopySlots(JSContext *cx, JSObject *from,
         if (!cx->compartment->wrap(cx, &v))
             return false;
         to->setSlot(n, v);
     }
     return true;
 }
 
 JS_FRIEND_API(JSObject *)
-JS_CloneObject(JSContext *cx, JSObject *obj_, JSObject *proto_, JSObject *parent_)
-{
-    RootedVarObject obj(cx, obj_);
-    RootedVarObject proto(cx, proto_);
-    RootedVarObject parent(cx, parent_);
-
+JS_CloneObject(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent)
+{
     /*
      * We can only clone native objects and proxies. Dense arrays are slowified if
      * we try to clone them.
      */
     if (!obj->isNative()) {
         if (obj->isDenseArray()) {
-            if (!JSObject::makeDenseArraySlow(cx, obj))
+            if (!obj->makeDenseArraySlow(cx))
                 return NULL;
         } else if (!obj->isProxy()) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_CANT_CLONE_OBJECT);
             return NULL;
         }
     }
     JSObject *clone = NewObjectWithGivenProto(cx, obj->getClass(), proto, parent, obj->getAllocKind());
@@ -3638,17 +3627,17 @@ DefineConstructorAndPrototype(JSContext 
     RootedVarObject proto(cx);
     proto = NewObjectWithClassProto(cx, clasp, protoProto, obj);
     if (!proto)
         return NULL;
 
     if (!proto->setSingletonType(cx))
         return NULL;
 
-    if (clasp == &ArrayClass && !JSObject::makeDenseArraySlow(cx, proto))
+    if (clasp == &ArrayClass && !proto->makeDenseArraySlow(cx))
         return NULL;
 
     /* After this point, control must exit via label bad or out. */
     RootedVarObject ctor(cx);
     bool named = false;
     bool cached = false;
     if (!constructor) {
         /*
@@ -3909,18 +3898,17 @@ JSObject::growSlots(JSContext *cx, uint3
      * by calling 'new' on a particular script, bump the GC kind for that
      * type to give these objects a larger number of fixed slots when future
      * objects are constructed.
      */
     if (!hasLazyType() && !oldCount && type()->newScript) {
         gc::AllocKind kind = type()->newScript->allocKind;
         unsigned newScriptSlots = gc::GetGCKindSlots(kind);
         if (newScriptSlots == numFixedSlots() && gc::TryIncrementAllocKind(&kind)) {
-            JSObject *obj = NewReshapedObject(cx, RootedVarTypeObject(cx, type()),
-                                              getParent(), kind,
+            JSObject *obj = NewReshapedObject(cx, type(), getParent(), kind,
                                               type()->newScript->shape);
             if (!obj)
                 return false;
 
             type()->newScript->allocKind = kind;
             type()->newScript->shape = obj->lastProperty();
             type()->markStateChange(cx);
         }
@@ -4428,28 +4416,26 @@ js_AddNativeProperty(JSContext *cx, JSOb
      */
     if (!js_PurgeScopeChain(cx, obj, id))
         return NULL;
 
     return obj->putProperty(cx, id, getter, setter, slot, attrs, flags, shortid);
 }
 
 JSBool
-js_DefineProperty(JSContext *cx, JSObject *obj_, jsid id, const Value *value,
+js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
                   PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
-    RootObject obj(cx, &obj_);
     return !!DefineNativeProperty(cx, obj, id, *value, getter, setter, attrs, 0, 0);
 }
 
 JSBool
-js_DefineElement(JSContext *cx, JSObject *obj_, uint32_t index, const Value *value,
+js_DefineElement(JSContext *cx, JSObject *obj, uint32_t index, const Value *value,
                  PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
-    RootObject obj(cx, &obj_);
     jsid id;
     if (!IndexToId(cx, index, &id))
         return false;
     return !!DefineNativeProperty(cx, obj, id, *value, getter, setter, attrs, 0, 0);
 }
 
 /*
  * Backward compatibility requires allowing addProperty hooks to mutate the
@@ -4471,24 +4457,25 @@ CallAddPropertyHook(JSContext *cx, Class
         }
     }
     return true;
 }
 
 namespace js {
 
 const Shape *
-DefineNativeProperty(JSContext *cx, HandleObject obj, jsid id, const Value &value_,
+DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &value_,
                      PropertyOp getter, StrictPropertyOp setter, unsigned attrs,
                      unsigned flags, int shortid, unsigned defineHow /* = 0 */)
 {
     JS_ASSERT((defineHow & ~(DNP_CACHE_RESULT | DNP_DONT_PURGE |
                              DNP_SKIP_TYPE)) == 0);
     JS_ASSERT(!(attrs & JSPROP_NATIVE_ACCESSORS));
 
+    RootObject objRoot(cx, &obj);
     RootId idRoot(cx, &id);
 
     /* Make a local copy of value so addProperty can mutate its inout parameter. */
     RootedVarValue value(cx);
     value = value_;
 
     /* Convert string indices to integers if appropriate. */
     id = js_CheckForStringIndex(id);
@@ -4662,39 +4649,39 @@ CallResolveOp(JSContext *cx, JSObject *s
             *propp = (JSProperty *) shape;
         }
     }
 
     return true;
 }
 
 static JS_ALWAYS_INLINE bool
-LookupPropertyWithFlagsInline(JSContext *cx, JSObject *obj_, jsid id_, unsigned flags,
+LookupPropertyWithFlagsInline(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
                               JSObject **objp, JSProperty **propp)
 {
-    RootedVarObject obj(cx, obj_);
-    RootedVarId id(cx, id_);
-
     /* We should not get string indices which aren't already integers here. */
-    JS_ASSERT(id.raw() == js_CheckForStringIndex(id));
+    JS_ASSERT(id == js_CheckForStringIndex(id));
+
+    RootObject objRoot(cx, &obj);
+    RootId idRoot(cx, &id);
 
     /* Search scopes starting with obj and following the prototype link. */
-    RootedVarObject start(cx, obj);
+    JSObject *start = obj;
     while (true) {
         const Shape *shape = obj->nativeLookup(cx, id);
         if (shape) {
             *objp = obj;
             *propp = (JSProperty *) shape;
             return true;
         }
 
         /* Try obj's class resolve hook if id was not found in obj's scope. */
         if (obj->getClass()->resolve != JS_ResolveStub) {
             bool recursed;
-            if (!CallResolveOp(cx, start, obj, id, flags, objp, propp, &recursed))
+            if (!CallResolveOp(cx, start, objRoot, idRoot, flags, objp, propp, &recursed))
                 return false;
             if (recursed)
                 break;
             if (*propp) {
                 /*
                  * For stats we do not recalculate protoIndex even if it was
                  * resolved on some other object.
                  */
@@ -4760,29 +4747,27 @@ js::LookupPropertyWithFlags(JSContext *c
 {
     /* Convert string indices to integers if appropriate. */
     id = js_CheckForStringIndex(id);
 
     return LookupPropertyWithFlagsInline(cx, obj, id, flags, objp, propp);
 }
 
 bool
-js::FindPropertyHelper(JSContext *cx,
-                       HandlePropertyName name, bool cacheResult, HandleObject scopeChain,
+js::FindPropertyHelper(JSContext *cx, PropertyName *name, bool cacheResult, JSObject *scopeChain,
                        JSObject **objp, JSObject **pobjp, JSProperty **propp)
 {
-    RootedVarId id(cx, ATOM_TO_JSID(name));
-
-    JSObject *pobj;
+    jsid id = ATOM_TO_JSID(name);
+    JSObject *obj, *parent, *pobj;
     int scopeIndex;
     JSProperty *prop;
 
     /* Scan entries on the scope chain that we can cache across. */
-    RootedVarObject obj(cx, scopeChain);
-    RootedVarObject parent(cx, obj->enclosingScope());
+    obj = scopeChain;
+    parent = obj->enclosingScope();
     for (scopeIndex = 0;
          parent
          ? IsCacheableNonGlobalScope(obj)
          : !obj->getOps()->lookupProperty;
          ++scopeIndex) {
         if (!LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, &pobj, &prop))
             return false;
 
@@ -4854,17 +4839,17 @@ js::FindPropertyHelper(JSContext *cx,
     return true;
 }
 
 /*
  * On return, if |*pobjp| is a native object, then |*propp| is a |Shape *|.
  * Otherwise, its type and meaning depends on the host object's implementation.
  */
 bool
-js::FindProperty(JSContext *cx, HandlePropertyName name, HandleObject scopeChain,
+js::FindProperty(JSContext *cx, PropertyName *name, JSObject *scopeChain,
                  JSObject **objp, JSObject **pobjp, JSProperty **propp)
 {
     return !!FindPropertyHelper(cx, name, false, scopeChain, objp, pobjp, propp);
 }
 
 JSObject *
 js::FindIdentifierBase(JSContext *cx, JSObject *scopeChain, PropertyName *name)
 {
@@ -4950,19 +4935,16 @@ js_NativeGetInline(JSContext *cx, JSObje
     jsbytecode *pc;
     JSScript *script = cx->stack.currentScript(&pc);
     if (script && script->hasAnalysis()) {
         analyze::Bytecode *code = script->analysis()->maybeCode(pc);
         if (code)
             code->accessGetter = true;
     }
 
-    Root<const Shape*> rootShape(cx, &shape);
-    RootObject pobjRoot(cx, &pobj);
-
     if (!shape->get(cx, receiver, obj, pobj, vp))
         return false;
 
     /* Update slotful shapes according to the value produced by the getter. */
     if (shape->hasSlot() && pobj->nativeContains(cx, *shape))
         pobj->nativeSetSlot(shape->slot(), *vp);
 
     return true;
@@ -4996,19 +4978,16 @@ js_NativeSet(JSContext *cx, JSObject *ob
          * Such properties effectively function as data descriptors which are
          * not writable, so attempting to set such a property should do nothing
          * or throw if we're in strict mode.
          */
         if (!shape->hasGetterValue() && shape->hasDefaultSetter())
             return js_ReportGetterOnlyAssignment(cx);
     }
 
-    RootObject objRoot(cx, &obj);
-    Root<const Shape *> shapeRoot(cx, &shape);
-
     int32_t sample = cx->runtime->propertyRemovals;
     if (!shape->set(cx, obj, strict, vp))
         return false;
 
     /*
      * Update any slot for the shape with the value produced by the setter,
      * unless the setter deleted the shape.
      */
@@ -5017,29 +4996,29 @@ js_NativeSet(JSContext *cx, JSObject *ob
          obj->nativeContains(cx, *shape))) {
         obj->setSlot(shape->slot(), *vp);
     }
 
     return true;
 }
 
 static JS_ALWAYS_INLINE JSBool
-js_GetPropertyHelperInline(JSContext *cx, HandleObject obj, HandleObject receiver, jsid id_,
+js_GetPropertyHelperInline(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id,
                            uint32_t getHow, Value *vp)
 {
+    JSObject *aobj, *obj2;
     JSProperty *prop;
-
-    RootedVarId id(cx, id_);
+    const Shape *shape;
 
     /* Convert string indices to integers if appropriate. */
     id = js_CheckForStringIndex(id);
 
+    aobj = js_GetProtoIfDenseArray(obj);
     /* This call site is hot -- use the always-inlined variant of LookupPropertyWithFlags(). */
-    RootedVarObject obj2(cx);
-    if (!LookupPropertyWithFlagsInline(cx, obj, id, cx->resolveFlags, obj2.address(), &prop))
+    if (!LookupPropertyWithFlagsInline(cx, aobj, id, cx->resolveFlags, &obj2, &prop))
         return false;
 
     if (!prop) {
         vp->setUndefined();
 
         if (!CallJSPropertyOp(cx, obj->getClass()->getProperty, obj, id, vp))
             return JS_FALSE;
 
@@ -5100,70 +5079,70 @@ js_GetPropertyHelperInline(JSContext *cx
     }
 
     if (!obj2->isNative()) {
         return obj2->isProxy()
                ? Proxy::get(cx, obj2, receiver, id, vp)
                : obj2->getGeneric(cx, id, vp);
     }
 
-    Shape *shape = (Shape *) prop;
+    shape = (Shape *) prop;
 
     if (getHow & JSGET_CACHE_RESULT)
-        JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, obj2, shape);
+        JS_PROPERTY_CACHE(cx).fill(cx, aobj, 0, 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))
         return JS_FALSE;
 
     return JS_TRUE;
 }
 
 bool
-js::GetPropertyHelper(JSContext *cx, HandleObject obj, jsid id, uint32_t getHow, Value *vp)
+js::GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uint32_t getHow, Value *vp)
 {
     return !!js_GetPropertyHelperInline(cx, obj, obj, id, getHow, vp);
 }
 
 JSBool
-js_GetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, jsid id, Value *vp)
+js_GetProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
 {
     /* This call site is hot -- use the always-inlined variant of js_GetPropertyHelper(). */
     return js_GetPropertyHelperInline(cx, obj, receiver, id, 0, vp);
 }
 
 JSBool
-js_GetElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index, Value *vp)
+js_GetElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index, Value *vp)
 {
     jsid id;
     if (!IndexToId(cx, index, &id))
         return false;
 
     /* This call site is hot -- use the always-inlined variant of js_GetPropertyHelper(). */
     return js_GetPropertyHelperInline(cx, obj, receiver, id, 0, vp);
 }
 
 JSBool
-js::GetPropertyDefault(JSContext *cx, HandleObject obj, HandleId id, const Value &def, Value *vp)
+js::GetPropertyDefault(JSContext *cx, JSObject *obj, jsid id, const Value &def, Value *vp)
 {
     JSProperty *prop;
-    RootedVarObject obj2(cx);
-    if (!LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, obj2.address(), &prop))
+    JSObject *obj2;
+    if (!LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop))
         return false;
 
     if (!prop) {
         *vp = def;
         return true;
     }
 
     return js_GetProperty(cx, obj2, id, vp);
 }
 
 JSBool
-js_GetMethod(JSContext *cx, HandleObject obj, jsid id, unsigned getHow, Value *vp)
+js_GetMethod(JSContext *cx, JSObject *obj, jsid id, unsigned getHow, Value *vp)
 {
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
 
     GenericIdOp op = obj->getOps()->getGeneric;
     if (!op) {
 #if JS_HAS_XML_SUPPORT
         JS_ASSERT(!obj->isXML());
 #endif
@@ -5221,35 +5200,35 @@ JSObject::reportNotExtensible(JSContext 
                                     JSDVG_IGNORE_STACK, ObjectValue(*this),
                                     NULL, NULL, NULL);
 }
 
 bool
 JSObject::callMethod(JSContext *cx, jsid id, unsigned argc, Value *argv, Value *vp)
 {
     Value fval;
-    return js_GetMethod(cx, RootedVarObject(cx, this), id, 0, &fval) &&
+    return js_GetMethod(cx, this, id, 0, &fval) &&
            Invoke(cx, ObjectValue(*this), fval, argc, argv, vp);
 }
 
 JSBool
-js_SetPropertyHelper(JSContext *cx, HandleObject obj, jsid id, unsigned defineHow,
+js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, unsigned defineHow,
                      Value *vp, JSBool strict)
 {
     JSObject *pobj;
     JSProperty *prop;
+    const Shape *shape;
     unsigned attrs, flags;
     int shortid;
     Class *clasp;
     PropertyOp getter;
     StrictPropertyOp setter;
     bool added;
 
     JS_ASSERT((defineHow & ~(DNP_CACHE_RESULT | DNP_UNQUALIFIED)) == 0);
-    RootId idRoot(cx, &id);
 
     /* Convert string indices to integers if appropriate. */
     id = js_CheckForStringIndex(id);
 
     if (JS_UNLIKELY(obj->watched())) {
         /* Fire watchpoints, if any. */
         WatchpointMap *wpmap = cx->compartment->watchpointMap;
         if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, vp))
@@ -5286,18 +5265,17 @@ js_SetPropertyHelper(JSContext *cx, Hand
         JS_ASSERT(!obj->isBlock());
 
         if (obj->isGlobal() &&
             (defineHow & DNP_UNQUALIFIED) &&
             !js::CheckUndeclaredVarAssignment(cx, JSID_TO_STRING(id))) {
             return JS_FALSE;
         }
     }
-
-    RootedVarShape shape(cx, (Shape *) prop);
+    shape = (Shape *) prop;
 
     /*
      * Now either shape is null, meaning id was not found in obj or one of its
      * prototypes; or shape is non-null, meaning id was found directly in pobj.
      */
     attrs = JSPROP_ENUMERATE;
     flags = 0;
     shortid = 0;
@@ -5415,17 +5393,17 @@ js_SetPropertyHelper(JSContext *cx, Hand
 
     if ((defineHow & DNP_CACHE_RESULT) && !added)
         JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, obj, shape);
 
     return js_NativeSet(cx, obj, shape, added, strict, vp);
 }
 
 JSBool
-js_SetElementHelper(JSContext *cx, HandleObject obj, uint32_t index, unsigned defineHow,
+js_SetElementHelper(JSContext *cx, JSObject *obj, uint32_t index, unsigned defineHow,
                     Value *vp, JSBool strict)
 {
     jsid id;
     if (!IndexToId(cx, index, &id))
         return false;
     return js_SetPropertyHelper(cx, obj, id, defineHow, vp, strict);
 }
 
@@ -5553,17 +5531,17 @@ JSBool
 js_DeleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *rval, JSBool strict)
 {
     return js_DeleteGeneric(cx, obj, SPECIALID_TO_JSID(sid), rval, strict);
 }
 
 namespace js {
 
 bool
-HasDataProperty(JSContext *cx, HandleObject obj, jsid id, Value *vp)
+HasDataProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     JS_ASSERT(id == js_CheckForStringIndex(id));
     if (const Shape *shape = obj->nativeLookup(cx, id)) {
         if (shape->hasDefaultGetter() && shape->hasSlot()) {
             *vp = obj->nativeGetSlot(shape->slot());
             return true;
         }
     }
@@ -5575,40 +5553,40 @@ HasDataProperty(JSContext *cx, HandleObj
  * Gets |obj[id]|.  If that value's not callable, returns true and stores a
  * non-primitive value in *vp.  If it's callable, calls it with no arguments
  * and |obj| as |this|, returning the result in *vp.
  *
  * This is a mini-abstraction for ES5 8.12.8 [[DefaultValue]], either steps 1-2
  * or steps 3-4.
  */
 static bool
-MaybeCallMethod(JSContext *cx, HandleObject obj, jsid id, Value *vp)
+MaybeCallMethod(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     if (!js_GetMethod(cx, obj, id, 0, vp))
         return false;
     if (!js_IsCallable(*vp)) {
         *vp = ObjectValue(*obj);
         return true;
     }
     return Invoke(cx, ObjectValue(*obj), *vp, 0, NULL, vp);
 }
 
 JSBool
-DefaultValue(JSContext *cx, HandleObject obj, JSType hint, Value *vp)
+DefaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp)
 {
     JS_ASSERT(hint == JSTYPE_NUMBER || hint == JSTYPE_STRING || hint == JSTYPE_VOID);
     JS_ASSERT(!obj->isXML());
 
     Class *clasp = obj->getClass();
     if (hint == JSTYPE_STRING) {
         /* Optimize (new String(...)).toString(). */
         if (clasp == &StringClass &&
             ClassMethodIsNative(cx, obj,
                                  &StringClass,
-                                 RootedVarId(cx, ATOM_TO_JSID(cx->runtime->atomState.toStringAtom)),
+                                 ATOM_TO_JSID(cx->runtime->atomState.toStringAtom),
                                  js_str_toString)) {
             *vp = StringValue(obj->asString().unbox());
             return true;
         }
 
         if (!MaybeCallMethod(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.toStringAtom), vp))
             return false;
         if (vp->isPrimitive())
@@ -5617,21 +5595,21 @@ DefaultValue(JSContext *cx, HandleObject
         if (!MaybeCallMethod(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom), vp))
             return false;
         if (vp->isPrimitive())
             return true;
     } else {
         /* Optimize (new String(...)).valueOf(). */
         if ((clasp == &StringClass &&
              ClassMethodIsNative(cx, obj, &StringClass,
-                                 RootedVarId(cx, ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom)),
+                                 ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom),
                                  js_str_toString)) ||
             (clasp == &NumberClass &&
              ClassMethodIsNative(cx, obj, &NumberClass,
-                                 RootedVarId(cx, ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom)),
+                                 ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom),
                                  js_num_valueOf))) {
             *vp = obj->isString()
                   ? StringValue(obj->asString().unbox())
                   : NumberValue(obj->asNumber().unbox());
             return true;
         }
 
         if (!MaybeCallMethod(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom), vp))
@@ -5831,17 +5809,17 @@ js_GetClassPrototype(JSContext *cx, JSOb
 
     return FindClassPrototype(cx, scopeobj, protoKey, protop, clasp);
 }
 
 JSObject *
 PrimitiveToObject(JSContext *cx, const Value &v)
 {
     if (v.isString())
-        return StringObject::create(cx, RootedVarString(cx, v.toString()));
+        return StringObject::create(cx, v.toString());
     if (v.isNumber())
         return NumberObject::create(cx, v.toNumber());
 
     JS_ASSERT(v.isBoolean());
     return BooleanObject::create(cx, v.toBoolean());
 }
 
 JSBool
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -268,57 +268,57 @@ extern JSBool
 js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const js::Value *value,
                   JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs);
 
 extern JSBool
 js_DefineElement(JSContext *cx, JSObject *obj, uint32_t index, const js::Value *value,
                  JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs);
 
 extern JSBool
-js_GetProperty(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, jsid id, js::Value *vp);
+js_GetProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, js::Value *vp);
 
 extern JSBool
-js_GetElement(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, uint32_t, js::Value *vp);
+js_GetElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t, js::Value *vp);
 
 inline JSBool
-js_GetProperty(JSContext *cx, js::HandleObject obj, jsid id, js::Value *vp)
+js_GetProperty(JSContext *cx, JSObject *obj, jsid id, js::Value *vp)
 {
     return js_GetProperty(cx, obj, obj, id, vp);
 }
 
 inline JSBool
-js_GetElement(JSContext *cx, js::HandleObject obj, uint32_t index, js::Value *vp)
+js_GetElement(JSContext *cx, JSObject *obj, uint32_t index, js::Value *vp)
 {
     return js_GetElement(cx, obj, obj, index, vp);
 }
 
 namespace js {
 
 extern JSBool
-GetPropertyDefault(JSContext *cx, js::HandleObject obj, js::HandleId id, const Value &def, Value *vp);
+GetPropertyDefault(JSContext *cx, JSObject *obj, jsid id, const Value &def, Value *vp);
 
 } /* namespace js */
 
 extern JSBool
-js_SetPropertyHelper(JSContext *cx, js::HandleObject obj, jsid id, unsigned defineHow,
+js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, unsigned defineHow,
                      js::Value *vp, JSBool strict);
 
 namespace js {
 
 inline bool
-SetPropertyHelper(JSContext *cx, HandleObject obj, PropertyName *name, unsigned defineHow,
+SetPropertyHelper(JSContext *cx, JSObject *obj, PropertyName *name, unsigned defineHow,
                   Value *vp, JSBool strict)
 {
     return !!js_SetPropertyHelper(cx, obj, ATOM_TO_JSID(name), defineHow, vp, strict);
 }
 
 } /* namespace js */
 
 extern JSBool
-js_SetElementHelper(JSContext *cx, js::HandleObject obj, uint32_t index, unsigned defineHow,
+js_SetElementHelper(JSContext *cx, JSObject *obj, uint32_t index, unsigned defineHow,
                     js::Value *vp, JSBool strict);
 
 extern JSBool
 js_GetAttributes(JSContext *cx, JSObject *obj, jsid id, unsigned *attrsp);
 
 extern JSBool
 js_GetElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, unsigned *attrsp);
 
@@ -342,17 +342,17 @@ js_DeleteGeneric(JSContext *cx, JSObject
 
 extern JSType
 js_TypeOf(JSContext *cx, JSObject *obj);
 
 namespace js {
 
 /* ES5 8.12.8. */
 extern JSBool
-DefaultValue(JSContext *cx, HandleObject obj, JSType hint, Value *vp);
+DefaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp);
 
 extern Class ArrayClass;
 extern Class ArrayBufferClass;
 extern Class BlockClass;
 extern Class BooleanClass;
 extern Class CallableObjectClass;
 extern Class DateClass;
 extern Class ErrorClass;
@@ -734,17 +734,17 @@ struct JSObject : public js::ObjectImpl
     inline EnsureDenseResult ensureDenseArrayElements(JSContext *cx, unsigned index, unsigned extra);
 
     /*
      * Check if after growing the dense array will be too sparse.
      * newElementsHint is an estimated number of elements to be added.
      */
     bool willBeSparseDenseArray(unsigned requiredCapacity, unsigned newElementsHint);
 
-    static bool makeDenseArraySlow(JSContext *cx, js::HandleObject obj);
+    JSBool makeDenseArraySlow(JSContext *cx);
 
     /*
      * If this array object has a data property with index i, set *vp to its
      * value and return true. If not, do vp->setMagic(JS_ARRAY_HOLE) and return
      * true. On OOM, report it and return false.
      */
     bool arrayGetOwnDataElement(JSContext *cx, size_t i, js::Value *vp);
 
@@ -1175,17 +1175,17 @@ js_LeaveSharpObject(JSContext *cx, JSIdA
 extern void
 js_TraceSharpMap(JSTracer *trc, JSSharpObjectMap *map);
 
 extern JSBool
 js_HasOwnPropertyHelper(JSContext *cx, js::LookupGenericOp lookup, unsigned argc,
                         js::Value *vp);
 
 extern JSBool
-js_HasOwnProperty(JSContext *cx, js::LookupGenericOp lookup, js::HandleObject obj, jsid id,
+js_HasOwnProperty(JSContext *cx, js::LookupGenericOp lookup, JSObject *obj, jsid id,
                   JSObject **objp, JSProperty **propp);
 
 extern JSBool
 js_PropertyIsEnumerable(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
 
 #if JS_HAS_OBJ_PROTO_PROP
 extern JSPropertySpec object_props[];
 #else
@@ -1294,17 +1294,17 @@ extern const char js_propertyIsEnumerabl
 #ifdef OLD_GETTER_SETTER_METHODS
 extern const char js_defineGetter_str[];
 extern const char js_defineSetter_str[];
 extern const char js_lookupGetter_str[];
 extern const char js_lookupSetter_str[];
 #endif
 
 extern JSBool
-js_PopulateObject(JSContext *cx, js::HandleObject newborn, JSObject *props);
+js_PopulateObject(JSContext *cx, JSObject *newborn, JSObject *props);
 
 /*
  * Fast access to immutable standard objects (constructors and prototypes).
  */
 extern JSBool
 js_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key,
                   JSObject **objp);
 
@@ -1314,21 +1314,21 @@ js_GetClassObject(JSContext *cx, JSObjec
  */
 extern JSBool
 js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey key,
                    js::Value *vp, js::Class *clasp = NULL);
 
 // Specialized call for constructing |this| with a known function callee,
 // and a known prototype.
 extern JSObject *
-js_CreateThisForFunctionWithProto(JSContext *cx, js::HandleObject callee, JSObject *proto);
+js_CreateThisForFunctionWithProto(JSContext *cx, JSObject *callee, JSObject *proto);
 
 // Specialized call for constructing |this| with a known function callee.
 extern JSObject *
-js_CreateThisForFunction(JSContext *cx, js::HandleObject callee, bool newType);
+js_CreateThisForFunction(JSContext *cx, JSObject *callee, bool newType);
 
 // Generic call for constructing |this|.
 extern JSObject *
 js_CreateThis(JSContext *cx, js::Class *clasp, JSObject *callee);
 
 extern jsid
 js_CheckForStringIndex(jsid id);
 
@@ -1337,17 +1337,17 @@ js_CheckForStringIndex(jsid id);
  * and setter, slot, attributes, and other members.
  */
 extern js::Shape *
 js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id,
                      JSPropertyOp getter, JSStrictPropertyOp setter, uint32_t slot,
                      unsigned attrs, unsigned flags, int shortid);
 
 extern JSBool
-js_DefineOwnProperty(JSContext *cx, js::HandleObject obj, js::HandleId id,
+js_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id,
                      const js::Value &descriptor, JSBool *bp);
 
 namespace js {
 
 /*
  * Flags for the defineHow parameter of js_DefineNativeProperty.
  */
 const unsigned DNP_CACHE_RESULT = 1;   /* an interpreter call from JSOP_INITPROP */
@@ -1356,22 +1356,22 @@ const unsigned DNP_UNQUALIFIED  = 4;   /
                                        the defineHow argument of
                                        js_SetPropertyHelper. */
 const unsigned DNP_SKIP_TYPE    = 8;   /* Don't update type information */
 
 /*
  * Return successfully added or changed shape or NULL on error.
  */
 extern const Shape *
-DefineNativeProperty(JSContext *cx, HandleObject obj, jsid id, const Value &value,
+DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &value,
                      PropertyOp getter, StrictPropertyOp setter, unsigned attrs,
                      unsigned flags, int shortid, unsigned defineHow = 0);
 
 inline const Shape *
-DefineNativeProperty(JSContext *cx, HandleObject obj, PropertyName *name, const Value &value,
+DefineNativeProperty(JSContext *cx, JSObject *obj, PropertyName *name, const Value &value,
                      PropertyOp getter, StrictPropertyOp setter, unsigned attrs,
                      unsigned flags, int shortid, unsigned defineHow = 0)
 {
     return DefineNativeProperty(cx, obj, ATOM_TO_JSID(name), value, getter, setter, attrs, flags,
                                 shortid, defineHow);
 }
 
 /*
@@ -1392,18 +1392,17 @@ LookupPropertyWithFlags(JSContext *cx, J
  * Call the [[DefineOwnProperty]] internal method of obj.
  *
  * If obj is an array, this follows ES5 15.4.5.1.
  * If obj is any other native object, this follows ES5 8.12.9.
  * If obj is a proxy, this calls the proxy handler's defineProperty method.
  * Otherwise, this reports an error and returns false.
  */
 extern bool
-DefineProperty(JSContext *cx, js::HandleObject obj,
-               js::HandleId id, const PropDesc &desc, bool throwError,
+DefineProperty(JSContext *cx, JSObject *obj, const jsid &id, const PropDesc &desc, bool throwError,
                bool *rval);
 
 /*
  * Read property descriptors from props, as for Object.defineProperties. See
  * ES5 15.2.3.7 steps 3-5.
  */
 extern bool
 ReadPropertyDescriptors(JSContext *cx, JSObject *props, bool checkAccessors,
@@ -1414,26 +1413,25 @@ ReadPropertyDescriptors(JSContext *cx, J
  * bytecode.
  */
 static const unsigned RESOLVE_INFER = 0xffff;
 
 /*
  * If cacheResult is false, return JS_NO_PROP_CACHE_FILL on success.
  */
 extern bool
-FindPropertyHelper(JSContext *cx, HandlePropertyName name,
-                   bool cacheResult, HandleObject scopeChain,
+FindPropertyHelper(JSContext *cx, PropertyName *name, bool cacheResult, JSObject *scopeChain,
                    JSObject **objp, JSObject **pobjp, JSProperty **propp);
 
 /*
  * Search for name either on the current scope chain or on the scope chain's
  * global object, per the global parameter.
  */
 extern bool
-FindProperty(JSContext *cx, HandlePropertyName name, HandleObject scopeChain,
+FindProperty(JSContext *cx, PropertyName *name, JSObject *scopeChain,
              JSObject **objp, JSObject **pobjp, JSProperty **propp);
 
 extern JSObject *
 FindIdentifierBase(JSContext *cx, JSObject *scopeChain, PropertyName *name);
 
 }
 
 extern JSObject *
@@ -1454,60 +1452,60 @@ js_NativeGet(JSContext *cx, JSObject *ob
 
 extern JSBool
 js_NativeSet(JSContext *cx, JSObject *obj, const js::Shape *shape, bool added,
              bool strict, js::Value *vp);
 
 namespace js {
 
 bool
-GetPropertyHelper(JSContext *cx, HandleObject obj, jsid id, uint32_t getHow, Value *vp);
+GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uint32_t getHow, Value *vp);
 
 inline bool
-GetPropertyHelper(JSContext *cx, HandleObject obj, PropertyName *name, uint32_t getHow, Value *vp)
+GetPropertyHelper(JSContext *cx, JSObject *obj, PropertyName *name, uint32_t getHow, Value *vp)
 {
     return GetPropertyHelper(cx, obj, ATOM_TO_JSID(name), getHow, vp);
 }
 
 bool
-GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, PropertyDescriptor *desc);
+GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, PropertyDescriptor *desc);
 
 bool
-GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, Value *vp);
+GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, Value *vp);
 
 bool
 NewPropertyDescriptorObject(JSContext *cx, const PropertyDescriptor *desc, Value *vp);
 
 } /* namespace js */
 
 extern JSBool
-js_GetMethod(JSContext *cx, js::HandleObject obj, jsid id, unsigned getHow, js::Value *vp);
+js_GetMethod(JSContext *cx, JSObject *obj, jsid id, unsigned getHow, js::Value *vp);
 
 namespace js {
 
 inline bool
-GetMethod(JSContext *cx, HandleObject obj, PropertyName *name, unsigned getHow, Value *vp)
+GetMethod(JSContext *cx, JSObject *obj, PropertyName *name, unsigned getHow, Value *vp)
 {
     return js_GetMethod(cx, obj, ATOM_TO_JSID(name), getHow, vp);
 }
 
 } /* namespace js */
 
 namespace js {
 
 /*
  * If obj has an already-resolved data property for id, return true and
  * store the property value in *vp. This helper assumes the caller has already
  * called js_CheckForStringIndex.
  */
 extern bool
-HasDataProperty(JSContext *cx, HandleObject obj, jsid id, Value *vp);
+HasDataProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp);
 
 inline bool
-HasDataProperty(JSContext *cx, HandleObject obj, JSAtom *atom, Value *vp)
+HasDataProperty(JSContext *cx, JSObject *obj, JSAtom *atom, Value *vp)
 {
     return HasDataProperty(cx, obj, js_CheckForStringIndex(ATOM_TO_JSID(atom)), vp);
 }
 
 extern JSBool
 CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
             js::Value *vp, unsigned *attrsp);
 
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -91,21 +91,17 @@ JSObject::enumerate(JSContext *cx, JSIte
     JSNewEnumerateOp op = getOps()->enumerate;
     return (op ? op : JS_EnumerateState)(cx, this, iterop, statep, idp);
 }
 
 inline bool
 JSObject::defaultValue(JSContext *cx, JSType hint, js::Value *vp)
 {
     JSConvertOp op = getClass()->convert;
-    bool ok;
-    if (op == JS_ConvertStub)
-        ok = js::DefaultValue(cx, js::RootedVarObject(cx, this), hint, vp);
-    else
-        ok = op(cx, this, hint, vp);
+    bool ok = (op == JS_ConvertStub ? js::DefaultValue : op)(cx, this, hint, vp);
     JS_ASSERT_IF(ok, vp->isPrimitive());
     return ok;
 }
 
 inline JSType
 JSObject::typeOf(JSContext *cx)
 {
     js::TypeOfOp op = getOps()->typeOf;
@@ -119,34 +115,31 @@ JSObject::thisObject(JSContext *cx)
     return op ? op(cx, this) : this;
 }
 
 inline JSBool
 JSObject::setGeneric(JSContext *cx, jsid id, js::Value *vp, JSBool strict)
 {
     if (getOps()->setGeneric)
         return nonNativeSetProperty(cx, id, vp, strict);
-    return js_SetPropertyHelper(cx,
-                                js::RootedVarObject(cx, this),
-                                js::RootedVarId(cx, id),
-                                0, vp, strict);
+    return js_SetPropertyHelper(cx, this, id, 0, vp, strict);
 }
 
 inline JSBool
 JSObject::setProperty(JSContext *cx, js::PropertyName *name, js::Value *vp, JSBool strict)
 {
     return setGeneric(cx, ATOM_TO_JSID(name), vp, strict);
 }
 
 inline JSBool
 JSObject::setElement(JSContext *cx, uint32_t index, js::Value *vp, JSBool strict)
 {
     if (getOps()->setElement)
         return nonNativeSetElement(cx, index, vp, strict);
-    return js_SetElementHelper(cx, js::RootedVarObject(cx, this), index, 0, vp, strict);
+    return js_SetElementHelper(cx, this, index, 0, vp, strict);
 }
 
 inline JSBool
 JSObject::setSpecial(JSContext *cx, js::SpecialId sid, js::Value *vp, JSBool strict)
 {
     return setGeneric(cx, SPECIALID_TO_JSID(sid), vp, strict);
 }
 
@@ -186,17 +179,17 @@ JSObject::changePropertyAttributes(JSCon
 inline JSBool
 JSObject::getGeneric(JSContext *cx, JSObject *receiver, jsid id, js::Value *vp)
 {
     js::GenericIdOp op = getOps()->getGeneric;
     if (op) {
         if (!op(cx, this, receiver, id, vp))
             return false;
     } else {
-        if (!js_GetProperty(cx, js::RootedVarObject(cx, this), js::RootedVarObject(cx, receiver), id, vp))
+        if (!js_GetProperty(cx, this, receiver, id, vp))
             return false;
     }
     return true;
 }
 
 inline JSBool
 JSObject::getProperty(JSContext *cx, JSObject *receiver, js::PropertyName *name, js::Value *vp)
 {
@@ -1537,21 +1530,21 @@ bool
 FindClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, JSObject **protop,
                    Class *clasp);
 
 /*
  * Create a plain object with the specified type. This bypasses getNewType to
  * avoid losing creation site information for objects made by scripted 'new'.
  */
 JSObject *
-NewObjectWithType(JSContext *cx, HandleTypeObject type, JSObject *parent, gc::AllocKind kind);
+NewObjectWithType(JSContext *cx, types::TypeObject *type, JSObject *parent, gc::AllocKind kind);
 
 /* Make an object with pregenerated shape from a NEWOBJECT bytecode. */
 static inline JSObject *
-CopyInitializerObject(JSContext *cx, HandleObject baseobj)
+CopyInitializerObject(JSContext *cx, JSObject *baseobj)
 {
     JS_ASSERT(baseobj->getClass() == &ObjectClass);
     JS_ASSERT(!baseobj->inDictionaryMode());
 
     gc::AllocKind kind = gc::GetGCObjectFixedSlotsKind(baseobj->numFixedSlots());
 #ifdef JS_THREADSAFE
     kind = gc::GetBackgroundAllocKind(kind);
 #endif
@@ -1563,17 +1556,17 @@ CopyInitializerObject(JSContext *cx, Han
 
     if (!obj->setLastProperty(cx, baseobj->lastProperty()))
         return NULL;
 
     return obj;
 }
 
 JSObject *
-NewReshapedObject(JSContext *cx, HandleTypeObject type, JSObject *parent,
+NewReshapedObject(JSContext *cx, js::types::TypeObject *type, JSObject *parent,
                   gc::AllocKind kind, const Shape *shape);
 
 /*
  * As for gc::GetGCObjectKind, where numSlots is a guess at the final size of
  * the object, zero if the final size is unknown. This should only be used for
  * objects that do not require any fixed slots.
  */
 static inline gc::AllocKind
@@ -1735,16 +1728,22 @@ DefineConstructorAndPrototype(JSContext 
 extern JSObject *
 js_InitClass(JSContext *cx, js::HandleObject obj, JSObject *parent_proto,
              js::Class *clasp, JSNative constructor, unsigned nargs,
              JSPropertySpec *ps, JSFunctionSpec *fs,
              JSPropertySpec *static_ps, JSFunctionSpec *static_fs,
              JSObject **ctorp = NULL,
              js::gc::AllocKind ctorKind = JSFunction::FinalizeKind);
 
+inline JSObject *
+js_GetProtoIfDenseArray(JSObject *obj)
+{
+    return obj->isDenseArray() ? obj->getProto() : obj;
+}
+
 /*
  * js_PurgeScopeChain does nothing if obj is not itself a prototype or parent
  * scope, else it reshapes the scope and prototype chains it links. It calls
  * js_PurgeScopeChainHelper, which asserts that obj is flagged as a delegate
  * (i.e., obj has ever been on a prototype or parent chain).
  */
 extern bool
 js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj, jsid id);
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -307,17 +307,17 @@ static bool
 PreprocessValue(JSContext *cx, JSObject *holder, KeyType key, Value *vp, StringifyContext *scx)
 {
     JSString *keyStr = NULL;
 
     /* Step 2. */
     if (vp->isObject()) {
         Value toJSON;
         jsid id = ATOM_TO_JSID(cx->runtime->atomState.toJSONAtom);
-        if (!js_GetMethod(cx, RootedVarObject(cx, &vp->toObject()), id, 0, &toJSON))
+        if (!js_GetMethod(cx, &vp->toObject(), id, 0, &toJSON))
             return false;
 
         if (js_IsCallable(toJSON)) {
             keyStr = KeyStringifier<KeyType>::toString(cx, key);
             if (!keyStr)
                 return false;
 
             InvokeArgsGuard args;
@@ -740,17 +740,17 @@ js_Stringify(JSContext *cx, Value *vp, J
         if (!gap.append(str->chars(), len))
             return false;
     } else {
         /* Step 8. */
         JS_ASSERT(gap.empty());
     }
 
     /* Step 9. */
-    RootedVarObject wrapper(cx, NewBuiltinClassInstance(cx, &ObjectClass));
+    JSObject *wrapper = NewBuiltinClassInstance(cx, &ObjectClass);
     if (!wrapper)
         return false;
 
     /* Step 10. */
     jsid emptyId = ATOM_TO_JSID(cx->runtime->atomState.emptyAtom);
     if (!DefineNativeProperty(cx, wrapper, emptyId, *vp, JS_PropertyStub, JS_StrictPropertyStub,
                               JSPROP_ENUMERATE, 0, 0))
     {
@@ -778,17 +778,17 @@ Walk(JSContext *cx, JSObject *holder, js
 
     /* Step 1. */
     Value val;
     if (!holder->getGeneric(cx, name, &val))
         return false;
 
     /* Step 2. */
     if (val.isObject()) {
-        RootedVarObject obj(cx, &val.toObject());
+        JSObject *obj = &val.toObject();
 
         /* 'val' must have been produced by the JSON parser, so not a proxy. */
         JS_ASSERT(!obj->isProxy());
         if (obj->isArray()) {
             /* Step 2a(ii). */
             uint32_t length = obj->getArrayLength();
 
             /* Step 2a(i), 2a(iii-iv). */
--- a/js/src/jsonparser.cpp
+++ b/js/src/jsonparser.cpp
@@ -534,18 +534,17 @@ JSONParser::parse(Value *vp)
         switch (state) {
           case FinishObjectMember: {
             Value v = valueStack.popCopy();
             /*
              * NB: Relies on js_DefineNativeProperty performing
              *     js_CheckForStringIndex.
              */
             jsid propid = ATOM_TO_JSID(&valueStack.popCopy().toString()->asAtom());
-            RootedVarObject obj(cx, &valueStack.back().toObject());
-            if (!DefineNativeProperty(cx, obj, propid, v,
+            if (!DefineNativeProperty(cx, &valueStack.back().toObject(), propid, v,
                                       JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE,
                                       0, 0))
             {
                 return false;
             }
             token = advanceAfterProperty();
             if (token == ObjectClose)
                 break;
--- a/js/src/jspropertycache.cpp
+++ b/js/src/jspropertycache.cpp
@@ -50,16 +50,25 @@ using namespace js;
 PropertyCacheEntry *
 PropertyCache::fill(JSContext *cx, JSObject *obj, unsigned scopeIndex, JSObject *pobj,
                     const Shape *shape)
 {
     JS_ASSERT(this == &JS_PROPERTY_CACHE(cx));
     JS_ASSERT(!cx->runtime->gcRunning);
 
     /*
+     * Check for fill from js_SetPropertyHelper where the setter removed shape
+     * from pobj (via unwatch or delete, e.g.).
+     */
+    if (!pobj->nativeContains(cx, *shape)) {
+        PCMETER(oddfills++);
+        return JS_NO_PROP_CACHE_FILL;
+    }
+
+    /*
      * Check for overdeep scope and prototype chain. Because resolve, getter,
      * and setter hooks can change the prototype chain using JS_SetPrototype
      * after LookupPropertyWithFlags has returned, we calculate the protoIndex
      * here and not in LookupPropertyWithFlags.
      *
      * The scopeIndex can't be wrong. We require JS_SetParent calls to happen
      * before any running script might consult a parent-linked scope chain. If
      * this requirement is not satisfied, the fill in progress will never hit,
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -265,20 +265,18 @@ ProxyHandler::keys(JSContext *cx, JSObje
 
     JS_ASSERT(i <= props.length());
     props.resize(i);
 
     return true;
 }
 
 bool
-ProxyHandler::iterate(JSContext *cx, JSObject *proxy_, unsigned flags, Value *vp)
+ProxyHandler::iterate(JSContext *cx, JSObject *proxy, unsigned flags, Value *vp)
 {
-    RootedVarObject proxy(cx, proxy_);
-
     JS_ASSERT(OperationInProgress(cx, proxy));
     AutoIdVector props(cx);
     if ((flags & JSITER_OWNONLY)
         ? !keys(cx, proxy, props)
         : !enumerate(cx, proxy, props)) {
         return false;
     }
     return EnumeratedIdVectorToIterator(cx, proxy, flags, props, vp);
@@ -315,17 +313,17 @@ ProxyHandler::regexp_toShared(JSContext 
 {
     JS_NOT_REACHED("This should have been a wrapped regexp");
     return false;
 }
 
 bool
 ProxyHandler::defaultValue(JSContext *cx, JSObject *proxy, JSType hint, Value *vp)
 {
-    return DefaultValue(cx, RootedVarObject(cx, proxy), hint, vp);
+    return DefaultValue(cx, proxy, hint, vp);
 }
 
 bool
 ProxyHandler::iteratorNext(JSContext *cx, JSObject *proxy, Value *vp)
 {
     vp->setMagic(JS_NO_ITER_VALUE);
     return true;
 }
@@ -1753,18 +1751,17 @@ FixProxy(JSContext *cx, JSObject *proxy,
     JSObject *parent = proxy->getParent();
     Class *clasp = IsFunctionProxy(proxy) ? &CallableObjectClass : &ObjectClass;
 
     /*
      * Make a blank object from the recipe fix provided to us.  This must have
      * number of fixed slots as the proxy so that we can swap their contents.
      */
     gc::AllocKind kind = proxy->getAllocKind();
-    RootedVarObject newborn(cx);
-    newborn = NewObjectWithGivenProto(cx, clasp, proto, parent, kind);
+    JSObject *newborn = NewObjectWithGivenProto(cx, clasp, proto, parent, kind);
     if (!newborn)
         return false;
 
     if (clasp == &CallableObjectClass) {
         newborn->setSlot(JSSLOT_CALLABLE_CALL, GetCall(proxy));
         newborn->setSlot(JSSLOT_CALLABLE_CONSTRUCT, GetConstruct(proxy));
     }
 
--- a/js/src/jsprvtd.h
+++ b/js/src/jsprvtd.h
@@ -124,17 +124,16 @@ struct ArgumentsData;
 struct Class;
 
 class RegExpGuard;
 class RegExpObject;
 class RegExpObjectBuilder;
 class RegExpShared;
 class RegExpStatics;
 class MatchPairs;
-class PropertyName;
 
 namespace detail { class RegExpCode; }
 
 enum RegExpFlag
 {
     IgnoreCaseFlag  = 0x01,
     GlobalFlag      = 0x02,
     MultilineFlag   = 0x04,
@@ -245,33 +244,82 @@ namespace types {
 
 class TypeSet;
 struct TypeCallsite;
 struct TypeObject;
 struct TypeCompartment;
 
 } /* namespace types */
 
-typedef JS::Handle<Shape*>             HandleShape;
-typedef JS::Handle<BaseShape*>         HandleBaseShape;
-typedef JS::Handle<types::TypeObject*> HandleTypeObject;
-typedef JS::Handle<JSAtom*>            HandleAtom;
-typedef JS::Handle<PropertyName*>      HandlePropertyName;
+enum ThingRootKind
+{
+    THING_ROOT_OBJECT,
+    THING_ROOT_SHAPE,
+    THING_ROOT_BASE_SHAPE,
+    THING_ROOT_TYPE_OBJECT,
+    THING_ROOT_STRING,
+    THING_ROOT_SCRIPT,
+    THING_ROOT_ID,
+    THING_ROOT_VALUE,
+    THING_ROOT_LIMIT
+};
+
+template <typename T> class Root;
+template <typename T> class RootedVar;
+
+template <typename T>
+struct RootMethods { };
+
+/*
+ * Reference to a stack location rooted for GC. See "Moving GC Stack Rooting"
+ * comment in jscntxt.h.
+ */
+template <typename T>
+class Handle
+{
+  public:
+    /* Copy handles of different types, with implicit coercion. */
+    template <typename S> Handle(Handle<S> handle) {
+        testAssign<S>();
+        ptr = reinterpret_cast<const T *>(handle.address());
+    }
 
-typedef JS::Root<Shape*>             RootShape;
-typedef JS::Root<BaseShape*>         RootBaseShape;
-typedef JS::Root<types::TypeObject*> RootTypeObject;
-typedef JS::Root<JSAtom*>            RootAtom;
-typedef JS::Root<PropertyName*>      RootPropertyName;
+    /* Get a handle from a rooted stack location, with implicit coercion. */
+    template <typename S> inline Handle(const Root<S> &root);
+    template <typename S> inline Handle(const RootedVar<S> &root);
+
+    const T *address() { return ptr; }
+
+    operator T () { return value(); }
+    T operator ->() { return value(); }
+
+  private:
+    const T *ptr;
+    T value() { return *ptr; }
 
-typedef JS::RootedVar<Shape*>             RootedVarShape;
-typedef JS::RootedVar<BaseShape*>         RootedVarBaseShape;
-typedef JS::RootedVar<types::TypeObject*> RootedVarTypeObject;
-typedef JS::RootedVar<JSAtom*>            RootedVarAtom;
-typedef JS::RootedVar<PropertyName*>      RootedVarPropertyName;
+    template <typename S>
+    void testAssign() {
+#ifdef DEBUG
+        T a = RootMethods<T>::initial();
+        S b = RootMethods<S>::initial();
+        a = b;
+        (void)a;
+#endif
+    }
+};
+
+typedef Handle<JSObject*>          HandleObject;
+typedef Handle<JSFunction*>        HandleFunction;
+typedef Handle<Shape*>             HandleShape;
+typedef Handle<BaseShape*>         HandleBaseShape;
+typedef Handle<types::TypeObject*> HandleTypeObject;
+typedef Handle<JSString*>          HandleString;
+typedef Handle<JSAtom*>            HandleAtom;
+typedef Handle<jsid>               HandleId;
+typedef Handle<Value>              HandleValue;
 
 enum XDRMode {
     XDR_ENCODE,
     XDR_DECODE
 };
 
 template <XDRMode mode>
 class XDRState;
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -239,72 +239,9 @@ typedef struct JSString                 
 typedef struct PRCallOnceType    JSCallOnceType;
 #else
 typedef JSBool                   JSCallOnceType;
 #endif
 typedef JSBool                 (*JSInitCallback)(void);
 
 JS_END_EXTERN_C
 
-#ifdef __cplusplus
-
-namespace JS {
-
-template <typename T>
-class Root;
-
-class SkipRoot;
-
-enum ThingRootKind
-{
-    THING_ROOT_OBJECT,
-    THING_ROOT_SHAPE,
-    THING_ROOT_BASE_SHAPE,
-    THING_ROOT_TYPE_OBJECT,
-    THING_ROOT_STRING,
-    THING_ROOT_SCRIPT,
-    THING_ROOT_ID,
-    THING_ROOT_VALUE,
-    THING_ROOT_LIMIT
-};
-
-struct ContextFriendFields {
-    JSRuntime *const    runtime;
-
-    ContextFriendFields(JSRuntime *rt)
-      : runtime(rt) { }
-
-    static const ContextFriendFields *get(const JSContext *cx) {
-        return reinterpret_cast<const ContextFriendFields *>(cx);
-    }
-
-    static ContextFriendFields *get(JSContext *cx) {
-        return reinterpret_cast<ContextFriendFields *>(cx);
-    }
-
-#ifdef JSGC_ROOT_ANALYSIS
-
-    /*
-     * Stack allocated GC roots for stack GC heap pointers, which may be
-     * overwritten if moved during a GC.
-     */
-    Root<void*> *thingGCRooters[THING_ROOT_LIMIT];
-
-#ifdef DEBUG
-    /*
-     * Stack allocated list of stack locations which hold non-relocatable
-     * GC heap pointers (where the target is rooted somewhere else) or integer
-     * values which may be confused for GC heap pointers. These are used to
-     * suppress false positives which occur when a rooting analysis treats the
-     * location as holding a relocatable pointer, but have no other effect on
-     * GC behavior.
-     */
-    SkipRoot *skipGCRooters;
-#endif
-
-#endif /* JSGC_ROOT_ANALYSIS */
-};
-
-} /* namespace JS */
-
-#endif /* __cplusplus */
-
 #endif /* jspubtd_h___ */
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -174,19 +174,17 @@ class NodeBuilder
     Value       callbacks[AST_LIMIT];  /* user-specified callbacks              */
     Value       userv;                 /* user-specified builder object or null */
 
   public:
     NodeBuilder(JSContext *c, bool l, char const *s)
         : cx(c), saveLoc(l), src(s) {
     }
 
-    bool init(JSObject *userobj_ = NULL) {
-        RootedVarObject userobj(cx, userobj_);
-
+    bool init(JSObject *userobj = NULL) {
         if (src) {
             if (!atomValue(src, &srcval))
                 return false;
         } else {
             srcval.setNull();
         }
 
         if (!userobj) {
@@ -199,20 +197,17 @@ class NodeBuilder
 
         userv.setObject(*userobj);
 
         for (unsigned i = 0; i < AST_LIMIT; i++) {
             Value funv;
 
             const char *name = callbackNames[i];
             JSAtom *atom = js_Atomize(cx, name, strlen(name));
-            if (!atom)
-                return false;
-            RootedVarId id(cx, ATOM_TO_JSID(atom));
-            if (!GetPropertyDefault(cx, userobj, id, NullValue(), &funv))
+            if (!atom || !GetPropertyDefault(cx, userobj, ATOM_TO_JSID(atom), NullValue(), &funv))
                 return false;
 
             if (funv.isNullOrUndefined()) {
                 callbacks[i].setNull();
                 continue;
             }
 
             if (!funv.isObject() || !funv.toObject().isFunction()) {
@@ -3123,32 +3118,34 @@ reflect_parse(JSContext *cx, uint32_t ar
 
     if (!arg.isNullOrUndefined()) {
         if (!arg.isObject()) {
             js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
                                      JSDVG_SEARCH_STACK, arg, NULL, "not an object", NULL);
             return JS_FALSE;
         }
 
-        RootedVarObject config(cx, &arg.toObject());
+        JSObject *config = &arg.toObject();
 
         Value prop;
 
         /* config.loc */
-        RootedVarId locId(cx, ATOM_TO_JSID(cx->runtime->atomState.locAtom));
-        if (!GetPropertyDefault(cx, config, locId, BooleanValue(true), &prop))
+        if (!GetPropertyDefault(cx, config, ATOM_TO_JSID(cx->runtime->atomState.locAtom),
+                                BooleanValue(true), &prop)) {
             return JS_FALSE;
+        }
 
         loc = js_ValueToBoolean(prop);
 
         if (loc) {
             /* config.source */
-            RootedVarId sourceId(cx, ATOM_TO_JSID(cx->runtime->atomState.sourceAtom));
-            if (!GetPropertyDefault(cx, config, sourceId, NullValue(), &prop))
+            if (!GetPropertyDefault(cx, config, ATOM_TO_JSID(cx->runtime->atomState.sourceAtom),
+                                    NullValue(), &prop)) {
                 return JS_FALSE;
+            }
 
             if (!prop.isNullOrUndefined()) {
                 JSString *str = ToString(cx, prop);
                 if (!str)
                     return JS_FALSE;
 
                 size_t length = str->length();
                 const jschar *chars = str->getChars(cx);
@@ -3157,27 +3154,28 @@ reflect_parse(JSContext *cx, uint32_t ar
 
                 filename = DeflateString(cx, chars, length);
                 if (!filename)
                     return JS_FALSE;
                 filenamep.reset(filename);
             }
 
             /* config.line */
-            RootedVarId lineId(cx, ATOM_TO_JSID(cx->runtime->atomState.lineAtom));
-            if (!GetPropertyDefault(cx, config, lineId, Int32Value(1), &prop) ||
+            if (!GetPropertyDefault(cx, config, ATOM_TO_JSID(cx->runtime->atomState.lineAtom),
+                                    Int32Value(1), &prop) ||
                 !ToUint32(cx, prop, &lineno)) {
                 return JS_FALSE;
             }
         }
 
         /* config.builder */
-        RootedVarId builderId(cx, ATOM_TO_JSID(cx->runtime->atomState.builderAtom));
-        if (!GetPropertyDefault(cx, config, builderId, NullValue(), &prop))
+        if (!GetPropertyDefault(cx, config, ATOM_TO_JSID(cx->runtime->atomState.builderAtom),
+                                NullValue(), &prop)) {
             return JS_FALSE;
+        }
 
         if (!prop.isNullOrUndefined()) {
             if (!prop.isObject()) {
                 js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
                                          JSDVG_SEARCH_STACK, prop, NULL, "not an object", NULL);
                 return JS_FALSE;
             }
             builder = &prop.toObject();
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -307,17 +307,17 @@ PropertyTable::grow(JSContext *cx)
 
 Shape *
 Shape::getChildBinding(JSContext *cx, const StackShape &child)
 {
     JS_ASSERT(!inDictionary());
 
     Shape *shape = JS_PROPERTY_TREE(cx).getChild(cx, this, numFixedSlots(), child);
     if (shape) {
-        //JS_ASSERT(shape->parent == this); // XXX 'this' is not rooted here
+        JS_ASSERT(shape->parent == this);
 
         /*
          * Update the number of fixed slots which bindings of this shape will
          * have. Bindings are constructed as new properties come in, so the
          * call object allocation class is not known ahead of time. Compute
          * the fixed slot count here, which will feed into call objects created
          * off of the bindings.
          */
@@ -515,24 +515,22 @@ JSObject::addProperty(JSContext *cx, jsi
 
     if (!isExtensible()) {
         reportNotExtensible(cx);
         return NULL;
     }
 
     NormalizeGetterAndSetter(cx, this, id, attrs, flags, getter, setter);
 
-    RootedVarObject self(cx, this);
-
     Shape **spp = NULL;
     if (inDictionaryMode())
         spp = lastProperty()->table().search(id, true);
 
-    return self->addPropertyInternal(cx, id, getter, setter, slot, attrs, flags, shortid,
-                                     spp, allowDictionary);
+    return addPropertyInternal(cx, id, getter, setter, slot, attrs, flags, shortid,
+                               spp, allowDictionary);
 }
 
 Shape *
 JSObject::addPropertyInternal(JSContext *cx, jsid id,
                               PropertyOp getter, StrictPropertyOp setter,
                               uint32_t slot, unsigned attrs,
                               unsigned flags, int shortid, Shape **spp,
                               bool allowDictionary)
@@ -548,17 +546,17 @@ JSObject::addPropertyInternal(JSContext 
             (slot == SHAPE_INVALID_SLOT) ||
             lastProperty()->hasMissingSlot() ||
             (slot == lastProperty()->maybeSlot() + 1);
         JS_ASSERT_IF(!allowDictionary, stableSlot);
         if (allowDictionary &&
             (!stableSlot || lastProperty()->entryCount() >= PropertyTree::MAX_HEIGHT)) {
             if (!toDictionaryMode(cx))
                 return NULL;
-            table = &self->lastProperty()->table();
+            table = &lastProperty()->table();
             spp = table->search(id, true);
         }
     } else {
         table = &lastProperty()->table();
         if (table->needsToGrow()) {
             if (!table->grow(cx))
                 return NULL;
             spp = table->search(id, true);
@@ -992,17 +990,17 @@ JSObject::replaceWithNewEquivalentShape(
 
     JSObject *self = this;
 
     if (!inDictionaryMode()) {
         RootObject selfRoot(cx, &self);
         RootShape newRoot(cx, &newShape);
         if (!toDictionaryMode(cx))
             return NULL;
-        oldShape = self->lastProperty();
+        oldShape = lastProperty();
     }
 
     if (!newShape) {
         RootObject selfRoot(cx, &self);
         RootShape oldRoot(cx, &oldShape);
         newShape = js_NewGCShape(cx);
         if (!newShape)
             return NULL;
@@ -1019,17 +1017,17 @@ JSObject::replaceWithNewEquivalentShape(
      * enumeration order (see bug 601399).
      */
     StackShape nshape(oldShape);
     newShape->initDictionaryShape(nshape, self->numFixedSlots(), oldShape->listp);
 
     JS_ASSERT(newShape->parent == oldShape);
     oldShape->removeFromDictionary(self);
 
-    if (newShape == self->lastProperty())
+    if (newShape == lastProperty())
         oldShape->handoffTableTo(newShape);
 
     if (spp)
         SHAPE_STORE_PRESERVING_COLLISION(spp, newShape);
     return newShape;
 }
 
 bool
@@ -1266,17 +1264,17 @@ Bindings::setParent(JSContext *cx, JSObj
 {
     /*
      * This may be invoked on GC heap allocated bindings, in which case this
      * is pointing to an internal value of a JSScript that can't itself be
      * relocated. The script itself will be rooted, and will not be moved, so
      * mark the stack value as non-relocatable for the stack root analysis.
      */
     Bindings *self = this;
-    SkipRoot root(cx, &self);
+    CheckRoot root(cx, &self);
 
     RootObject rootObj(cx, &obj);
 
     if (!ensureShape(cx))
         return false;
 
     /* This is only used for Block objects, which have a NULL proto. */
     Shape *newShape = Shape::setObjectParent(cx, obj, NULL, self->lastBinding);
@@ -1317,34 +1315,31 @@ EmptyShape::getInitialShape(JSContext *c
     size_t nfixed = GetGCKindSlots(kind, clasp);
     InitialShapeEntry::Lookup lookup(clasp, proto, parent, nfixed, objectFlags);
 
     InitialShapeSet::AddPtr p = table.lookupForAdd(lookup);
 
     if (p)
         return p->shape;
 
-    RootObject protoRoot(cx, &lookup.proto);
-    RootObject parentRoot(cx, &lookup.parent);
-
     RootedVar<UnownedBaseShape*> nbase(cx);
 
     StackBaseShape base(clasp, parent, objectFlags);
     nbase = BaseShape::getUnowned(cx, base);
     if (!nbase)
         return NULL;
 
     Shape *shape = JS_PROPERTY_TREE(cx).newShape(cx);
     if (!shape)
         return NULL;
     new (shape) EmptyShape(nbase, nfixed);
 
     InitialShapeEntry entry;
     entry.shape = shape;
-    entry.proto = lookup.proto;
+    entry.proto = proto;
 
     if (!table.relookupOrAdd(p, lookup, entry))
         return NULL;
 
     return shape;
 }
 
 void
--- a/js/src/jsscope.h
+++ b/js/src/jsscope.h
@@ -514,20 +514,16 @@ struct Shape : public js::gc::Cell
                                    has a double-indirect back pointer,
                                    either to the next shape's parent if not
                                    last, else to obj->shape_ */
     };
 
     static inline Shape *search(JSContext *cx, Shape *start, jsid id,
                                 Shape ***pspp, bool adding = false);
 
-#ifdef DEBUG
-    static inline Shape *searchNoAllocation(JSContext *cx, Shape *start, jsid id);
-#endif
-
     inline void removeFromDictionary(JSObject *obj);
     inline void insertIntoDictionary(HeapPtrShape *dictp);
 
     inline void initDictionaryShape(const StackShape &child, uint32_t nfixed,
                                     HeapPtrShape *dictp);
 
     Shape *getChildBinding(JSContext *cx, const StackShape &child);
 
@@ -1078,34 +1074,16 @@ Shape::search(JSContext *cx, Shape *star
     for (Shape *shape = start; shape; shape = shape->parent) {
         if (shape->propidRef() == id)
             return shape;
     }
 
     return NULL;
 }
 
-#ifdef DEBUG
-/* static */ inline Shape *
-Shape::searchNoAllocation(JSContext *cx, Shape *start, jsid id)
-{
-    if (start->hasTable()) {
-        Shape **spp = start->table().search(id, false);
-        return SHAPE_FETCH(spp);
-    }
-
-    for (Shape *shape = start; shape; shape = shape->parent) {
-        if (shape->propidRef() == id)
-            return shape;
-    }
-
-    return NULL;
-}
-#endif /* DEBUG */
-
 } // namespace js
 
 #ifdef _MSC_VER
 #pragma warning(pop)
 #pragma warning(pop)
 #endif
 
 namespace JS {
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -98,17 +98,17 @@ Bindings::lookup(JSContext *cx, JSAtom *
 
     if (shape->getter() == CallObject::getArgOp)
         return ARGUMENT;
 
     return shape->writable() ? VARIABLE : CONSTANT;
 }
 
 bool
-Bindings::add(JSContext *cx, HandleAtom name, BindingKind kind)
+Bindings::add(JSContext *cx, JSAtom *name, BindingKind kind)
 {
     if (!ensureShape(cx))
         return false;
 
     if (nargs + nvars == BINDING_COUNT_LIMIT) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              (kind == ARGUMENT)
                              ? JSMSG_TOO_MANY_FUN_ARGS
@@ -487,20 +487,20 @@ js::XDRScript(XDRState<mode> *xdr, JSScr
                     if (!bindings.addDestructuring(cx, &dummy))
                         return false;
                 } else {
                     JS_ASSERT(!names[i]);
                 }
                 continue;
             }
 
-            RootedVarAtom name(cx);
+            JSAtom *name;
             if (mode == XDR_ENCODE)
                 name = names[i];
-            if (!XDRAtom(xdr, name.address()))
+            if (!XDRAtom(xdr, &name))
                 return false;
             if (mode == XDR_DECODE) {
                 BindingKind kind = (i < nargs)
                                    ? ARGUMENT
                                    : (bitmap[i >> JS_BITS_PER_UINT32_LOG2] &
                                       JS_BIT(i & (JS_BITS_PER_UINT32 - 1))
                                      ? CONSTANT
                                      : VARIABLE);
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -189,33 +189,33 @@ class Bindings
      * given name prevails.  (We preserve both bindings for the decompiler,
      * which must deal with such cases.)  Pass null for name when indicating a
      * destructuring argument.  Return true on success.
      *
      * The parser builds shape paths for functions, usable by Call objects at
      * runtime, by calling an "add" method. All ARGUMENT bindings must be added
      * before before any VARIABLE or CONSTANT bindings.
      */
-    bool add(JSContext *cx, HandleAtom name, BindingKind kind);
+    bool add(JSContext *cx, JSAtom *name, BindingKind kind);
 
     /* Convenience specializations. */
-    bool addVariable(JSContext *cx, HandleAtom name) {
+    bool addVariable(JSContext *cx, JSAtom *name) {
         return add(cx, name, VARIABLE);
     }
-    bool addConstant(JSContext *cx, HandleAtom name) {
+    bool addConstant(JSContext *cx, JSAtom *name) {
         return add(cx, name, CONSTANT);
     }
-    bool addArgument(JSContext *cx, HandleAtom name, uint16_t *slotp) {
+    bool addArgument(JSContext *cx, JSAtom *name, uint16_t *slotp) {
         JS_ASSERT(name != NULL); /* not destructuring */
         *slotp = nargs;
         return add(cx, name, ARGUMENT);
     }
     bool addDestructuring(JSContext *cx, uint16_t *slotp) {
         *slotp = nargs;
-        return add(cx, RootedVarAtom(cx), ARGUMENT);
+        return add(cx, NULL, ARGUMENT);
     }
 
     void noteDup() { hasDup_ = true; }
     bool hasDup() const { return hasDup_; }
 
     /*
      * Look up an argument or variable name, returning its kind when found or
      * NONE when no such name exists. When indexp is not null and the name
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -463,21 +463,21 @@ static JS_ALWAYS_INLINE JSString *
 ThisToStringForStringProto(JSContext *cx, CallReceiver call)
 {
     JS_CHECK_RECURSION(cx, return NULL);
 
     if (call.thisv().isString())
         return call.thisv().toString();
 
     if (call.thisv().isObject()) {
-        RootedVarObject obj(cx, &call.thisv().toObject());
+        JSObject *obj = &call.thisv().toObject();
         if (obj->isString() &&
             ClassMethodIsNative(cx, obj,
                                 &StringClass,
-                                RootedVarId(cx, ATOM_TO_JSID(cx->runtime->atomState.toStringAtom)),
+                                ATOM_TO_JSID(cx->runtime->atomState.toStringAtom),
                                 js_str_toString))
         {
             JSString *str = obj->asString().unbox();
             call.thisv().setString(str);
             return str;
         }
     } else if (call.thisv().isNullOrUndefined()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CONVERT_TO,
@@ -1492,17 +1492,17 @@ class StringRegExpGuard
 
     /* If the pattern is not already a regular expression, make it so. */
     bool normalizeRegExp(JSContext *cx, bool flat, unsigned optarg, CallArgs args)
     {
         if (re_.initialized())
             return true;
 
         /* Build RegExp from pattern string. */
-        RootedVarString opt(cx);
+        JSString *opt;
         if (optarg < args.length()) {
             opt = ToString(cx, args[optarg]);
             if (!opt)
                 return false;
         } else {
             opt = NULL;
         }
 
@@ -1545,46 +1545,42 @@ enum MatchControlFlags {
    REPLACE_ARGS  = TEST_GLOBAL_BIT | TEST_SINGLE_BIT | CALLBACK_ON_SINGLE_BIT
 };
 
 /* Factor out looping and matching logic. */
 static bool
 DoMatch(JSContext *cx, RegExpStatics *res, JSString *str, RegExpShared &re,
         DoMatchCallback callback, void *data, MatchControlFlags flags, Value *rval)
 {
-    RootedVar<JSLinearString*> linearStr(cx, str->ensureLinear(cx));
+    JSLinearString *linearStr = str->ensureLinear(cx);
     if (!linearStr)
         return false;
 
+    const jschar *chars = linearStr->chars();
+    size_t length = linearStr->length();
+
     if (re.global()) {
         RegExpExecType type = (flags & TEST_GLOBAL_BIT) ? RegExpTest : RegExpExec;
         for (size_t count = 0, i = 0, length = str->length(); i <= length; ++count) {
             if (!JS_CHECK_OPERATION_LIMIT(cx))
                 return false;
-
-            const jschar *chars = linearStr->chars();
-            size_t charsLen = linearStr->length();
-
-            if (!ExecuteRegExp(cx, res, re, linearStr, chars, charsLen, &i, type, rval))
+            if (!ExecuteRegExp(cx, res, re, linearStr, chars, length, &i, type, rval))
                 return false;
             if (!Matched(type, *rval))
                 break;
             if (!callback(cx, res, count, data))
                 return false;
             if (!res->matched())
                 ++i;
         }
     } else {
-        const jschar *chars = linearStr->chars();
-        size_t charsLen = linearStr->length();
-
         RegExpExecType type = (flags & TEST_SINGLE_BIT) ? RegExpTest : RegExpExec;
         bool callbackOnSingle = !!(flags & CALLBACK_ON_SINGLE_BIT);
         size_t i = 0;
-        if (!ExecuteRegExp(cx, res, re, linearStr, chars, charsLen, &i, type, rval))
+        if (!ExecuteRegExp(cx, res, re, linearStr, chars, length, &i, type, rval))
             return false;
         if (callbackOnSingle && Matched(type, *rval) && !callback(cx, res, 0, data))
             return false;
     }
     return true;
 }
 
 static bool
@@ -1650,18 +1646,18 @@ js::str_match(JSContext *cx, unsigned ar
 
     /* Return if there was an error in tryFlatMatch. */
     if (cx->isExceptionPending())
         return false;
 
     if (!g.normalizeRegExp(cx, false, 1, args))
         return false;
 
-    RootedVarObject array(cx);
-    MatchArgType arg = array.address();
+    JSObject *array = NULL;
+    MatchArgType arg = &array;
     RegExpStatics *res = cx->regExpStatics();
     Value rval;
     if (!DoMatch(cx, res, str, g.regExp(), MatchCallback, arg, MATCH_ARGS, &rval))
         return false;
 
     if (g.regExp().global())
         args.rval() = ObjectOrNullValue(array);
     else
@@ -1710,24 +1706,24 @@ js::str_search(JSContext *cx, unsigned a
     else
         args.rval() = Int32Value(-1);
     return true;
 }
 
 struct ReplaceData
 {
     ReplaceData(JSContext *cx)
-      : str(cx), lambda(cx), elembase(cx), repstr(cx), sb(cx)
+     : sb(cx)
     {}
 
-    RootedVarString    str;            /* 'this' parameter object as a string */
+    JSString           *str;           /* 'this' parameter object as a string */
     StringRegExpGuard  g;              /* regexp parameter object and private data */
-    RootedVarObject    lambda;         /* replacement function object or null */
-    RootedVarObject    elembase;       /* object for function(a){return b[a]} replace */
-    RootedVar<JSLinearString*> repstr; /* replacement string */
+    JSObject           *lambda;        /* replacement function object or null */
+    JSObject           *elembase;      /* object for function(a){return b[a]} replace */
+    JSLinearString     *repstr;        /* replacement string */
     const jschar       *dollar;        /* null or pointer to first $ in repstr */
     const jschar       *dollarEnd;     /* limit pointer for js_strchr_limit */
     int                leftIndex;      /* left context index in str->chars */
     JSSubString        dollarStr;      /* for "$$" InterpretDollar result */
     bool               calledBack;     /* record whether callback has been called */
     InvokeArgsGuard    args;           /* arguments for lambda call */
     StringBuffer       sb;             /* buffer built during DoMatch */
 };
@@ -1794,18 +1790,17 @@ InterpretDollar(JSContext *cx, RegExpSta
         return true;
     }
     return false;
 }
 
 static bool
 FindReplaceLength(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t *sizep)
 {
-    RootedVarObject base(cx, rdata.elembase);
-    if (base) {
+    if (JSObject *base = rdata.elembase) {
         /*
          * The base object is used when replace was passed a lambda which looks like
          * 'function(a) { return b[a]; }' for the base object b.  b will not change
          * in the course of the replace unless we end up making a scripted call due
          * to accessing a scripted getter or a value with a scripted toString.
          */
         JS_ASSERT(rdata.lambda);
         JS_ASSERT(!base->getOps()->lookupProperty);
@@ -1943,38 +1938,36 @@ DoReplace(JSContext *cx, RegExpStatics *
 }
 
 static bool
 ReplaceRegExpCallback(JSContext *cx, RegExpStatics *res, size_t count, void *p)
 {
     ReplaceData &rdata = *static_cast<ReplaceData *>(p);
 
     rdata.calledBack = true;
+    JSLinearString &str = rdata.str->asLinear();  /* flattened for regexp */
     size_t leftoff = rdata.leftIndex;
+    const jschar *left = str.chars() + leftoff;
     size_t leftlen = res->matchStart() - leftoff;
     rdata.leftIndex = res->matchLimit();
 
     size_t replen = 0;  /* silence 'unused' warning */
     if (!FindReplaceLength(cx, res, rdata, &replen))
         return false;
 
     size_t growth = leftlen + replen;
     if (!rdata.sb.reserve(rdata.sb.length() + growth))
         return false;
-
-    JSLinearString &str = rdata.str->asLinear();  /* flattened for regexp */
-    const jschar *left = str.chars() + leftoff;
-
     rdata.sb.infallibleAppend(left, leftlen); /* skipped-over portion of the search value */
     DoReplace(cx, res, rdata);
     return true;
 }
 
 static bool
-BuildFlatReplacement(JSContext *cx, HandleString textstr, HandleString repstr,
+BuildFlatReplacement(JSContext *cx, JSString *textstr, JSString *repstr,
                      const FlatMatch &fm, CallArgs *args)
 {
     RopeBuilder builder(cx);
     size_t match = fm.match();
     size_t matchEnd = match + fm.patternLength();
 
     if (textstr->isRope()) {
         /*
@@ -1996,52 +1989,48 @@ BuildFlatReplacement(JSContext *cx, Hand
                  */
                 if (match >= pos) {
                     /*
                      * If this part of the rope overlaps with the left side of
                      * the pattern, then it must be the only one to overlap with
                      * the first character in the pattern, so we include the
                      * replacement string here.
                      */
-                    RootedVarString leftSide(cx);
-                    leftSide = js_NewDependentString(cx, str, 0, match - pos);
+                    JSString *leftSide = js_NewDependentString(cx, str, 0, match - pos);
                     if (!leftSide ||
                         !builder.append(leftSide) ||
                         !builder.append(repstr)) {
                         return false;
                     }
                 }
 
                 /*
                  * If str runs off the end of the matched string, append the
                  * last part of str.
                  */
                 if (strEnd > matchEnd) {
-                    RootedVarString rightSide(cx);
-                    rightSide = js_NewDependentString(cx, str, matchEnd - pos,
-                                                      strEnd - matchEnd);
+                    JSString *rightSide = js_NewDependentString(cx, str, matchEnd - pos,
+                                                                strEnd - matchEnd);
                     if (!rightSide || !builder.append(rightSide))
                         return false;
                 }
             } else {
-                if (!builder.append(RootedVarString(cx, str)))
+                if (!builder.append(str))
                     return false;
             }
             pos += str->length();
             if (!r.popFront())
                 return false;
         }
     } else {
-        RootedVarString leftSide(cx);
-        leftSide = js_NewDependentString(cx, textstr, 0, match);
+        JSString *leftSide = js_NewDependentString(cx, textstr, 0, match);
         if (!leftSide)
             return false;
-        RootedVarString rightSide(cx);
-        rightSide = js_NewDependentString(cx, textstr, match + fm.patternLength(),
-                                          textstr->length() - match - fm.patternLength());
+        JSString *rightSide = js_NewDependentString(cx, textstr, match + fm.patternLength(),
+                                                    textstr->length() - match - fm.patternLength());
         if (!rightSide ||
             !builder.append(leftSide) ||
             !builder.append(repstr) ||
             !builder.append(rightSide)) {
             return false;
         }
     }
 
@@ -2107,25 +2096,25 @@ BuildDollarReplacement(JSContext *cx, JS
             break;
           default: /* The dollar we saw was not special (no matter what its mother told it). */
             ENSURE(newReplaceChars.append(*it));
             continue;
         }
         ++it; /* We always eat an extra char in the above switch. */
     }
 
-    RootedVarString leftSide(cx, js_NewDependentString(cx, textstr, 0, matchStart));
+    JSString *leftSide = js_NewDependentString(cx, textstr, 0, matchStart);
     ENSURE(leftSide);
 
-    RootedVarString newReplace(cx, newReplaceChars.finishString());
+    JSString *newReplace = newReplaceChars.finishString();
     ENSURE(newReplace);
 
     JS_ASSERT(textstr->length() >= matchLimit);
-    RootedVarString rightSide(cx, js_NewDependentString(cx, textstr, matchLimit,
-                                                        textstr->length() - matchLimit));
+    JSString *rightSide = js_NewDependentString(cx, textstr, matchLimit,
+                                                textstr->length() - matchLimit);
     ENSURE(rightSide);
 
     RopeBuilder builder(cx);
     ENSURE(builder.append(leftSide) &&
            builder.append(newReplace) &&
            builder.append(rightSide));
 #undef ENSURE
 
@@ -2189,27 +2178,27 @@ str_replace_flat_lambda(JSContext *cx, C
     Value *sp = args.array();
     sp[0].setString(matchStr);
     sp[1].setInt32(fm.match());
     sp[2].setString(rdata.str);
 
     if (!Invoke(cx, rdata.args))
         return false;
 
-    RootedVarString repstr(cx, ToString(cx, args.rval()));
+    JSString *repstr = ToString(cx, args.rval());
     if (!repstr)
         return false;
 
-    RootedVarString leftSide(cx, js_NewDependentString(cx, rdata.str, 0, fm.match()));
+    JSString *leftSide = js_NewDependentString(cx, rdata.str, 0, fm.match());
     if (!leftSide)
         return false;
 
     size_t matchLimit = fm.match() + fm.patternLength();
-    RootedVarString rightSide(cx, js_NewDependentString(cx, rdata.str, matchLimit,
-                                                        rdata.str->length() - matchLimit));
+    JSString *rightSide = js_NewDependentString(cx, rdata.str, matchLimit,
+                                                rdata.str->length() - matchLimit);
     if (!rightSide)
         return false;
 
     RopeBuilder builder(cx);
     if (!(builder.append(leftSide) &&
           builder.append(repstr) &&
           builder.append(rightSide))) {
         return false;
@@ -2388,18 +2377,17 @@ class SplitMatchResult {
     void setResult(size_t length, size_t endIndex) {
         length_ = length;
         endIndex_ = endIndex;
     }
 };
 
 template<class Matcher>
 static JSObject *
-SplitHelper(JSContext *cx, Handle<JSLinearString*> str, uint32_t limit, const Matcher &splitMatch,
-            TypeObject *type)
+SplitHelper(JSContext *cx, JSLinearString *str, uint32_t limit, Matcher splitMatch, TypeObject *type)
 {
     size_t strLength = str->length();
     SplitMatchResult result;
 
     /* Step 11. */
     if (strLength == 0) {
         if (!splitMatch(cx, str, 0, &result))
             return NULL;
@@ -2412,18 +2400,18 @@ SplitHelper(JSContext *cx, Handle<JSLine
          *   var a = "".split("");
          *   assertEq(a.length, 0);
          *   var b = "".split(/.?/);
          *   assertEq(b.length, 0);
          */
         if (!result.isFailure())
             return NewDenseEmptyArray(cx);
 
-        RootedVarValue v(cx, StringValue(str));
-        return NewDenseCopiedArray(cx, 1, v.address());
+        Value v = StringValue(str);
+        return NewDenseCopiedArray(cx, 1, &v);
     }
 
     /* Step 12. */
     size_t lastEndIndex = 0;
     size_t index = 0;
 
     /* Step 13. */
     AutoValueVector splits(cx);
@@ -2530,18 +2518,17 @@ class SplitRegExpMatcher
     RegExpShared &re;
     RegExpStatics *res;
 
   public:
     SplitRegExpMatcher(RegExpShared &re, RegExpStatics *res) : re(re), res(res) {}
 
     static const bool returnsCaptures = true;
 
-    bool operator()(JSContext *cx, JSLinearString *str, size_t index,
-                    SplitMatchResult *result) const
+    bool operator()(JSContext *cx, JSLinearString *str, size_t index, SplitMatchResult *result)
     {
         Value rval = UndefinedValue();
         const jschar *chars = str->chars();
         size_t length = str->length();
         if (!ExecuteRegExp(cx, res, re, str, chars, length, &index, RegExpTest, &rval))
             return false;
         if (!rval.isTrue()) {
             result->setFailure();
@@ -2552,51 +2539,52 @@ class SplitRegExpMatcher
 
         result->setResult(sep.length, index);
         return true;
     }
 };
 
 class SplitStringMatcher
 {
-    RootedVar<JSLinearString*> sep;
+    const jschar *sepChars;
+    size_t sepLength;
 
   public:
-    SplitStringMatcher(JSContext *cx, JSLinearString *sep)
-      : sep(cx, sep)
-    {}
+    SplitStringMatcher(JSLinearString *sep) {
+        sepChars = sep->chars();
+        sepLength = sep->length();
+    }
 
     static const bool returnsCaptures = false;
 
-    bool operator()(JSContext *cx, JSLinearString *str, size_t index, SplitMatchResult *res) const
+    bool operator()(JSContext *cx, JSLinearString *str, size_t index, SplitMatchResult *res)
     {
         JS_ASSERT(index == 0 || index < str->length());
         const jschar *chars = str->chars();
-        int match = StringMatch(chars + index, str->length() - index,
-                                sep->chars(), sep->length());
+        int match = StringMatch(chars + index, str->length() - index, sepChars, sepLength);
         if (match == -1)
             res->setFailure();
         else
-            res->setResult(sep->length(), index + match + sep->length());
+            res->setResult(sepLength, index + match + sepLength);
         return true;
     }
 };
 
 /* ES5 15.5.4.14 */
 JSBool
 js::str_split(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Steps 1-2. */
     JSString *str = ThisToStringForStringProto(cx, args);
     if (!str)
         return false;
 
-    RootedVarTypeObject type(cx, GetTypeCallerInitObject(cx, JSProto_Array));
+    TypeObject *type = GetTypeCallerInitObject(cx, JSProto_Array);
     if (!type)
         return false;
     AddTypeProperty(cx, type, NULL, Type::StringType());
 
     /* Step 5: Use the second argument as the split limit, if given. */
     uint32_t limit;
     if (args.hasDefined(1)) {
         double d;
@@ -2637,29 +2625,26 @@ js::str_split(JSContext *cx, unsigned ar
         Value v = StringValue(str);
         JSObject *aobj = NewDenseCopiedArray(cx, 1, &v);
         if (!aobj)
             return false;
         aobj->setType(type);
         args.rval() = ObjectValue(*aobj);
         return true;
     }
-    RootedVar<JSLinearString*> strlin(cx, str->ensureLinear(cx));
+    JSLinearString *strlin = str->ensureLinear(cx);
     if (!strlin)
         return false;
 
     /* Steps 11-15. */
     JSObject *aobj;
-    if (!re.initialized()) {
-        SplitStringMatcher matcher(cx, sepstr);
-        aobj = SplitHelper(cx, strlin, limit, matcher, type);
-    } else {
-        SplitRegExpMatcher matcher(*re, cx->regExpStatics());
-        aobj = SplitHelper(cx, strlin, limit, matcher, type);
-    }
+    if (!re.initialized())
+        aobj = SplitHelper(cx, strlin, limit, SplitStringMatcher(sepstr), type);
+    else
+        aobj = SplitHelper(cx, strlin, limit, SplitRegExpMatcher(*re, cx->regExpStatics()), type);
     if (!aobj)
         return false;
 
     /* Step 16. */
     aobj->setType(type);
     args.rval() = ObjectValue(*aobj);
     return true;
 }
@@ -2715,22 +2700,22 @@ out:
 
 /*
  * Python-esque sequence operations.
  */
 static JSBool
 str_concat(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedVarString str(cx, ThisToStringForStringProto(cx, args));
+    JSString *str = ThisToStringForStringProto(cx, args);
     if (!str)
         return false;
 
     for (unsigned i = 0; i < args.length(); i++) {
-        RootedVarString argStr(cx, ToString(cx, args[i]));
+        JSString *argStr = ToString(cx, args[i]);
         if (!argStr)
             return false;
 
         str = js_ConcatStrings(cx, str, argStr);
         if (!str)
             return false;
     }
 
@@ -3022,17 +3007,17 @@ static JSFunctionSpec string_methods[] =
     JS_FS_END
 };
 
 JSBool
 js_String(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    RootedVarString str(cx);
+    JSString *str;
     if (args.length() > 0) {
         str = ToString(cx, args[0]);
         if (!str)
             return false;
     } else {
         str = cx->runtime->emptyString;
     }
 
@@ -3100,25 +3085,24 @@ StringObject::assignInitialShape(JSConte
                            LENGTH_SLOT, JSPROP_PERMANENT | JSPROP_READONLY);
 }
 
 JSObject *
 js_InitStringClass(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isNative());
 
-    RootedVar<GlobalObject*> global(cx, &obj->asGlobal());
-
-    RootedVarObject proto(cx, global->createBlankPrototype(cx, &StringClass));
-    if (!proto || !proto->asString().init(cx, RootedVarString(cx, cx->runtime->emptyString)))
+    GlobalObject *global = &obj->asGlobal();
+
+    JSObject *proto = global->createBlankPrototype(cx, &StringClass);
+    if (!proto || !proto->asString().init(cx, cx->runtime->emptyString))
         return NULL;
 
     /* Now create the String function. */
-    RootedVarFunction ctor(cx);
-    ctor = global->createConstructor(cx, js_String, CLASS_ATOM(cx, String), 1);
+    JSFunction *ctor = global->createConstructor(cx, js_String, CLASS_ATOM(cx, String), 1);
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, proto))
         return NULL;
 
     if (!DefinePropertiesAndBrand(cx, proto, NULL, string_methods) ||
         !DefinePropertiesAndBrand(cx, ctor, NULL, string_static_methods))
@@ -3323,17 +3307,17 @@ js_ValueToSource(JSContext *cx, const Va
             return js_NewStringCopyN(cx, js_negzero_ucNstr, 2);
         }
         return ToString(cx, v);
     }
 
     Value rval = NullValue();
     Value fval;
     jsid id = ATOM_TO_JSID(cx->runtime->atomState.toSourceAtom);
-    if (!js_GetMethod(cx, RootedVarObject(cx, &v.toObject()), id, 0, &fval))
+    if (!js_GetMethod(cx, &v.toObject(), id, 0, &fval))
         return NULL;
     if (js_IsCallable(fval)) {
         if (!Invoke(cx, v, fval, 0, NULL, &rval))
             return NULL;
     }
 
     return ToString(cx, rval);
 }
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -69,17 +69,17 @@ class MutatingRopeSegmentRange;
 /*
  * Utility for building a rope (lazy concatenation) of strings.
  */
 class RopeBuilder;
 
 }  /* namespace js */
 
 extern JSString * JS_FASTCALL
-js_ConcatStrings(JSContext *cx, js::HandleString s1, js::HandleString s2);
+js_ConcatStrings(JSContext *cx, JSString *s1, JSString *s2);
 
 extern JSString * JS_FASTCALL
 js_toLowerCase(JSContext *cx, JSString *str);
 
 extern JSString * JS_FASTCALL
 js_toUpperCase(JSContext *cx, JSString *str);
 
 struct JSSubString {
--- a/js/src/jsstrinlines.h
+++ b/js/src/jsstrinlines.h
@@ -48,27 +48,27 @@
 #include "jscntxtinlines.h"
 #include "jsgcinlines.h"
 #include "vm/String-inl.h"
 
 namespace js {
 
 class RopeBuilder {
     JSContext *cx;
-    RootedVarString res;
+    JSString *res;
 
     RopeBuilder(const RopeBuilder &other) MOZ_DELETE;
     void operator=(const RopeBuilder &other) MOZ_DELETE;
 
   public:
     RopeBuilder(JSContext *cx)
-      : cx(cx), res(cx, cx->runtime->emptyString)
+      : cx(cx), res(cx->runtime->emptyString)
     {}
 
-    inline bool append(HandleString str) {
+    inline bool append(JSString *str) {
         res = js_ConcatStrings(cx, res, str);
         return !!res;
     }
 
     inline JSString *result() {
         return res;
     }
 };
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -468,45 +468,45 @@ JSBool
 ArrayBuffer::obj_getGeneric(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
 {
     obj = getArrayBuffer(obj);
     if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) {
         vp->setInt32(obj->arrayBufferByteLength());
         return true;
     }
 
-    RootedVarObject delegate(cx, DelegateObject(cx, obj));
+    JSObject *delegate = DelegateObject(cx, obj);
     if (!delegate)
         return false;
-    return js_GetProperty(cx, delegate, RootedVarObject(cx, receiver), id, vp);
+    return js_GetProperty(cx, delegate, receiver, id, vp);
 }
 
 JSBool
 ArrayBuffer::obj_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, PropertyName *name,
                              Value *vp)
 {
     obj = getArrayBuffer(obj);
     if (name == cx->runtime->atomState.byteLengthAtom) {
         vp->setInt32(obj->arrayBufferByteLength());
         return true;
     }
 
-    RootedVarObject delegate(cx, DelegateObject(cx, obj));
+    JSObject *delegate = DelegateObject(cx, obj);
     if (!delegate)
         return false;
-    return js_GetProperty(cx, delegate, RootedVarObject(cx, receiver), ATOM_TO_JSID(name), vp);
+    return js_GetProperty(cx, delegate, receiver, ATOM_TO_JSID(name), vp);
 }
 
 JSBool
 ArrayBuffer::obj_getElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index, Value *vp)
 {
-    RootedVarObject delegate(cx, DelegateObject(cx, getArrayBuffer(obj)));
+    JSObject *delegate = DelegateObject(cx, getArrayBuffer(obj));
     if (!delegate)
         return false;
-    return js_GetElement(cx, delegate, RootedVarObject(cx, receiver), index, vp);
+    return js_GetElement(cx, delegate, receiver, index, vp);
 }
 
 JSBool
 ArrayBuffer::obj_getElementIfPresent(JSContext *cx, JSObject *obj, JSObject *receiver,
                                      uint32_t index, Value *vp, bool *present)
 {
     JSObject *delegate = DelegateObject(cx, getArrayBuffer(obj));
     if (!delegate)
@@ -521,20 +521,16 @@ ArrayBuffer::obj_getSpecial(JSContext *c
 }
 
 JSBool
 ArrayBuffer::obj_setGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
 {
     if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom))
         return true;
 
-    RootedVarObject delegate(cx, DelegateObject(cx, obj));
-    if (!delegate)
-        return false;
-
     if (JSID_IS_ATOM(id, cx->runtime->atomState.protoAtom)) {
         // setting __proto__ = null
         // effectively removes the prototype chain.
         // any attempt to set __proto__ on native
         // objects after setting them to null makes
         // __proto__ just a plain property.
         // the following code simulates this behaviour on arrays.
         //
@@ -544,16 +540,19 @@ ArrayBuffer::obj_setGeneric(JSContext *c
         // of treating it as special or plain.
         // if the delegate's prototype has now changed
         // then we change our prototype too.
         //
         // otherwise __proto__ was a plain property
         // and we don't modify our prototype chain
         // since obj_getProperty will fetch it as a plain
         // property from the delegate.
+        JSObject *delegate = DelegateObject(cx, obj);
+        if (!delegate)
+            return false;
 
         JSObject *oldDelegateProto = delegate->getProto();
 
         if (!js_SetPropertyHelper(cx, delegate, id, 0, vp, strict))
             return false;
 
         if (delegate->getProto() != oldDelegateProto) {
             // actual __proto__ was set and not a plain property called
@@ -567,29 +566,33 @@ ArrayBuffer::obj_setGeneric(JSContext *c
                 // restore delegate prototype chain
                 SetProto(cx, delegate, oldDelegateProto, true);
                 return false;
             }
         }
         return true;
     }
 
+    JSObject *delegate = DelegateObject(cx, obj);
+    if (!delegate)
+        return false;
+
     return js_SetPropertyHelper(cx, delegate, id, 0, vp, strict);
 }
 
 JSBool
 ArrayBuffer::obj_setProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict)
 {
     return obj_setGeneric(cx, obj, ATOM_TO_JSID(name), vp, strict);
 }
 
 JSBool
 ArrayBuffer::obj_setElement(JSContext *cx, JSObject *obj, uint32_t index, Value *vp, JSBool strict)
 {
-    RootedVarObject delegate(cx, DelegateObject(cx, obj));
+    JSObject *delegate = DelegateObject(cx, obj);
     if (!delegate)
         return false;
 
     return js_SetElementHelper(cx, delegate, index, 0, vp, strict);
 }
 
 JSBool
 ArrayBuffer::obj_setSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool strict)
--- a/js/src/jswrapper.cpp
+++ b/js/src/jswrapper.cpp
@@ -260,17 +260,17 @@ Wrapper::keys(JSContext *cx, JSObject *w
     GET(GetPropertyNames(cx, wrappedObject(wrapper), JSITER_OWNONLY, &props));
 }
 
 bool
 Wrapper::iterate(JSContext *cx, JSObject *wrapper, unsigned flags, Value *vp)
 {
     vp->setUndefined(); // default result if we refuse to perform this action
     const jsid id = JSID_VOID;
-    GET(GetIterator(cx, RootedVarObject(cx, wrappedObject(wrapper)), flags, vp));
+    GET(GetIterator(cx, wrappedObject(wrapper), flags, vp));
 }
 
 bool
 Wrapper::call(JSContext *cx, JSObject *wrapper, unsigned argc, Value *vp)
 {
     vp->setUndefined(); // default result if we refuse to perform this action
     const jsid id = JSID_VOID;
     CHECKED(ProxyHandler::call(cx, wrapper, argc, vp), CALL);
@@ -361,17 +361,17 @@ Wrapper::defaultValue(JSContext *cx, JSO
     if (hint == JSTYPE_VOID)
         return ToPrimitive(cx, vp);
     return ToPrimitive(cx, hint, vp);
 }
 
 bool
 Wrapper::iteratorNext(JSContext *cx, JSObject *wrapper, Value *vp)
 {
-    if (!js_IteratorMore(cx, RootedVarObject(cx, wrappedObject(wrapper)), vp))
+    if (!js_IteratorMore(cx, wrappedObject(wrapper), vp))
         return false;
 
     if (vp->toBoolean()) {
         *vp = cx->iterValue;
         cx->iterValue.setUndefined();
     } else {
         vp->setMagic(JS_NO_ITER_VALUE);
     }
@@ -687,18 +687,18 @@ static bool
 Reify(JSContext *cx, JSCompartment *origin, Value *vp)
 {
     JSObject *iterObj = &vp->toObject();
     NativeIterator *ni = iterObj->getNativeIterator();
 
     AutoCloseIterator close(cx, iterObj);
 
     /* Wrap the iteratee. */
-    RootedVarObject obj(cx, ni->obj);
-    if (!origin->wrap(cx, obj.address()))
+    JSObject *obj = ni->obj;
+    if (!origin->wrap(cx, &obj))
         return false;
 
     /*
      * Wrap the elements in the iterator's snapshot.
      * N.B. the order of closing/creating iterators is important due to the
      * implicit cx->enumerators state.
      */
     size_t length = ni->numKeys();
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -151,17 +151,17 @@ const char js_amp_entity_str[]    = "&am
 const char js_gt_entity_str[]     = "&gt;";
 const char js_lt_entity_str[]     = "&lt;";
 const char js_quot_entity_str[]   = "&quot;";
 const char js_leftcurly_entity_str[]   = "&#123;";
 
 #define IS_STAR(str)  ((str)->length() == 1 && *(str)->chars() == '*')
 
 static JSBool
-GetXMLFunction(JSContext *cx, HandleObject obj, HandleId id, jsval *vp);
+GetXMLFunction(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
 
 static JSBool
 IsDeclared(const JSObject *obj)
 {
     jsval v;
 
     JS_ASSERT(obj->getClass() == &NamespaceClass);
     v = obj->getNamespaceDeclared();
@@ -400,31 +400,31 @@ static JSPropertySpec qname_props[] = {
     {js_localName_str, 0, QNAME_ATTRS, QNameLocalName_getter, 0},
     {0,0,0,0,0}
 };
 
 static JSString *
 ConvertQNameToString(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isQName());
-    RootedVarString uri(cx, obj->getNameURI());
-    RootedVarString str(cx);
+    JSString *uri = obj->getNameURI();
+    JSString *str;
     if (!uri) {
         /* No uri means wildcard qualifier. */
         str = cx->runtime->atomState.starQualifierAtom;
     } else if (uri->empty()) {
         /* Empty string for uri means localName is in no namespace. */
         str = cx->runtime->emptyString;
     } else {
-        RootedVarString qualstr(cx, cx->runtime->atomState.qualifierAtom);
+        JSString *qualstr = cx->runtime->atomState.qualifierAtom;
         str = js_ConcatStrings(cx, uri, qualstr);
         if (!str)
             return NULL;
     }
-    str = js_ConcatStrings(cx, str, RootedVarString(cx, obj->getQNameLocalName()));
+    str = js_ConcatStrings(cx, str, obj->getQNameLocalName());
     if (!str)
         return NULL;
 
     if (obj->getClass() == &AttributeNameClass) {
         JS::Anchor<JSString *> anchor(str);
         size_t length = str->length();
         jschar *chars = (jschar *) cx->malloc_((length + 2) * sizeof(jschar));
         if (!chars)
@@ -3760,25 +3760,23 @@ GetNamedProperty(JSContext *cx, JSXML *x
         }
     }
 
     return JS_TRUE;
 }
 
 /* ECMA-357 9.1.1.1 XML [[Get]] and 9.2.1.1 XMLList [[Get]]. */
 static JSBool
-GetProperty(JSContext *cx, JSObject *obj_, jsid id_, jsval *vp)
+GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 {
     JSXML *xml, *list, *kid;
     uint32_t index;
     JSObject *kidobj, *listobj;
     JSObject *nameqn;
-
-    RootedVarObject obj(cx, obj_);
-    RootedVarId id(cx, id_);
+    jsid funid;
 
     if (!obj->isXML())
         return true;
     xml = (JSXML *) obj->getPrivate();
     if (!xml)
         return true;
 
     if (js_IdIsIndex(id, &index)) {
@@ -3808,18 +3806,17 @@ GetProperty(JSContext *cx, JSObject *obj
             }
         }
         return true;
     }
 
     /*
      * ECMA-357 9.2.1.1/9.1.1.1 qname case.
      */
-    RootedVarId funid(cx);
-    nameqn = ToXMLName(cx, IdToJsval(id), funid.address());
+    nameqn = ToXMLName(cx, IdToJsval(id), &funid);
     if (!nameqn)
         return false;
     if (!JSID_IS_VOID(funid))
         return GetXMLFunction(cx, obj, funid, vp);
 
     jsval roots[2] = { OBJECT_TO_JSVAL(nameqn), JSVAL_NULL };
     AutoArrayRooter tvr(cx, ArrayLength(roots), roots);
 
@@ -3878,31 +3875,28 @@ KidToString(JSContext *cx, JSXML *xml, u
 }
 
 /* Forward declared -- its implementation uses other statics that call it. */
 static JSBool
 ResolveValue(JSContext *cx, JSXML *list, JSXML **result);
 
 /* ECMA-357 9.1.1.2 XML [[Put]] and 9.2.1.2 XMLList [[Put]]. */
 static JSBool
-PutProperty(JSContext *cx, JSObject *obj_, jsid id_, JSBool strict, jsval *vp)
+PutProperty(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
 {
     JSBool ok, primitiveAssign;
     enum { OBJ_ROOT, ID_ROOT, VAL_ROOT };
     JSXML *xml, *vxml, *rxml, *kid, *attr, *parent, *copy, *kid2, *match;
-    JSObject *vobj, *nameobj, *attrobj, *kidobj, *copyobj;
+    JSObject *vobj, *nameobj, *attrobj, *parentobj, *kidobj, *copyobj;
     JSObject *targetprop, *nameqn, *attrqn;
     uint32_t index, i, j, k, n, q, matchIndex;
     jsval attrval, nsval;
     jsid funid;
     JSObject *ns;
 
-    RootedVarObject obj(cx, obj_);
-    RootedVarId id(cx, id_);
-
     if (!obj->isXML())
         return JS_TRUE;
     xml = (JSXML *) obj->getPrivate();
     if (!xml)
         return JS_TRUE;
 
     xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
     if (!xml)
@@ -4095,17 +4089,17 @@ PutProperty(JSContext *cx, JSObject *obj
                                               nameobj->getQNameLocalName());
                 if (!nameobj)
                     goto bad;
             }
             id = OBJECT_TO_JSID(nameobj);
 
             if (parent) {
                 /* 2(e)(i). */
-                RootedVarObject parentobj(cx, js_GetXMLObject(cx, parent));
+                parentobj = js_GetXMLObject(cx, parent);
                 if (!parentobj)
                     goto bad;
                 ok = PutProperty(cx, parentobj, id, strict, vp);
                 if (!ok)
                     goto out;
 
                 /* 2(e)(ii). */
                 ok = GetProperty(cx, parentobj, id, vp);
@@ -4303,26 +4297,26 @@ PutProperty(JSContext *cx, JSObject *obj
                 goto out;
 
             /* 7(b-c). */
             if (vxml && vxml->xml_class == JSXML_CLASS_LIST) {
                 n = vxml->xml_kids.length;
                 if (n == 0) {
                     *vp = STRING_TO_JSVAL(cx->runtime->emptyString);
                 } else {
-                    RootedVarString left(cx, KidToString(cx, vxml, 0));
+                    JSString *left = KidToString(cx, vxml, 0);
                     if (!left)
                         goto bad;
 
-                    RootedVarString space(cx, cx->runtime->atomState.spaceAtom);
+                    JSString *space = cx->runtime->atomState.spaceAtom;
                     for (i = 1; i < n; i++) {
                         left = js_ConcatStrings(cx, left, space);
                         if (!left)
                             goto bad;
-                        RootedVarString right(cx, KidToString(cx, vxml, i));
+                        JSString *right = KidToString(cx, vxml, i);
                         if (!right)
                             goto bad;
                         left = js_ConcatStrings(cx, left, right);
                         if (!left)
                             goto bad;
                     }
 
                     roots[VAL_ROOT] = *vp = STRING_TO_JSVAL(left);
@@ -4528,16 +4522,17 @@ bad:
 }
 
 /* ECMA-357 9.1.1.10 XML [[ResolveValue]], 9.2.1.10 XMLList [[ResolveValue]]. */
 static JSBool
 ResolveValue(JSContext *cx, JSXML *list, JSXML **result)
 {
     JSXML *target, *base;
     JSObject *targetprop;
+    jsid id;
     jsval tv;
 
     if (list->xml_class != JSXML_CLASS_LIST || list->xml_kids.length != 0) {
         if (!js_GetXMLObject(cx, list))
             return JS_FALSE;
         *result = list;
         return JS_TRUE;
     }
@@ -4558,17 +4553,17 @@ ResolveValue(JSContext *cx, JSXML *list,
         return JS_FALSE;
     if (!base) {
         *result = NULL;
         return JS_TRUE;
     }
     if (!js_GetXMLObject(cx, base))
         return JS_FALSE;
 
-    RootedVarId id(cx, OBJECT_TO_JSID(targetprop));
+    id = OBJECT_TO_JSID(targetprop);
     if (!GetProperty(cx, base->object, id, &tv))
         return JS_FALSE;
     target = (JSXML *) JSVAL_TO_OBJECT(tv)->getPrivate();
 
     if (JSXML_LENGTH(target) == 0) {
         if (base->xml_class == JSXML_CLASS_LIST && JSXML_LENGTH(base) > 1) {
             *result = NULL;
             return JS_TRUE;
@@ -5212,29 +5207,29 @@ again:
         return simple;
     }
 }
 
 /*
  * 11.2.2.1 Step 3(d) onward.
  */
 JSBool
-js_GetXMLMethod(JSContext *cx, HandleObject obj, jsid id, Value *vp)
+js_GetXMLMethod(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     JS_ASSERT(obj->isXML());
 
     if (JSID_IS_OBJECT(id))
         js_GetLocalNameFromFunctionQName(JSID_TO_OBJECT(id), &id, cx);
 
     /*
      * As our callers have a bad habit of passing a pointer to an unrooted
      * local value as vp, we use a proper root here.
      */
     AutoValueRooter tvr(cx);
-    JSBool ok = GetXMLFunction(cx, obj, RootedVarId(cx, id), tvr.addr());
+    JSBool ok = GetXMLFunction(cx, obj, id, tvr.addr());
     *vp = tvr.value();
     return ok;
 }
 
 JSBool
 js_TestXMLEquality(JSContext *cx, const Value &v1, const Value &v2, JSBool *bp)
 {
     JSXML *xml, *vxml;
@@ -6337,18 +6332,17 @@ xml_normalize_helper(JSContext *cx, JSOb
         if (kid->xml_class == JSXML_CLASS_ELEMENT) {
             kidobj = js_GetXMLObject(cx, kid);
             if (!kidobj || !xml_normalize_helper(cx, kidobj, kid))
                 return JS_FALSE;
         } else if (kid->xml_class == JSXML_CLASS_TEXT) {
             while (i + 1 < n &&
                    (kid2 = XMLARRAY_MEMBER(&xml->xml_kids, i + 1, JSXML)) &&
                    kid2->xml_class == JSXML_CLASS_TEXT) {
-                str = js_ConcatStrings(cx, RootedVarString(cx, kid->xml_value),
-                                       RootedVarString(cx, kid2->xml_value));
+                str = js_ConcatStrings(cx, kid->xml_value, kid2->xml_value);
                 if (!str)
                     return JS_FALSE;
                 NormalizingDelete(cx, xml, i + 1);
                 n = xml->xml_kids.length;
                 kid->xml_value = str;
             }
             if (kid->xml_value->empty()) {
                 NormalizingDelete(cx, xml, i);
@@ -6960,32 +6954,34 @@ xml_text(JSContext *cx, unsigned argc, j
     XML_METHOD_PROLOG;
     return xml_text_helper(cx, obj, xml, vp);
 }
 
 /* XML and XMLList */
 static JSString *
 xml_toString_helper(JSContext *cx, JSXML *xml)
 {
+    JSString *str, *kidstr;
+
     if (xml->xml_class == JSXML_CLASS_ATTRIBUTE ||
         xml->xml_class == JSXML_CLASS_TEXT) {
         return xml->xml_value;
     }
 
     if (!HasSimpleContent(xml))
         return ToXMLString(cx, OBJECT_TO_JSVAL(xml->object), 0);
 
-    RootedVarString str(cx, cx->runtime->emptyString);
+    str = cx->runtime->emptyString;
     if (!js_EnterLocalRootScope(cx))
         return NULL;
     JSXMLArrayCursor<JSXML> cursor(&xml->xml_kids);
     while (JSXML *kid = cursor.getNext()) {
         if (kid->xml_class != JSXML_CLASS_COMMENT &&
             kid->xml_class != JSXML_CLASS_PROCESSING_INSTRUCTION) {
-            RootedVarString kidstr(cx, xml_toString_helper(cx, kid));
+            kidstr = xml_toString_helper(cx, kid);
             if (!kidstr) {
                 str = NULL;
                 break;
             }
             str = js_ConcatStrings(cx, str, kidstr);
             if (!str)
                 break;
         }
@@ -7794,25 +7790,25 @@ js_FindXMLProperty(JSContext *cx, const 
     if (str && js_ValueToPrintable(cx, StringValue(str), &printable)) {
         JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
                                      JSMSG_UNDEFINED_XML_NAME, printable.ptr());
     }
     return JS_FALSE;
 }
 
 static JSBool
-GetXMLFunction(JSContext *cx, HandleObject obj, HandleId id, jsval *vp)
+GetXMLFunction(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 {
     JS_ASSERT(obj->isXML());
 
     /*
      * See comments before xml_lookupGeneric about the need for the proto
      * chain lookup.
      */
-    RootedVarObject target(cx, obj);
+    JSObject *target = obj;
     for (;;) {
         if (!js_GetProperty(cx, target, id, vp))
             return false;
         if (!JSVAL_IS_PRIMITIVE(*vp) && JSVAL_TO_OBJECT(*vp)->isFunction())
             return true;
         target = target->getProto();
         if (target == NULL || !target->isNative())
             break;
--- a/js/src/jsxml.h
+++ b/js/src/jsxml.h
@@ -282,17 +282,17 @@ js_GetAnyName(JSContext *cx, jsid *idp);
 
 /*
  * Note: nameval must be either QName, AttributeName, or AnyName.
  */
 extern JSBool
 js_FindXMLProperty(JSContext *cx, const js::Value &nameval, JSObject **objp, jsid *idp);
 
 extern JSBool
-js_GetXMLMethod(JSContext *cx, js::HandleObject obj, jsid id, js::Value *vp);
+js_GetXMLMethod(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
 
 extern JSBool
 js_GetXMLDescendants(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
 
 extern JSBool
 js_DeleteXMLListElements(JSContext *cx, JSObject *listobj);
 
 extern JSBool
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -6530,17 +6530,17 @@ mjit::Compiler::emitEval(uint32_t argc)
     pushSyncedEntry(0);
 }
 
 bool
 mjit::Compiler::jsop_newinit()
 {
     bool isArray;
     unsigned count = 0;
-    RootedVarObject baseobj(cx);
+    JSObject *baseobj = NULL;
     switch (*PC) {
       case JSOP_NEWINIT:
         isArray = (GET_UINT8(PC) == JSProto_Array);
         break;
       case JSOP_NEWARRAY:
         isArray = true;
         count = GET_UINT24(PC);
         break;
@@ -6566,17 +6566,17 @@ mjit::Compiler::jsop_newinit()
         stub = JS_FUNC_TO_DATA_PTR(void *, stubs::NewInitObject);
         stubArg = (void *) baseobj;
     }
 
     /*
      * Don't bake in types for non-compileAndGo scripts, or at initializers
      * producing objects with singleton types.
      */
-    RootedVarTypeObject type(cx);
+    types::TypeObject *type = NULL;
     if (globalObj && !types::UseNewTypeForInitializer(cx, script, PC)) {
         type = types::TypeScript::InitObject(cx, script, PC,
                                              isArray ? JSProto_Array : JSProto_Object);
         if (!type)
             return false;
     }
 
     size_t maxArraySlots =
@@ -7003,17 +7003,17 @@ mjit::Compiler::leaveBlock()
 //       NULL
 //   call js_CreateThisFromFunctionWithProto(...)
 //
 bool
 mjit::Compiler::constructThis()
 {
     JS_ASSERT(isConstructing);
 
-    RootedVarFunction fun(cx, script->function());
+    JSFunction *fun = script->function();
 
     do {
         if (!cx->typeInferenceEnabled() ||
             !fun->hasSingletonType() ||
             fun->getType(cx)->unknownProperties())
         {
             break;
         }
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -636,17 +636,17 @@ js_InternalThrow(VMFrame &f)
     return NULL;
 }
 
 void JS_FASTCALL
 stubs::CreateThis(VMFrame &f, JSObject *proto)
 {
     JSContext *cx = f.cx;
     StackFrame *fp = f.fp();
-    RootedVarObject callee(cx, &fp->callee());
+    JSObject *callee = &fp->callee();
     JSObject *obj = js_CreateThisForFunctionWithProto(cx, callee, proto);
     if (!obj)
         THROW();
     fp->formalArgs()[-1].setObject(*obj);
 }
 
 void JS_FASTCALL
 stubs::ScriptDebugPrologue(VMFrame &f)
@@ -898,17 +898,17 @@ js_InternalInterpret(void *returnData, v
         break;
 
       case REJOIN_DEFLOCALFUN:
         fp->slots()[GET_SLOTNO(pc)].setObject(* (JSObject *) returnReg);
         f.regs.pc = nextpc;
         break;
 
       case REJOIN_THIS_PROTOTYPE: {
-        RootedVarObject callee(cx, &fp->callee());
+        JSObject *callee = &fp->callee();
         JSObject *proto = f.regs.sp[0].isObject() ? &f.regs.sp[0].toObject() : NULL;
         JSObject *obj = js_CreateThisForFunctionWithProto(cx, callee, proto);
         if (!obj)
             return js_InternalThrow(f);
         fp->formalArgs()[-1].setObject(*obj);
 
         if (Probes::callTrackingActive(cx))
             Probes::enterJSFun(f.cx, f.fp()->maybeFun(), f.fp()->script());
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -690,37 +690,38 @@ IsCacheableProtoChain(JSObject *obj, JSO
     return true;
 }
 
 template <typename IC>
 struct GetPropHelper {
     // These fields are set in the constructor and describe a property lookup.
     JSContext   *cx;
     JSObject    *obj;
-    RootedVarPropertyName name;
+    PropertyName *name;
     IC          &ic;
     VMFrame     &f;
 
     // These fields are set by |bind| and |lookup|. After a call to either
     // function, these are set exactly as they are in JSOP_GETPROP or JSOP_NAME.
+    JSObject    *aobj;
     JSObject    *holder;
     JSProperty  *prop;
 
     // This field is set by |bind| and |lookup| only if they returned
     // Lookup_Cacheable, otherwise it is NULL.
     const Shape *shape;
 
     GetPropHelper(JSContext *cx, JSObject *obj, PropertyName *name, IC &ic, VMFrame &f)
-      : cx(cx), obj(obj), name(cx, name), ic(ic), f(f), holder(NULL), prop(NULL), shape(NULL)
+      : cx(cx), obj(obj), name(name), ic(ic), f(f), holder(NULL), prop(NULL), shape(NULL)
     { }
 
   public:
     LookupStatus bind() {
         RecompilationMonitor monitor(cx);
-        RootedVarObject scopeChain(cx, cx->stack.currentScriptedScopeChain());
+        JSObject *scopeChain = cx->stack.currentScriptedScopeChain();
         if (js_CodeSpec[*f.pc()].format & JOF_GNAME)
             scopeChain = &scopeChain->global();
         if (!FindProperty(cx, name, scopeChain, &obj, &holder, &prop))
             return ic.error(cx);
         if (monitor.recompiled())
             return Lookup_Uncacheable;
         if (!prop)
             return ic.disable(cx, "lookup failed");
@@ -728,19 +729,17 @@ struct GetPropHelper {
             return ic.disable(cx, "non-native");
         if (!IsCacheableProtoChain(obj, holder))
             return ic.disable(cx, "non-native holder");
         shape = (const Shape *)prop;
         return Lookup_Cacheable;
     }
 
     LookupStatus lookup() {
-        JSObject *aobj = obj;
-        if (obj->isDenseArray())
-            aobj = obj->getProto();
+        JSObject *aobj = js_GetProtoIfDenseArray(obj);
         if (!aobj->isNative())
             return ic.disable(f, "non-native");
 
         RecompilationMonitor monitor(cx);
         if (!aobj->lookupProperty(cx, name, &holder, &prop))
             return ic.error(cx);
         if (monitor.recompiled())
             return Lookup_Uncacheable;
@@ -2376,17 +2375,18 @@ GetElementIC::attachTypedArray(VMFrame &
 #endif /* JS_METHODJIT_TYPED_ARRAY */
 
 LookupStatus
 GetElementIC::update(VMFrame &f, JSObject *obj, const Value &v, jsid id, Value *vp)
 {
     /*
      * Only treat this as a GETPROP for non-numeric string identifiers. The
      * GETPROP IC assumes the id has already gone through filtering for string
-     * indexes in the emitter.
+     * indexes in the emitter, i.e. js_GetProtoIfDenseArray is only valid to
+     * use when looking up non-integer identifiers.
      */
     uint32_t dummy;
     if (v.isString() && JSID_IS_ATOM(id) && !JSID_TO_ATOM(id)->isIndex(&dummy))
         return attachGetProp(f, obj, v, JSID_TO_ATOM(id)->asPropertyName(), vp);
 
 #if defined JS_METHODJIT_TYPED_ARRAY
     /*
      * Typed array ICs can make stub calls, and need to know which registers
@@ -2416,17 +2416,17 @@ ic::GetElement(VMFrame &f, ic::GetElemen
         stubs::GetElem(f);
         return;
     }
 
     Value idval = f.regs.sp[-1];
 
     RecompilationMonitor monitor(cx);
 
-    RootedVarObject obj(cx, ValueToObject(cx, f.regs.sp[-2]));
+    JSObject *obj = ValueToObject(cx, f.regs.sp[-2]);
     if (!obj)
         THROW();
 
 #if JS_HAS_XML_SUPPORT
     // Some XML properties behave differently when accessed in a call vs. normal
     // context, so we fall back to stubs::GetElem.
     if (obj->isXML()) {
         ic->disable(f, "XML object");
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -211,24 +211,21 @@ stubs::ToId(VMFrame &f)
     if (!FetchElementId(f.cx, obj, idval, id, &idval))
         THROW();
 
     if (!idval.isInt32())
         TypeScript::MonitorUnknown(f.cx, f.script(), f.pc());
 }
 
 void JS_FASTCALL
-stubs::ImplicitThis(VMFrame &f, PropertyName *name_)
+stubs::ImplicitThis(VMFrame &f, PropertyName *name)
 {
-    RootedVarObject scopeObj(f.cx, f.cx->stack.currentScriptedScopeChain());
-    RootedVarPropertyName name(f.cx, name_);
-
     JSObject *obj, *obj2;
     JSProperty *prop;
-    if (!FindPropertyHelper(f.cx, name, false, scopeObj, &obj, &obj2, &prop))
+    if (!FindPropertyHelper(f.cx, name, false, f.cx->stack.currentScriptedScopeChain(), &obj, &obj2, &prop))
         THROW();
 
     if (!ComputeImplicitThis(f.cx, obj, &f.regs.sp[0]))
         THROW();
 }
 
 void JS_FASTCALL
 stubs::BitOr(VMFrame &f)
@@ -314,32 +311,31 @@ stubs::Ursh(VMFrame &f)
     u >>= (j & 31);
 
 	if (!f.regs.sp[-2].setNumber(uint32_t(u)))
         TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
 }
 
 template<JSBool strict>
 void JS_FASTCALL
-stubs::DefFun(VMFrame &f, JSFunction *fun_)
+stubs::DefFun(VMFrame &f, JSFunction *fun)
 {
-    RootedVarFunction fun(f.cx, fun_);
+    JSObject *obj2;
 
     JSContext *cx = f.cx;
     StackFrame *fp = f.fp();
 
     /*
      * A top-level function defined in Global or Eval code (see ECMA-262
      * Ed. 3), or else a SpiderMonkey extension: a named function statement in
      * a compound statement (not at the top statement level of global code, or
      * at the top level of a function body).
      */
     JSObject *obj = fun;
 
-    RootedVarObject obj2(f.cx);
     if (fun->isNullClosure()) {
         /*
          * Even a null closure needs a parent for principals finding.
          * FIXME: bug 476950, although debugger users may also demand some kind
          * of scope link for debugger-assisted eval-in-frame.
          */
         obj2 = &fp->scopeChain();
     } else {
@@ -619,17 +615,17 @@ stubs::Add(VMFrame &f)
     JSContext *cx = f.cx;
     FrameRegs &regs = f.regs;
     Value rval = regs.sp[-1];
     Value lval = regs.sp[-2];
 
     /* The string + string case is easily the hottest;  try it first. */
     bool lIsString = lval.isString();
     bool rIsString = rval.isString();
-    RootedVarString lstr(cx), rstr(cx);
+    JSString *lstr, *rstr;
     if (lIsString && rIsString) {
         lstr = lval.toString();
         rstr = rval.toString();
         goto string_concat;
 
     } else
 #if JS_HAS_XML_SUPPORT
     if (lval.isObject() && lval.toObject().isXML() &&
@@ -923,17 +919,17 @@ void JS_FASTCALL
 stubs::NewInitObject(VMFrame &f, JSObject *baseobj)
 {
     JSContext *cx = f.cx;
     TypeObject *type = (TypeObject *) f.scratch;
 
     JSObject *obj;
 
     if (baseobj) {
-        obj = CopyInitializerObject(cx, RootedVarObject(cx, baseobj));
+        obj = CopyInitializerObject(cx, baseobj);
     } else {
         gc::AllocKind kind = GuessObjectGCKind(0);
         obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
     }
 
     if (!obj)
         THROW();
 
@@ -998,21 +994,19 @@ stubs::RegExp(VMFrame &f, JSObject *rege
     JS_ASSERT(proto);
     JSObject *obj = CloneRegExpObject(f.cx, regex, proto);
     if (!obj)
         THROW();
     f.regs.sp[0].setObject(*obj);
 }
 
 JSObject * JS_FASTCALL
-stubs::Lambda(VMFrame &f, JSFunction *fun_)
+stubs::Lambda(VMFrame &f, JSFunction *fun)
 {
-    RootedVarFunction fun(f.cx, fun_);
-
-    RootedVarObject parent(f.cx);
+    JSObject *parent;
     if (fun->isNullClosure()) {
         parent = &f.fp()->scopeChain();
     } else {
         parent = GetScopeChain(f.cx, f.fp());
         if (!parent)
             THROWV(NULL);
     }
 
@@ -1073,17 +1067,17 @@ InitPropOrMethod(VMFrame &f, PropertyNam
     FrameRegs &regs = f.regs;
 
     /* Load the property's initial value into rval. */
     JS_ASSERT(regs.sp - f.fp()->base() >= 2);
     Value rval;
     rval = regs.sp[-1];
 
     /* Load the object being initialized into lval/obj. */
-    RootedVarObject obj(cx, &regs.sp[-2].toObject());
+    JSObject *obj = &regs.sp[-2].toObject();
     JS_ASSERT(obj->isNative());
 
     /* Get the immediate property name into id. */
     jsid id = ATOM_TO_JSID(name);
 
     if (JS_UNLIKELY(name == cx->runtime->atomState.protoAtom)
         ? !js_SetPropertyHelper(cx, obj, id, 0, &rval, false)
         : !DefineNativeProperty(cx, obj, id, rval, NULL, NULL,
@@ -1114,17 +1108,17 @@ stubs::IterNext(VMFrame &f, int32_t offs
 JSBool JS_FASTCALL
 stubs::IterMore(VMFrame &f)
 {
     JS_ASSERT(f.regs.sp - 1 >= f.fp()->base());
     JS_ASSERT(f.regs.sp[-1].isObject());
 
     Value v;
     JSObject *iterobj = &f.regs.sp[-1].toObject();
-    if (!js_IteratorMore(f.cx, RootedVarObject(f.cx, iterobj), &v))
+    if (!js_IteratorMore(f.cx, iterobj, &v))
         THROWV(JS_FALSE);
 
     return v.toBoolean();
 }
 
 void JS_FASTCALL
 stubs::EndIter(VMFrame &f)
 {
@@ -1417,24 +1411,21 @@ stubs::Pos(VMFrame &f)
 {
     if (!ToNumber(f.cx, &f.regs.sp[-1]))
         THROW();
     if (!f.regs.sp[-1].isInt32())
         TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
 }
 
 void JS_FASTCALL
-stubs::DelName(VMFrame &f, PropertyName *name_)
+stubs::DelName(VMFrame &f, PropertyName *name)
 {
-    RootedVarObject scopeObj(f.cx, f.cx->stack.currentScriptedScopeChain());
-    RootedVarPropertyName name(f.cx, name_);
-
     JSObject *obj, *obj2;
     JSProperty *prop;
-    if (!FindProperty(f.cx, name, scopeObj, &obj, &obj2, &prop))
+    if (!FindProperty(f.cx, name, f.cx->stack.currentScriptedScopeChain(), &obj, &obj2, &prop))
         THROW();
 
     /* 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);
@@ -1487,17 +1478,17 @@ stubs::DefVarOrConst(VMFrame &f, Propert
     unsigned attrs = JSPROP_ENUMERATE;
     if (!f.fp()->isEvalFrame())
         attrs |= JSPROP_PERMANENT;
     if (JSOp(*f.regs.pc) == JSOP_DEFCONST)
         attrs |= JSPROP_READONLY;
 
     JSObject &obj = f.fp()->varObj();
 
-    if (!DefVarOrConstOperation(f.cx, RootedVarObject(f.cx, &obj), dn, attrs))
+    if (!DefVarOrConstOperation(f.cx, obj, dn, attrs))
         THROW();
 }
 
 void JS_FASTCALL
 stubs::SetConst(VMFrame &f, PropertyName *name)
 {
     JSContext *cx = f.cx;
 
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -2737,26 +2737,24 @@ ShapeOf(JSContext *cx, unsigned argc, js
 }
 
 /*
  * If referent has an own property named id, copy that property to obj[id].
  * Since obj is native, this isn't totally transparent; properties of a
  * non-native referent may be simplified to data properties.
  */
 static JSBool
-CopyProperty(JSContext *cx, JSObject *obj_, JSObject *referent, jsid id,
+CopyProperty(JSContext *cx, JSObject *obj, JSObject *referent, jsid id,
              unsigned lookupFlags, JSObject **objp)
 {
     JSProperty *prop;
     PropertyDescriptor desc;
     unsigned propFlags = 0;
     JSObject *obj2;
 
-    RootedVarObject obj(cx, obj_);
-
     *objp = NULL;
     if (referent->isNative()) {
         if (!LookupPropertyWithFlags(cx, referent, id, lookupFlags, &obj2, &prop))
             return false;
         if (obj2 != referent)
             return true;
 
         const Shape *shape = (Shape *) prop;
@@ -4298,21 +4296,19 @@ global_enumerate(JSContext *cx, JSObject
 #ifdef LAZY_STANDARD_CLASSES
     return JS_EnumerateStandardClasses(cx, obj);
 #else
     return JS_TRUE;
 #endif
 }
 
 static JSBool
-global_resolve(JSContext *cx, JSObject *obj_, jsid id, unsigned flags,
+global_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
                JSObject **objp)
 {
-    RootedVarObject obj(cx, obj_);
-
 #ifdef LAZY_STANDARD_CLASSES
     JSBool resolved;
 
     if (!JS_ResolveStandardClass(cx, obj, id, &resolved))
         return JS_FALSE;
     if (resolved) {
         *objp = obj;
         return JS_TRUE;
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -81,31 +81,31 @@ js_PutArgsObject(StackFrame *fp)
         fp->forEachCanonicalActualArg(PutArg(comp, argsobj));
         argsobj.setStackFrame(NULL);
     } else {
         JS_ASSERT(!argsobj.maybeStackFrame());
     }
 }
 
 ArgumentsObject *
-ArgumentsObject::create(JSContext *cx, uint32_t argc, HandleObject callee)
+ArgumentsObject::create(JSContext *cx, uint32_t argc, JSObject &callee)
 {
     JS_ASSERT(argc <= StackSpace::ARGS_LENGTH_MAX);
 
-    RootedVarObject proto(cx, callee->global().getOrCreateObjectPrototype(cx));
+    JSObject *proto = callee.global().getOrCreateObjectPrototype(cx);
     if (!proto)
         return NULL;
 
     RootedVarTypeObject type(cx);
 
     type = proto->getNewType(cx);
     if (!type)
         return NULL;
 
-    bool strict = callee->toFunction()->inStrictMode();
+    bool strict = callee.toFunction()->inStrictMode();
     Class *clasp = strict ? &StrictArgumentsObjectClass : &NormalArgumentsObjectClass;
 
     RootedVarShape emptyArgumentsShape(cx);
     emptyArgumentsShape =
         EmptyShape::getInitialShape(cx, clasp, proto,
                                     proto->getParent(), FINALIZE_KIND,
                                     BaseShape::INDEXED);
     if (!emptyArgumentsShape)
@@ -115,17 +115,17 @@ ArgumentsObject::create(JSContext *cx, u
     unsigned numBytes = offsetof(ArgumentsData, slots) +
                         numDeletedWords * sizeof(size_t) +
                         argc * sizeof(Value);
 
     ArgumentsData *data = (ArgumentsData *)cx->malloc_(numBytes);
     if (!data)
         return NULL;
 
-    data->callee.init(ObjectValue(*callee));
+    data->callee.init(ObjectValue(callee));
     for (HeapValue *vp = data->slots; vp != data->slots + argc; vp++)
         vp->init(UndefinedValue());
     data->deletedBits = (size_t *)(data->slots + argc);
     ClearAllBitArrayElements(data->deletedBits, numDeletedWords);
 
     /* We have everything needed to fill in the object, so make the object. */
     JSObject *obj = JSObject::create(cx, FINALIZE_KIND, emptyArgumentsShape, type, NULL);
     if (!obj)
@@ -144,18 +144,17 @@ ArgumentsObject::create(JSContext *cx, u
     return &argsobj;
 }
 
 ArgumentsObject *
 ArgumentsObject::create(JSContext *cx, StackFrame *fp)
 {
     JS_ASSERT(fp->script()->needsArgsObj());
 
-    ArgumentsObject *argsobj = ArgumentsObject::create(cx, fp->numActualArgs(),
-                                                       RootedVarObject(cx, &fp->callee()));
+    ArgumentsObject *argsobj = ArgumentsObject::create(cx, fp->numActualArgs(), fp->callee());
     if (!argsobj)
         return NULL;
 
     /*
      * Strict mode functions have arguments objects that copy the initial
      * actual parameter values. Non-strict mode arguments use the frame pointer
      * to retrieve up-to-date parameter values.
      */
@@ -166,17 +165,17 @@ ArgumentsObject::create(JSContext *cx, S
 
     fp->initArgsObj(*argsobj);
     return argsobj;
 }
 
 ArgumentsObject *
 ArgumentsObject::createUnexpected(JSContext *cx, StackFrame *fp)
 {
-    ArgumentsObject *argsobj = create(cx, fp->numActualArgs(), RootedVarObject(cx, &fp->callee()));
+    ArgumentsObject *argsobj = create(cx, fp->numActualArgs(), fp->callee());
     if (!argsobj)
         return NULL;
 
     fp->forEachCanonicalActualArg(PutArg(cx->compartment, *argsobj));
     return argsobj;
 }
 
 static JSBool
@@ -271,41 +270,41 @@ ArgSetter(JSContext *cx, JSObject *obj, 
 }
 
 static JSBool
 args_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
              JSObject **objp)
 {
     *objp = NULL;
 
-    RootedVar<NormalArgumentsObject*> argsobj(cx, &obj->asNormalArguments());
+    NormalArgumentsObject &argsobj = obj->asNormalArguments();
 
     unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
     if (JSID_IS_INT(id)) {
         uint32_t arg = uint32_t(JSID_TO_INT(id));
-        if (arg >= argsobj->initialLength() || argsobj->isElementDeleted(arg))
+        if (arg >= argsobj.initialLength() || argsobj.isElementDeleted(arg))
             return true;
 
         attrs |= JSPROP_ENUMERATE;
     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
-        if (argsobj->hasOverriddenLength())
+        if (argsobj.hasOverriddenLength())
             return true;
     } else {
         if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom))
             return true;
 
-        if (argsobj->callee().isMagic(JS_OVERWRITTEN_CALLEE))
+        if (argsobj.callee().isMagic(JS_OVERWRITTEN_CALLEE))
             return true;
     }
 
     Value undef = UndefinedValue();
-    if (!js_DefineProperty(cx, argsobj, id, &undef, ArgGetter, ArgSetter, attrs))
+    if (!js_DefineProperty(cx, &argsobj, id, &undef, ArgGetter, ArgSetter, attrs))
         return JS_FALSE;
 
-    *objp = argsobj;
+    *objp = &argsobj;
     return true;
 }
 
 bool
 NormalArgumentsObject::optimizedGetElem(JSContext *cx, StackFrame *fp, const Value &elem, Value *vp)
 {
     JS_ASSERT(!fp->hasArgsObj());
 
@@ -400,38 +399,37 @@ StrictArgGetter(JSContext *cx, JSObject 
 }
 
 static JSBool
 StrictArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
 {
     if (!obj->isStrictArguments())
         return true;
 
-    RootedVar<StrictArgumentsObject*> argsobj(cx, &obj->asStrictArguments());
-    RootId idRoot(cx, &id);
+    StrictArgumentsObject &argsobj = obj->asStrictArguments();
 
     if (JSID_IS_INT(id)) {
         unsigned arg = unsigned(JSID_TO_INT(id));
-        if (arg < argsobj->initialLength()) {
-            argsobj->setElement(arg, *vp);
+        if (arg < argsobj.initialLength()) {
+            argsobj.setElement(arg, *vp);
             return true;
         }
     } else {
         JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom));
     }
 
     /*
      * For simplicity we use delete/set to replace the property with one
      * backed by the default Object getter and setter. Note that we rely on
      * args_delProperty to clear the corresponding reserved slot so the GC can
      * collect its value.
      */
     AutoValueRooter tvr(cx);
-    return js_DeleteGeneric(cx, argsobj, id, tvr.addr(), strict) &&
-           js_SetPropertyHelper(cx, argsobj, id, 0, vp, strict);
+    return js_DeleteGeneric(cx, &argsobj, id, tvr.addr(), strict) &&
+           js_SetPropertyHelper(cx, &argsobj, id, 0, vp, strict);
 }
 
 static JSBool
 strictargs_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags, JSObject **objp)
 {
     *objp = NULL;
 
     StrictArgumentsObject &argsobj = obj->asStrictArguments();
--- a/js/src/vm/ArgumentsObject.h
+++ b/js/src/vm/ArgumentsObject.h
@@ -133,17 +133,17 @@ class ArgumentsObject : public JSObject
     static const uint32_t STACK_FRAME_SLOT = 2;
 
     /* Lower-order bit stolen from the length slot. */
     static const uint32_t LENGTH_OVERRIDDEN_BIT = 0x1;
     static const uint32_t PACKED_BITS_COUNT = 1;
 
     void initInitialLength(uint32_t length);
     void initData(ArgumentsData *data);
-    static ArgumentsObject *create(JSContext *cx, uint32_t argc, HandleObject callee);
+    static ArgumentsObject *create(JSContext *cx, uint32_t argc, JSObject &callee);
 
   public:
     static const uint32_t RESERVED_SLOTS = 3;
     static const gc::AllocKind FINALIZE_KIND = gc::FINALIZE_OBJECT4;
 
     /* Create an arguments object for a frame that is expecting them. */
     static ArgumentsObject *create(JSContext *cx, StackFrame *fp);
 
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -823,17 +823,17 @@ Debugger::newCompletionValue(JSContext *
         result->setNull();
         return true;
 
       default:
         JS_NOT_REACHED("bad status passed to Debugger::newCompletionValue");
     }
 
     /* Common tail for JSTRAP_RETURN and JSTRAP_THROW. */
-    RootedVarObject obj(cx, NewBuiltinClassInstance(cx, &ObjectClass));
+    JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass);
     if (!obj ||
         !wrapDebuggeeValue(cx, &value) ||
         !DefineNativeProperty(cx, obj, key, value, JS_PropertyStub, JS_StrictPropertyStub,
                               JSPROP_ENUMERATE, 0, 0))
     {
         return false;
     }
 
@@ -899,17 +899,17 @@ Debugger::parseResumptionValue(AutoCompa
     if (!cx->compartment->wrap(cx, vp)) {
         vp->setUndefined();
         return JSTRAP_ERROR;
     }
     return shape->propid() == returnId ? JSTRAP_RETURN : JSTRAP_THROW;
 }
 
 bool
-CallMethodIfPresent(JSContext *cx, HandleObject obj, const char *name, int argc, Value *argv,
+CallMethodIfPresent(JSContext *cx, JSObject *obj, const char *name, int argc, Value *argv,
                     Value *rval)
 {
     rval->setUndefined();
     JSAtom *atom = js_Atomize(cx, name, strlen(name));
     Value fval;
     return atom &&
            js_GetMethod(cx, obj, ATOM_TO_JSID(atom), 0, &fval) &&
            (!js_IsCallable(fval) ||
@@ -1137,17 +1137,17 @@ Debugger::onTrap(JSContext *cx, Value *v
             AutoCompartment ac(cx, dbg->object);
             if (!ac.enter())
                 return JSTRAP_ERROR;
 
             Value argv[1];
             if (!dbg->getScriptFrame(cx, fp, &argv[0]))
                 return dbg->handleUncaughtException(ac, vp, false);
             Value rv;
-            bool ok = CallMethodIfPresent(cx, RootedVarObject(cx, bp->handler), "hit", 1, argv, &rv);
+            bool ok = CallMethodIfPresent(cx, bp->handler, "hit", 1, argv, &rv);
             JSTrapStatus st = dbg->parseResumptionValue(ac, ok, rv, vp, true);
             if (st != JSTRAP_CONTINUE)
                 return st;
 
             /* Calling JS code invalidates site. Reload it. */
             site = script->getBreakpointSite(pc);
         }
     }
@@ -3167,17 +3167,17 @@ DebuggerFrame_getArguments(JSContext *cx
     THIS_FRAME(cx, argc, vp, "get arguments", args, thisobj, fp);
     Value argumentsv = thisobj->getReservedSlot(JSSLOT_DEBUGFRAME_ARGUMENTS);
     if (!argumentsv.isUndefined()) {
         JS_ASSERT(argumentsv.isObjectOrNull());
         args.rval() = argumentsv;
         return true;
     }
 
-    RootedVarObject argsobj(cx);
+    JSObject *argsobj;
     if (fp->hasArgs()) {
         /* Create an arguments object. */
         RootedVar<GlobalObject*> global(cx);
         global = &args.callee().global();
         JSObject *proto = global->getOrCreateArrayPrototype(cx);
         if (!proto)
             return false;
         argsobj = NewObjectWithGivenProto(cx, &DebuggerArguments_class, proto, global);
@@ -3432,17 +3432,17 @@ DebuggerFrameEval(JSContext *cx, unsigne
             }
         }
     }
 
     AutoCompartment ac(cx, &fp->scopeChain());
     if (!ac.enter())
         return false;
 
-    RootedVar<Env*> env(cx, JS_GetFrameScopeChain(cx, Jsvalify(fp)));
+    Env *env = JS_GetFrameScopeChain(cx, Jsvalify(fp));
     if (!env)
         return false;
 
     /* If evalWithBindings, create the inner environment. */
     if (mode == WithBindings) {
         /* TODO - This should probably be a Call object, like ES5 strict eval. */
         env = NewObjectWithGivenProto(cx, &ObjectClass, NULL, env);
         if (!env)
@@ -3559,25 +3559,25 @@ DebuggerObject_checkThis(JSContext *cx, 
                              "Debugger.Object", fnname, "prototype object");
         return NULL;
     }
     return thisobj;
 }
 
 #define THIS_DEBUGOBJECT_REFERENT(cx, argc, vp, fnname, args, obj)            \
     CallArgs args = CallArgsFromVp(argc, vp);                                 \
-    RootedVarObject obj(cx, DebuggerObject_checkThis(cx, args, fnname));      \
+    JSObject *obj = DebuggerObject_checkThis(cx, args, fnname);               \
     if (!obj)                                                                 \
         return false;                                                         \
     obj = (JSObject *) obj->getPrivate();                                     \
     JS_ASSERT(obj)
 
 #define THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, fnname, args, dbg, obj) \
     CallArgs args = CallArgsFromVp(argc, vp);                                 \
-    RootedVarObject obj(cx, DebuggerObject_checkThis(cx, args, fnname));      \
+    JSObject *obj = DebuggerObject_checkThis(cx, args, fnname);               \
     if (!obj)                                                                 \
         return false;                                                         \
     Debugger *dbg = Debugger::fromChildJSObject(obj);                         \
     obj = (JSObject *) obj->getPrivate();                                     \
     JS_ASSERT(obj)
 
 static JSBool
 DebuggerObject_construct(JSContext *cx, unsigned argc, Value *vp)
@@ -3715,25 +3715,25 @@ DebuggerObject_getEnvironment(JSContext 
     return dbg->wrapEnvironment(cx, env, &args.rval());
 }
 
 static JSBool
 DebuggerObject_getOwnPropertyDescriptor(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "getOwnPropertyDescriptor", args, dbg, obj);
 
-    RootedVarId id(cx);
-    if (!ValueToId(cx, argc >= 1 ? args[0] : UndefinedValue(), id.address()))
+    jsid id;
+    if (!ValueToId(cx, argc >= 1 ? args[0] : UndefinedValue(), &id))
         return false;
 
     /* Bug: This can cause the debuggee to run! */
     AutoPropertyDescriptorRooter desc(cx);
     {
         AutoCompartment ac(cx, obj);
-        if (!ac.enter() || !cx->compartment->wrapId(cx, id.address()))
+        if (!ac.enter() || !cx->compartment->wrapId(cx, &id))
             return false;
 
         ErrorCopier ec(ac, dbg->toJSObject());
         if (!GetOwnPropertyDescriptor(cx, obj, id, &desc))
             return false;
     }
 
     if (desc.obj) {
@@ -3849,33 +3849,33 @@ WrapIdAndPropDesc(JSContext *cx, JSObjec
 }
 
 static JSBool
 DebuggerObject_defineProperty(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "defineProperty", args, dbg, obj);
     REQUIRE_ARGC("Debugger.Object.defineProperty", 2);
 
-    RootedVarId id(cx);
-    if (!ValueToId(cx, args[0], id.address()))
+    jsid id;
+    if (!ValueToId(cx, args[0], &id))
         return JS_FALSE;
 
     const Value &descval = args[1];
     AutoPropDescArrayRooter descs(cx);
     PropDesc *desc = descs.append();
     if (!desc || !desc->initialize(cx, descval, false))
         return false;
 
     desc->pd.setUndefined();
     if (!UnwrapPropDesc(cx, dbg, obj, desc))
         return false;
 
     {
         AutoCompartment ac(cx, obj);
-        if (!ac.enter() || !WrapIdAndPropDesc(cx, obj, id.address(), desc))
+        if (!ac.enter() || !WrapIdAndPropDesc(cx, obj, &id, desc))
             return false;
 
         ErrorCopier ec(ac, dbg->toJSObject());
         bool dummy;
         if (!DefineProperty(cx, obj, id, *desc, true, &dummy))
             return false;
     }
 
@@ -3910,17 +3910,17 @@ DebuggerObject_defineProperties(JSContex
         for (size_t i = 0; i < n; i++) {
             if (!WrapIdAndPropDesc(cx, obj, &ids[i], &descs[i]))
                 return false;
         }
 
         ErrorCopier ec(ac, dbg->toJSObject());
         for (size_t i = 0; i < n; i++) {
             bool dummy;
-            if (!DefineProperty(cx, obj, RootedVarId(cx, ids[i]), descs[i], true, &dummy))
+            if (!DefineProperty(cx, obj, ids[i], descs[i], true, &dummy))
                 return false;
         }
     }
 
     args.rval().setUndefined();
     return true;
 }
 
--- a/js/src/vm/ObjectImpl.cpp
+++ b/js/src/vm/ObjectImpl.cpp
@@ -137,25 +137,16 @@ MOZ_NEVER_INLINE
 const Shape *
 js::ObjectImpl::nativeLookup(JSContext *cx, jsid id)
 {
     MOZ_ASSERT(isNative());
     Shape **spp;
     return Shape::search(cx, lastProperty(), id, &spp);
 }
 
-#ifdef DEBUG
-const Shape *
-js::ObjectImpl::nativeLookupNoAllocation(JSContext *cx, jsid id)
-{
-    MOZ_ASSERT(isNative());
-    return Shape::searchNoAllocation(cx, lastProperty(), id);
-}
-#endif
-
 void
 js::ObjectImpl::markChildren(JSTracer *trc)
 {
     MarkTypeObject(trc, &type_, "type");
 
     MarkShape(trc, &shape_, "shape");
 
     Class *clasp = shape_->getObjectClass();
--- a/js/src/vm/ObjectImpl.h
+++ b/js/src/vm/ObjectImpl.h
@@ -742,20 +742,16 @@ class ObjectImpl : public gc::Cell
 
     inline uint32_t slotSpan() const;
 
     /* Compute dynamicSlotsCount() for this object. */
     inline uint32_t numDynamicSlots() const;
 
     const Shape * nativeLookup(JSContext *cx, jsid id);
 
-#ifdef DEBUG
-    const Shape * nativeLookupNoAllocation(JSContext *cx, jsid id);
-#endif
-
     inline Class *getClass() const;
     inline JSClass *getJSClass() const;
     inline bool hasClass(const Class *c) const;
     inline const ObjectOps *getOps() const;
 
     /*
      * An object is a delegate if it is on another object's prototype or scope
      * chain, and therefore the delegate might be asked implicitly to get or
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -55,17 +55,17 @@ using js::detail::RegExpCode;
 JS_STATIC_ASSERT(IgnoreCaseFlag == JSREG_FOLD);
 JS_STATIC_ASSERT(GlobalFlag == JSREG_GLOB);
 JS_STATIC_ASSERT(MultilineFlag == JSREG_MULTILINE);
 JS_STATIC_ASSERT(StickyFlag == JSREG_STICKY);
 
 /* RegExpObjectBuilder */
 
 RegExpObjectBuilder::RegExpObjectBuilder(JSContext *cx, RegExpObject *reobj)
-  : cx(cx), reobj_(cx, reobj)
+  : cx(cx), reobj_(reobj)
 {}
 
 bool
 RegExpObjectBuilder::getOrCreate()
 {
     if (reobj_)
         return true;
 
@@ -88,61 +88,61 @@ RegExpObjectBuilder::getOrCreateClone(Re
         return false;
     clone->initPrivate(NULL);
 
     reobj_ = &clone->asRegExp();
     return true;
 }
 
 RegExpObject *
-RegExpObjectBuilder::build(HandleAtom source, RegExpShared &shared)
+RegExpObjectBuilder::build(JSAtom *source, RegExpShared &shared)
 {
     if (!getOrCreate())
         return NULL;
 
     if (!reobj_->init(cx, source, shared.getFlags()))
         return NULL;
 
     reobj_->setShared(cx, shared);
     return reobj_;
 }
 
 RegExpObject *
-RegExpObjectBuilder::build(HandleAtom source, RegExpFlag flags)
+RegExpObjectBuilder::build(JSAtom *source, RegExpFlag flags)
 {
     if (!getOrCreate())
         return NULL;
 
-    return reobj_->init(cx, source, flags) ? reobj_.raw() : NULL;
+    return reobj_->init(cx, source, flags) ? reobj_ : NULL;
 }
 
 RegExpObject *
-RegExpObjectBuilder::clone(Handle<RegExpObject *> other, Handle<RegExpObject *> proto)
+RegExpObjectBuilder::clone(RegExpObject *other, RegExpObject *proto)
 {
     if (!getOrCreateClone(proto))
         return NULL;
 
     /*
      * Check that the RegExpShared for the original is okay to use in
      * the clone -- if the |RegExpStatics| provides more flags we'll
      * need a different |RegExpShared|.
      */
     RegExpStatics *res = cx->regExpStatics();
     RegExpFlag origFlags = other->getFlags();
     RegExpFlag staticsFlags = res->getFlags();
     if ((origFlags & staticsFlags) != staticsFlags) {
         RegExpFlag newFlags = RegExpFlag(origFlags | staticsFlags);
-        return build(RootedVar<JSAtom *>(cx, other->getSource()), newFlags);
+        return build(other->getSource(), newFlags);
     }
 
     RegExpGuard g;
     if (!other->getShared(cx, &g))
         return NULL;
 
-    return build(RootedVarAtom(cx, other->getSource()), *g);
+    return build(other->getSource(), *g);
 }
 
 /* MatchPairs */
 
 MatchPairs *
 MatchPairs::create(LifoAlloc &alloc, size_t pairCount, size_t backingPairCount)
 {
     void *mem = alloc.alloc(calculateSize(backingPairCount));
@@ -368,25 +368,25 @@ RegExpObject::create(JSContext *cx, RegE
     RegExpFlag staticsFlags = res->getFlags();
     return createNoStatics(cx, chars, length, RegExpFlag(flags | staticsFlags), tokenStream);
 }
 
 RegExpObject *
 RegExpObject::createNoStatics(JSContext *cx, const jschar *chars, size_t length, RegExpFlag flags,
                               TokenStream *tokenStream)
 {
-    RootedVarAtom source(cx, js_AtomizeChars(cx, chars, length));
+    JSAtom *source = js_AtomizeChars(cx, chars, length);
     if (!source)
         return NULL;
 
     return createNoStatics(cx, source, flags, tokenStream);
 }
 
 RegExpObject *
-RegExpObject::createNoStatics(JSContext *cx, HandleAtom source, RegExpFlag flags,
+RegExpObject::createNoStatics(JSContext *cx, JSAtom *source, RegExpFlag flags,
                               TokenStream *tokenStream)
 {
     if (!RegExpCode::checkSyntax(cx, tokenStream, source))
         return NULL;
 
     RegExpObjectBuilder builder(cx);
     return builder.build(source, flags);
 }
@@ -410,86 +410,78 @@ RegExpObject::assignInitialShape(JSConte
 
     JS_STATIC_ASSERT(LAST_INDEX_SLOT == 0);
     JS_STATIC_ASSERT(SOURCE_SLOT == LAST_INDEX_SLOT + 1);
     JS_STATIC_ASSERT(GLOBAL_FLAG_SLOT == SOURCE_SLOT + 1);
     JS_STATIC_ASSERT(IGNORE_CASE_FLAG_SLOT == GLOBAL_FLAG_SLOT + 1);
     JS_STATIC_ASSERT(MULTILINE_FLAG_SLOT == IGNORE_CASE_FLAG_SLOT + 1);
     JS_STATIC_ASSERT(STICKY_FLAG_SLOT == MULTILINE_FLAG_SLOT + 1);
 
-    RootedVarObject self(cx, this);
-
     /* The lastIndex property alone is writable but non-configurable. */
     if (!addDataProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lastIndexAtom),
                          LAST_INDEX_SLOT, JSPROP_PERMANENT))
     {
         return NULL;
     }
 
     /* Remaining instance properties are non-writable and non-configurable. */
-    if (!self->addDataProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.sourceAtom),
-                               SOURCE_SLOT, JSPROP_PERMANENT | JSPROP_READONLY) ||
-        !self->addDataProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.globalAtom),
-                               GLOBAL_FLAG_SLOT, JSPROP_PERMANENT | JSPROP_READONLY) ||
-        !self->addDataProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.ignoreCaseAtom),
-                               IGNORE_CASE_FLAG_SLOT, JSPROP_PERMANENT | JSPROP_READONLY) ||
-        !self->addDataProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.multilineAtom),
-                               MULTILINE_FLAG_SLOT, JSPROP_PERMANENT | JSPROP_READONLY))
+    if (!addDataProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.sourceAtom),
+                         SOURCE_SLOT, JSPROP_PERMANENT | JSPROP_READONLY) ||
+        !addDataProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.globalAtom),
+                         GLOBAL_FLAG_SLOT, JSPROP_PERMANENT | JSPROP_READONLY) ||
+        !addDataProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.ignoreCaseAtom),
+                         IGNORE_CASE_FLAG_SLOT, JSPROP_PERMANENT | JSPROP_READONLY) ||
+        !addDataProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.multilineAtom),
+                         MULTILINE_FLAG_SLOT, JSPROP_PERMANENT | JSPROP_READONLY))
     {
         return NULL;
     }
 
-    return self->addDataProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.stickyAtom),
-                                 STICKY_FLAG_SLOT, JSPROP_PERMANENT | JSPROP_READONLY);
+    return addDataProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.stickyAtom),
+                           STICKY_FLAG_SLOT, JSPROP_PERMANENT | JSPROP_READONLY);
 }
 
 inline bool
-RegExpObject::init(JSContext *cx, HandleAtom source, RegExpFlag flags)
+RegExpObject::init(JSContext *cx, JSAtom *source, RegExpFlag flags)
 {
-    RootedVar<RegExpObject *> self(cx, this);
-
     if (nativeEmpty()) {
         if (isDelegate()) {
             if (!assignInitialShape(cx))
                 return false;
         } else {
             Shape *shape = assignInitialShape(cx);
             if (!shape)
                 return false;
-            EmptyShape::insertInitialShape(cx, shape, self->getProto());
+            EmptyShape::insertInitialShape(cx, shape, getProto());
         }
-        JS_ASSERT(!self->nativeEmpty());
+        JS_ASSERT(!nativeEmpty());
     }
 
     DebugOnly<JSAtomState *> atomState = &cx->runtime->atomState;
-    JS_ASSERT(self->nativeLookupNoAllocation(cx, ATOM_TO_JSID(atomState->lastIndexAtom))->slot() ==
-              LAST_INDEX_SLOT);
-    JS_ASSERT(self->nativeLookupNoAllocation(cx, ATOM_TO_JSID(atomState->sourceAtom))->slot() ==
-              SOURCE_SLOT);
-    JS_ASSERT(self->nativeLookupNoAllocation(cx, ATOM_TO_JSID(atomState->globalAtom))->slot() ==
-              GLOBAL_FLAG_SLOT);
-    JS_ASSERT(self->nativeLookupNoAllocation(cx, ATOM_TO_JSID(atomState->ignoreCaseAtom))->slot() ==
-              IGNORE_CASE_FLAG_SLOT);
-    JS_ASSERT(self->nativeLookupNoAllocation(cx, ATOM_TO_JSID(atomState->multilineAtom))->slot() ==
-              MULTILINE_FLAG_SLOT);
-    JS_ASSERT(self->nativeLookupNoAllocation(cx, ATOM_TO_JSID(atomState->stickyAtom))->slot() ==
-              STICKY_FLAG_SLOT);
+    JS_ASSERT(nativeLookup(cx, ATOM_TO_JSID(atomState->lastIndexAtom))->slot() == LAST_INDEX_SLOT);
+    JS_ASSERT(nativeLookup(cx, ATOM_TO_JSID(atomState->sourceAtom))->slot() == SOURCE_SLOT);
+    JS_ASSERT(nativeLookup(cx, ATOM_TO_JSID(atomState->globalAtom))->slot() == GLOBAL_FLAG_SLOT);
+    JS_ASSERT(nativeLookup(cx, ATOM_TO_JSID(atomState->ignoreCaseAtom))->slot() ==
+                                 IGNORE_CASE_FLAG_SLOT);
+    JS_ASSERT(nativeLookup(cx, ATOM_TO_JSID(atomState->multilineAtom))->slot() ==
+                                 MULTILINE_FLAG_SLOT);
+    JS_ASSERT(nativeLookup(cx, ATOM_TO_JSID(atomState->stickyAtom))->slot() == STICKY_FLAG_SLOT);
 
     /*
      * If this is a re-initialization with an existing RegExpShared, 'flags'
      * may not match getShared()->flags, so forget the RegExpShared.
      */
-    self->JSObject::setPrivate(NULL);
+    JSObject::setPrivate(NULL);
 
-    self->zeroLastIndex();
-    self->setSource(source);
-    self->setGlobal(flags & GlobalFlag);
-    self->setIgnoreCase(flags & IgnoreCaseFlag);
-    self->setMultiline(flags & MultilineFlag);
-    self->setSticky(flags & StickyFlag);
+    zeroLastIndex();
+    setSource(source);
+    setGlobal(flags & GlobalFlag);
+    setIgnoreCase(flags & IgnoreCaseFlag);
+    setMultiline(flags & MultilineFlag);
+    setSticky(flags & StickyFlag);
     return true;
 }
 
 RegExpRunStatus
 RegExpObject::execute(JSContext *cx, const jschar *chars, size_t length, size_t *lastIndex,
                       MatchPairs **output)
 {
     RegExpGuard g;
@@ -710,18 +702,17 @@ RegExpCompartment::get(JSContext *cx, JS
 
 JSObject *
 js::CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *proto)
 {
     JS_ASSERT(obj->isRegExp());
     JS_ASSERT(proto->isRegExp());
 
     RegExpObjectBuilder builder(cx);
-    return builder.clone(RootedVar<RegExpObject*>(cx, &obj->asRegExp()),
-                         RootedVar<RegExpObject*>(cx, &proto->asRegExp()));
+    return builder.clone(&obj->asRegExp(), &proto->asRegExp());
 }
 
 bool
 js::ParseRegExpFlags(JSContext *cx, JSString *flagStr, RegExpFlag *flagsOut)
 {
     size_t n = flagStr->length();
     const jschar *s = flagStr->getChars(cx);
     if (!s)
@@ -755,26 +746,26 @@ js::ParseRegExpFlags(JSContext *cx, JSSt
     }
     return true;
 }
 
 template<XDRMode mode>
 bool
 js::XDRScriptRegExpObject(XDRState<mode> *xdr, HeapPtrObject *objp)
 {
-    RootedVarAtom source(xdr->cx());
+    JSAtom *source = 0;
     uint32_t flagsword = 0;
 
     if (mode == XDR_ENCODE) {
         JS_ASSERT(objp);
         RegExpObject &reobj = (*objp)->asRegExp();
         source = reobj.getSource();
         flagsword = reobj.getFlags();
     }
-    if (!XDRAtom(xdr, source.address()) || !xdr->codeUint32(&flagsword))
+    if (!XDRAtom(xdr, &source) || !xdr->codeUint32(&flagsword))
         return false;
     if (mode == XDR_DECODE) {
         RegExpFlag flags = RegExpFlag(flagsword);
         RegExpObject *reobj = RegExpObject::createNoStatics(xdr->cx(), source, flags, NULL);
         if (!reobj)
             return false;
 
         if (!reobj->clearParent(xdr->cx()))
--- a/js/src/vm/RegExpObject.h