Add various autorooting, bug 772303. r=terrence
authorBrian Hackett <bhackett1024@gmail.com>
Sun, 12 Aug 2012 19:50:49 -0600
changeset 102173 454e12a2460fdead7805cf496e33ec93ca9148d8
parent 102172 ee73e7a89076deb0d85b9b52d6b19411e1091e5f
child 102174 d093de44e8509a4ae394665e29af06b16fade56b
push id13347
push userbhackett@mozilla.com
push dateMon, 13 Aug 2012 01:52:27 +0000
treeherdermozilla-inbound@454e12a2460f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs772303
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Add various autorooting, bug 772303. r=terrence
js/src/builtin/Eval.cpp
js/src/builtin/MapObject.cpp
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/jit-test/tests/sunspider/check-crypto-md5.js
js/src/jit-test/tests/sunspider/check-crypto-sha1.js
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsatom.cpp
js/src/jsbool.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jsdate.cpp
js/src/jsexn.cpp
js/src/jsfun.cpp
js/src/jsinterp.cpp
js/src/jsinterpinlines.h
js/src/jsiter.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/json.cpp
js/src/jsopcode.cpp
js/src/jsopcode.h
js/src/jsproxy.cpp
js/src/jsreflect.cpp
js/src/jsstr.cpp
js/src/jsstrinlines.h
js/src/jstypedarray.cpp
js/src/jsxml.cpp
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/MonoIC.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/shell/js.cpp
js/src/vm/Debugger.cpp
js/src/vm/ObjectImpl.cpp
js/src/vm/ScopeObject.cpp
--- a/js/src/builtin/Eval.cpp
+++ b/js/src/builtin/Eval.cpp
@@ -81,35 +81,39 @@ class EvalScriptGuard
 {
     JSContext *cx_;
     Rooted<JSScript*> script_;
 
     /* These fields are only valid if lookup_.str is non-NULL. */
     EvalCacheLookup lookup_;
     EvalCache::AddPtr p_;
 
+    Rooted<JSLinearString*> lookupStr_;
+
   public:
     EvalScriptGuard(JSContext *cx)
-      : cx_(cx), script_(cx)
+      : cx_(cx), script_(cx), lookupStr_(cx)
     {
         lookup_.str = NULL;
     }
 
     ~EvalScriptGuard() {
         if (script_) {
             CallDestroyScriptHook(cx_->runtime->defaultFreeOp(), script_);
             script_->isActiveEval = false;
             script_->isCachedEval = true;
+            lookup_.str = lookupStr_;
             if (lookup_.str && IsEvalCacheCandidate(script_))
                 cx_->runtime->evalCache.relookupOrAdd(p_, lookup_, script_);
         }
     }
 
     void lookupInEvalCache(JSLinearString *str, JSFunction *caller, unsigned staticLevel)
     {
+        lookupStr_ = str;
         lookup_.str = str;
         lookup_.caller = caller;
         lookup_.staticLevel = staticLevel;
         lookup_.version = cx_->findVersion();
         lookup_.compartment = cx_->compartment;
         p_ = cx_->runtime->evalCache.lookupForAdd(lookup_);
         if (p_) {
             script_ = *p_;
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -818,16 +818,18 @@ MapIteratorObject::next_impl(JSContext *
         return js_ThrowStopIteration(cx);
     if (range->empty()) {
         cx->delete_(range);
         thisobj.setReservedSlot(RangeSlot, PrivateValue(NULL));
         return js_ThrowStopIteration(cx);
     }
 
     Value pair[2] = { range->front().key.get(), range->front().value };
+    AutoValueArray root(cx, pair, 2);
+
     JSObject *pairobj = NewDenseCopiedArray(cx, 2, pair);
     if (!pairobj)
         return false;
     range->popFront();
     args.rval().setObject(*pairobj);
     return true;
 }
 
@@ -965,17 +967,17 @@ MapObject::construct(JSContext *cx, unsi
         return false;
     }
     obj->setPrivate(map);
 
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.hasDefined(0)) {
         ForOfIterator iter(cx, args[0]);
         while (iter.next()) {
-            JSObject *pairobj = js_ValueToNonNullObject(cx, iter.value());
+            RootedObject pairobj(cx, js_ValueToNonNullObject(cx, iter.value()));
             if (!pairobj)
                 return false;
 
             RootedValue key(cx);
             if (!pairobj->getElement(cx, 0, &key))
                 return false;
             HashableValue hkey;
             if (!hkey.setValue(cx, key))
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -298,18 +298,20 @@ frontend::CompileFunctionBody(JSContext 
         /*
          * NB: do not use AutoLocalNameArray because it will release space
          * allocated from cx->tempLifoAlloc by DefineArg.
          */
         BindingVector names(cx);
         if (!GetOrderedBindings(cx, funsc.bindings, &names))
             return false;
 
+        RootedPropertyName name(cx);
         for (unsigned i = 0; i < nargs; i++) {
-            if (!DefineArg(fn, names[i].maybeName, i, &parser))
+            name = names[i].maybeName;
+            if (!DefineArg(fn, name, i, &parser))
                 return false;
         }
     }
 
     /*
      * After we're done parsing, we must fold constants, analyze any nested
      * functions, and generate code for this function, including a stop opcode
      * at the end.
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -464,17 +464,17 @@ CheckStrictAssignment(JSContext *cx, Par
 
 /*
  * Check that it is permitted to introduce a binding for atom.  Strict mode
  * forbids introducing new definitions for 'eval', 'arguments', or for any
  * strict mode reserved keyword.  Use pn for reporting error locations, or use
  * tc's token stream if pn is NULL.
  */
 bool
-CheckStrictBinding(JSContext *cx, Parser *parser, PropertyName *name, ParseNode *pn)
+CheckStrictBinding(JSContext *cx, Parser *parser, HandlePropertyName name, ParseNode *pn)
 {
     if (!parser->tc->sc->needStrictChecks())
         return true;
 
     JSAtomState *atomState = &cx->runtime->atomState;
     if (name == atomState->evalAtom ||
         name == atomState->argumentsAtom ||
         FindKeyword(name->charsZ(), name->length()))
@@ -484,17 +484,17 @@ CheckStrictBinding(JSContext *cx, Parser
             return false;
         return parser->reportStrictModeError(pn, JSMSG_BAD_BINDING, bytes.ptr());
     }
 
     return true;
 }
 
 static bool
-ReportBadParameter(JSContext *cx, Parser *parser, JSAtom *name, unsigned errorNumber)
+ReportBadParameter(JSContext *cx, Parser *parser, HandlePropertyName name, unsigned errorNumber)
 {
     Definition *dn = parser->tc->decls.lookupFirst(name);
     JSAutoByteString bytes;
     return js_AtomToPrintableString(cx, name, &bytes) &&
            parser->reportStrictModeError(dn, errorNumber, bytes.ptr());
 }
 
 static bool
@@ -873,23 +873,23 @@ MakeDefIntoUse(Definition *dn, ParseNode
 /*
  * Parameter block types for the several Binder functions.  We use a common
  * helper function signature in order to share code among destructuring and
  * simple variable declaration parsers.  In the destructuring case, the binder
  * function is called indirectly from the variable declaration parser by way
  * of CheckDestructuring and its friends.
  */
 typedef bool
-(*Binder)(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser);
+(*Binder)(JSContext *cx, BindData *data, HandlePropertyName name, Parser *parser);
 
 static bool
-BindLet(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser);
+BindLet(JSContext *cx, BindData *data, HandlePropertyName name, Parser *parser);
 
 static bool
-BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser);
+BindVarOrConst(JSContext *cx, BindData *data, HandlePropertyName name, Parser *parser);
 
 struct frontend::BindData {
     BindData(JSContext *cx) : let(cx) {}
 
     ParseNode       *pn;        /* name node for definition processing and
                                    error source coordinates */
     JSOp            op;         /* prolog bytecode or nop */
     Binder          binder;     /* binder, discriminates u */
@@ -1134,17 +1134,17 @@ LeaveFunction(ParseNode *fn, Parser *par
     return true;
 }
 
 /*
  * DefineArg is called for both the formals of a regular function definition
  * and the formals specified by the Function constructor.
  */
 bool
-frontend::DefineArg(ParseNode *pn, PropertyName *name, unsigned i, Parser *parser)
+frontend::DefineArg(ParseNode *pn, HandlePropertyName name, unsigned i, Parser *parser)
 {
     JSContext *cx = parser->context;
     TreeContext *tc = parser->tc;
     SharedContext *sc = tc->sc;
 
     /*
      * Make an argument definition node, distinguished by being in
      * parser->tc->decls but having PNK_NAME kind and JSOP_NOP op. Insert it in
@@ -1174,33 +1174,33 @@ frontend::DefineArg(ParseNode *pn, Prope
     if (!argpn->pn_cookie.set(cx, tc->staticLevel, i))
         return false;
     argpn->pn_dflags |= PND_BOUND;
     return true;
 }
 
 #if JS_HAS_DESTRUCTURING
 static bool
-BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser)
+BindDestructuringArg(JSContext *cx, BindData *data, HandlePropertyName name, Parser *parser)
 {
     TreeContext *tc = parser->tc;
     JS_ASSERT(tc->sc->inFunction());
 
     /*
      * NB: Check tc->decls rather than tc->sc->bindings, because destructuring
      *     bindings aren't added to tc->sc->bindings until after all arguments have
      *     been parsed.
      */
-    if (tc->decls.lookupFirst(atom)) {
+    if (tc->decls.lookupFirst(name)) {
         parser->reportError(NULL, JSMSG_DESTRUCT_DUP_ARG);
         return false;
     }
 
     ParseNode *pn = data->pn;
-    if (!CheckStrictBinding(cx, parser, atom->asPropertyName(), pn))
+    if (!CheckStrictBinding(cx, parser, name, pn))
         return false;
 
     /*
      * Distinguish destructured-to binding nodes as vars, not args, by setting
      * pn_op to JSOP_SETLOCAL. Parser::functionDef checks for this pn_op value
      * when processing the destructuring-assignment AST prelude induced by such
      * destructuring args in Parser::functionArguments.
      *
@@ -1215,17 +1215,17 @@ BindDestructuringArg(JSContext *cx, Bind
      * destructured, and zero or more VARs (as in named local variables) for
      * the destructured-to identifiers in the property value positions within
      * the object or array destructuring pattern, and all ARGs for the formal
      * parameter list bound as locals before any VAR for a destructured name.
      */
     pn->setOp(JSOP_SETLOCAL);
     pn->pn_dflags |= PND_BOUND;
 
-    return Define(pn, atom, tc);
+    return Define(pn, name, tc);
 }
 #endif /* JS_HAS_DESTRUCTURING */
 
 bool
 Parser::functionArguments(ParseNode **listp, bool &hasRest)
 {
     if (tokenStream.getToken() != TOK_LP) {
         reportError(NULL, JSMSG_PAREN_BEFORE_FORMAL);
@@ -2015,40 +2015,40 @@ ReportRedeclaration(JSContext *cx, Parse
  * must already be in such a scope.
  *
  * Throw a SyntaxError if 'atom' is an invalid name. Otherwise create a
  * property for the new variable on the block object, tc->blockChain;
  * populate data->pn->pn_{op,cookie,defn,dflags}; and stash a pointer to
  * data->pn in a slot of the block object.
  */
 static bool
-BindLet(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser)
+BindLet(JSContext *cx, BindData *data, HandlePropertyName name, Parser *parser)
 {
     TreeContext *tc = parser->tc;
     ParseNode *pn = data->pn;
-    if (!CheckStrictBinding(cx, parser, atom->asPropertyName(), pn))
+    if (!CheckStrictBinding(cx, parser, name, pn))
         return false;
 
     Rooted<StaticBlockObject *> blockObj(cx, data->let.blockObj);
     unsigned blockCount = blockObj->slotCount();
     if (blockCount == JS_BIT(16)) {
         parser->reportError(pn, data->let.overflow);
         return false;
     }
 
     /*
      * For bindings that are hoisted to the beginning of the block/function,
      * Define() right now. For the rest, delay Define() until PushLetScope.
      */
     if (data->let.varContext == HoistVars) {
         JS_ASSERT(!tc->atBodyLevel());
-        Definition *dn = tc->decls.lookupFirst(atom);
+        Definition *dn = tc->decls.lookupFirst(name);
         if (dn && dn->pn_blockid == tc->blockid())
-            return ReportRedeclaration(cx, parser, pn, dn->isConst(), atom);
-        if (!Define(pn, atom, tc, true))
+            return ReportRedeclaration(cx, parser, pn, dn->isConst(), name);
+        if (!Define(pn, name, tc, true))
             return false;
     }
 
     /*
      * Assign block-local index to pn->pn_cookie right away, encoding it as an
      * upvar cookie whose skip tells the current static level. The emitter will
      * adjust the node's slot based on its stack depth model -- and, for global
      * and eval code, js::frontend::CompileScript will adjust the slot
@@ -2059,21 +2059,21 @@ BindLet(JSContext *cx, BindData *data, J
         return false;
     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;
-    RootedId id(cx, AtomToId(atom));
+    RootedId id(cx, NameToId(name));
     Shape *shape = StaticBlockObject::addVar(cx, blockObj, id, blockCount, &redeclared);
     if (!shape) {
         if (redeclared)
-            ReportRedeclaration(cx, parser, pn, false, atom);
+            ReportRedeclaration(cx, parser, pn, false, name);
         return false;
     }
 
     /* Store pn in the static block object. */
     blockObj->setDefinitionParseNode(blockCount, reinterpret_cast<Definition *>(pn));
     return true;
 }
 
@@ -2158,42 +2158,40 @@ BindFunctionLocal(JSContext *cx, BindDat
     } else {
         JS_ASSERT(bi->kind == VARIABLE || bi->kind == CONSTANT);
     }
 
     return true;
 }
 
 static bool
-BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom_, Parser *parser)
+BindVarOrConst(JSContext *cx, BindData *data, HandlePropertyName name, Parser *parser)
 {
-    RootedAtom atom(cx, atom_);
-
     TreeContext *tc = parser->tc;
     ParseNode *pn = data->pn;
 
     /* Default best op for pn is JSOP_NAME; we'll try to improve below. */
     pn->setOp(JSOP_NAME);
 
-    if (!CheckStrictBinding(cx, parser, atom->asPropertyName(), pn))
+    if (!CheckStrictBinding(cx, parser, name, pn))
         return false;
 
-    StmtInfoTC *stmt = LexicalLookup(tc, atom, NULL, (StmtInfoTC *)NULL);
+    StmtInfoTC *stmt = LexicalLookup(tc, name, NULL, (StmtInfoTC *)NULL);
 
     if (stmt && stmt->type == STMT_WITH) {
         pn->pn_dflags |= PND_DEOPTIMIZED;
         tc->sc->setFunMightAliasLocals();
         return true;
     }
 
-    DefinitionList::Range defs = tc->decls.lookupMulti(atom);
+    DefinitionList::Range defs = tc->decls.lookupMulti(name);
     JS_ASSERT_IF(stmt, !defs.empty());
 
     if (defs.empty()) {
-        if (!Define(pn, atom, tc))
+        if (!Define(pn, name, tc))
             return false;
 
         if (data->op == JSOP_DEFCONST)
             pn->pn_dflags |= PND_CONST;
 
         if (tc->sc->inFunction())
             return BindFunctionLocal(cx, data, defs, tc);
 
@@ -2205,42 +2203,42 @@ BindVarOrConst(JSContext *cx, BindData *
      * disallows several forms of redeclaration. Critically,
      *   let (x) { var x; } // error
      * is not allowed which allows us to turn any non-error redeclaration
      * into a use of the initial declaration.
      */
     Definition *dn = defs.front();
     Definition::Kind dn_kind = dn->kind();
     if (dn_kind == Definition::ARG) {
-        JSAutoByteString name;
-        if (!js_AtomToPrintableString(cx, atom, &name))
+        JSAutoByteString bytes;
+        if (!js_AtomToPrintableString(cx, name, &bytes))
             return false;
 
         if (data->op == JSOP_DEFCONST) {
-            parser->reportError(pn, JSMSG_REDECLARED_PARAM, name.ptr());
+            parser->reportError(pn, JSMSG_REDECLARED_PARAM, bytes.ptr());
             return false;
         }
-        if (!parser->reportStrictWarning(pn, JSMSG_VAR_HIDES_ARG, name.ptr()))
+        if (!parser->reportStrictWarning(pn, JSMSG_VAR_HIDES_ARG, bytes.ptr()))
             return false;
     } else {
         bool error = (data->op == JSOP_DEFCONST ||
                       dn_kind == Definition::CONST ||
                       (dn_kind == Definition::LET &&
-                       (stmt->type != STMT_CATCH || OuterLet(tc, stmt, atom))));
+                       (stmt->type != STMT_CATCH || OuterLet(tc, stmt, name))));
 
         if (cx->hasStrictOption()
             ? data->op != JSOP_DEFVAR || dn_kind != Definition::VAR
             : error)
         {
-            JSAutoByteString name;
+            JSAutoByteString bytes;
             Parser::Reporter reporter =
                 error ? &Parser::reportError : &Parser::reportStrictWarning;
-            if (!js_AtomToPrintableString(cx, atom, &name) ||
+            if (!js_AtomToPrintableString(cx, name, &bytes) ||
                 !(parser->*reporter)(pn, JSMSG_REDECLARED_VAR,
-                                     Definition::kindString(dn_kind), name.ptr()))
+                                     Definition::kindString(dn_kind), bytes.ptr()))
             {
                 return false;
             }
         }
     }
 
     LinkUseToDef(pn, dn);
     return true;
@@ -2324,18 +2322,20 @@ NoteNameUse(ParseNode *pn, Parser *parse
 
 #if JS_HAS_DESTRUCTURING
 
 static bool
 BindDestructuringVar(JSContext *cx, BindData *data, ParseNode *pn, Parser *parser)
 {
     JS_ASSERT(pn->isKind(PNK_NAME));
 
+    RootedPropertyName name(cx, pn->pn_atom->asPropertyName());
+
     data->pn = pn;
-    if (!data->binder(cx, data, pn->pn_atom, parser))
+    if (!data->binder(cx, data, name, parser))
         return false;
 
     /*
      * Select the appropriate name-setting opcode, respecting eager selection
      * done by the data->binder function.
      */
     if (pn->pn_dflags & PND_BOUND)
         pn->setOp(JSOP_SETLOCAL);
@@ -3432,17 +3432,17 @@ Parser::tryStatement()
                 pn3 = destructuringExpr(&data, tt);
                 if (!pn3)
                     return NULL;
                 break;
 #endif
 
               case TOK_NAME:
               {
-                JSAtom *label = tokenStream.currentToken().name();
+                RootedPropertyName label(context, tokenStream.currentToken().name());
                 pn3 = NewBindingNode(label, this);
                 if (!pn3)
                     return NULL;
                 data.pn = pn3;
                 if (!data.binder(context, &data, label, this))
                     return NULL;
                 break;
               }
@@ -4143,17 +4143,17 @@ Parser::variables(ParseNodeKind kind, St
 #endif /* JS_HAS_DESTRUCTURING */
 
         if (tt != TOK_NAME) {
             if (tt != TOK_ERROR)
                 reportError(NULL, JSMSG_NO_VARIABLE_NAME);
             return NULL;
         }
 
-        PropertyName *name = tokenStream.currentToken().name();
+        RootedPropertyName name(context, tokenStream.currentToken().name());
         pn2 = NewBindingNode(name, this, varContext);
         if (!pn2)
             return NULL;
         if (data.op == JSOP_DEFCONST)
             pn2->pn_dflags |= PND_CONST;
         data.pn = pn2;
         if (!data.binder(context, &data, name, this))
             return NULL;
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -322,17 +322,17 @@ Parser::reportStrictModeError(ParseNode 
     va_list args;
     va_start(args, errorNumber);
     bool result = tokenStream.reportStrictModeErrorNumberVA(pn, errorNumber, args);
     va_end(args);
     return result;
 }
 
 bool
-DefineArg(ParseNode *pn, PropertyName *name, unsigned i, Parser *parser);
+DefineArg(ParseNode *pn, HandlePropertyName name, unsigned i, Parser *parser);
 
 } /* namespace frontend */
 } /* namespace js */
 
 /*
  * Convenience macro to access Parser.tokenStream as a pointer.
  */
 #define TS(p) (&(p)->tokenStream)
--- a/js/src/jit-test/tests/sunspider/check-crypto-md5.js
+++ b/js/src/jit-test/tests/sunspider/check-crypto-md5.js
@@ -278,10 +278,15 @@ And, Montague, come you this afternoon,\
 To know our further pleasure in this case,\n\
 To old Free-town, our common judgment-place.\n\
 Once more, on pain of death, all men depart."
 
 for (var i = 0; i <4; i++) {
     plainText += plainText;
 }
 
+// root checks performed during integer conversion operations can poison
+// crypto integers in this test.
+if (relaxRootChecks)
+  relaxRootChecks();
+
 var md5Output = hex_md5(plainText);
 assertEq(md5Output, "a831e91e0f70eddcb70dc61c6f82f6cd")
--- a/js/src/jit-test/tests/sunspider/check-crypto-sha1.js
+++ b/js/src/jit-test/tests/sunspider/check-crypto-sha1.js
@@ -216,10 +216,15 @@ Which, but their children's end, nought 
 Is now the two hours' traffic of our stage;\n\
 The which if you with patient ears attend,\n\
 What here shall miss, our toil shall strive to mend.";
 
 for (var i = 0; i <4; i++) {
     plainText += plainText;
 }
 
+// root checks performed during integer conversion operations can poison
+// crypto integers in this test.
+if (relaxRootChecks)
+  relaxRootChecks();
+
 var sha1Output = hex_sha1(plainText);
 assertEq(sha1Output, "2524d264def74cce2498bf112bedf00e6c0b796d")
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -591,37 +591,39 @@ JS_ValueToInt64(JSContext *cx, jsval v, 
 JS_PUBLIC_API(JSBool)
 JS_ValueToUint64(JSContext *cx, jsval v, uint64_t *ip)
 {
     RootedValue value(cx, v);
     return JS::ToUint64(cx, value, ip);
 }
 
 JS_PUBLIC_API(JSBool)
-JS_ValueToInt32(JSContext *cx, jsval v, int32_t *ip)
-{
-    AssertHeapIsIdle(cx);
-    CHECK_REQUEST(cx);
+JS_ValueToInt32(JSContext *cx, jsval vArg, int32_t *ip)
+{
+    AssertHeapIsIdle(cx);
+    CHECK_REQUEST(cx);
+
+    RootedValue v(cx, vArg);
     assertSameCompartment(cx, v);
 
     if (v.isInt32()) {
         *ip = v.toInt32();
         return true;
     }
 
     double d;
     if (v.isDouble()) {
         d = v.toDouble();
     } else if (!ToNumberSlow(cx, v, &d)) {
         return false;
     }
 
     if (MOZ_DOUBLE_IS_NaN(d) || d <= -2147483649.0 || 2147483648.0 <= d) {
         js_ReportValueError(cx, JSMSG_CANT_CONVERT,
-                            JSDVG_SEARCH_STACK, v, NULL);
+                            JSDVG_SEARCH_STACK, v, NullPtr());
         return false;
     }
 
     *ip = (int32_t) floor(d + 0.5);  /* Round to nearest */
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
@@ -4952,22 +4954,24 @@ JS_BindCallable(JSContext *cx, JSObject 
     RootedObject target(cx, targetArg);
     RootedValue thisArg(cx, ObjectValue(*newThis));
     return js_fun_bind(cx, target, thisArg, NULL, 0);
 }
 
 JSBool
 js_generic_native_method_dispatcher(JSContext *cx, unsigned argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     JSFunctionSpec *fs = (JSFunctionSpec *)
         vp->toObject().toFunction()->getExtendedSlot(0).toPrivate();
     JS_ASSERT((fs->flags & JSFUN_GENERIC_NATIVE) != 0);
 
     if (argc < 1) {
-        js_ReportMissingArg(cx, *vp, 0);
+        js_ReportMissingArg(cx, args.calleev(), 0);
         return JS_FALSE;
     }
 
     /*
      * Copy all actual (argc) arguments down over our |this| parameter, vp[1],
      * which is almost always the class constructor object, e.g. Array.  Then
      * call the corresponding prototype native method with our first argument
      * passed as |this|.
@@ -5913,18 +5917,18 @@ JS_New(JSContext *cx, JSObject *ctorArg,
     // This is not a simple variation of JS_CallFunctionValue because JSOP_NEW
     // is not a simple variation of JSOP_CALL. We have to determine what class
     // of object to create, create it, and clamp the return value to an object,
     // among other details. InvokeConstructor does the hard work.
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, argc, &args))
         return NULL;
 
-    args.calleev().setObject(*ctor);
-    args.thisv().setNull();
+    args.setCallee(ObjectValue(*ctor));
+    args.setThis(NullValue());
     PodCopy(args.array(), argv, argc);
 
     if (!InvokeConstructor(cx, args))
         return NULL;
 
     if (!args.rval().isObject()) {
         /*
          * Although constructors may return primitives (via proxies), this
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1048,25 +1048,26 @@ class JS_PUBLIC_API(AutoGCRooter) {
         XML =          -9, /* js::AutoXMLRooter */
         OBJECT =      -10, /* js::AutoObjectRooter */
         ID =          -11, /* js::AutoIdRooter */
         VALVECTOR =   -12, /* js::AutoValueVector */
         DESCRIPTOR =  -13, /* js::AutoPropertyDescriptorRooter */
         STRING =      -14, /* js::AutoStringRooter */
         IDVECTOR =    -15, /* js::AutoIdVector */
         OBJVECTOR =   -16, /* js::AutoObjectVector */
-        SCRIPTVECTOR =-17, /* js::AutoScriptVector */
-        PROPDESC =    -18, /* js::PropDesc::AutoRooter */
-        SHAPERANGE =  -19, /* js::Shape::Range::AutoRooter */
-        STACKSHAPE =  -20, /* js::StackShape::AutoRooter */
-        STACKBASESHAPE=-21,/* js::StackBaseShape::AutoRooter */
-        BINDINGS =    -22, /* js::Bindings::AutoRooter */
-        GETTERSETTER =-23, /* js::AutoRooterGetterSetter */
-        REGEXPSTATICS=-24, /* js::RegExpStatics::AutoRooter */
-        HASHABLEVALUE=-25
+        STRINGVECTOR =-17, /* js::AutoStringVector */
+        SCRIPTVECTOR =-18, /* js::AutoScriptVector */
+        PROPDESC =    -19, /* js::PropDesc::AutoRooter */
+        SHAPERANGE =  -20, /* js::Shape::Range::AutoRooter */
+        STACKSHAPE =  -21, /* js::StackShape::AutoRooter */
+        STACKBASESHAPE=-22,/* js::StackBaseShape::AutoRooter */
+        BINDINGS =    -23, /* js::Bindings::AutoRooter */
+        GETTERSETTER =-24, /* js::AutoRooterGetterSetter */
+        REGEXPSTATICS=-25, /* js::RegExpStatics::AutoRooter */
+        HASHABLEVALUE=-26
     };
 
   private:
     AutoGCRooter ** const stackTop;
 
     /* No copy or assignment semantics. */
     AutoGCRooter(AutoGCRooter &ida) MOZ_DELETE;
     void operator=(AutoGCRooter &ida) MOZ_DELETE;
@@ -1250,16 +1251,17 @@ class AutoVectorRooter : protected AutoG
     explicit AutoVectorRooter(JSContext *cx, ptrdiff_t tag
                               JS_GUARD_OBJECT_NOTIFIER_PARAM)
       : AutoGCRooter(cx, tag), vector(cx), vectorRoot(cx, &vector)
     {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     size_t length() const { return vector.length(); }
+    bool empty() const { return vector.empty(); }
 
     bool append(const T &v) { return vector.append(v); }
     bool append(const AutoVectorRooter<T> &other) {
         return vector.append(other.vector);
     }
 
     /* For use when space has already been reserved. */
     void infallibleAppend(const T &v) { vector.infallibleAppend(v); }
@@ -1376,32 +1378,43 @@ class CallReceiver
     void clearUsedRval() const {}
 #endif
     Value *argv_;
   public:
     friend CallReceiver CallReceiverFromVp(Value *);
     friend CallReceiver CallReceiverFromArgv(Value *);
     Value *base() const { return argv_ - 2; }
     JSObject &callee() const { JS_ASSERT(!usedRval_); return argv_[-2].toObject(); }
-    Value &calleev() const { JS_ASSERT(!usedRval_); return argv_[-2]; }
-    Value &thisv() const { return argv_[-1]; }
+
+    JS::HandleValue calleev() const {
+        JS_ASSERT(!usedRval_);
+        return JS::HandleValue::fromMarkedLocation(&argv_[-2]);
+    }
+
+    JS::HandleValue thisv() const {
+        return JS::HandleValue::fromMarkedLocation(&argv_[-1]);
+    }
 
     JS::MutableHandleValue rval() const {
         setUsedRval();
         return JS::MutableHandleValue::fromMarkedLocation(&argv_[-2]);
     }
 
     Value *spAfterCall() const {
         setUsedRval();
         return argv_ - 1;
     }
 
-    void setCallee(Value calleev) {
+    void setCallee(Value calleev) const {
         clearUsedRval();
-        this->calleev() = calleev;
+        argv_[-2] = calleev;
+    }
+
+    void setThis(Value thisv) const {
+        argv_[-1] = thisv;
     }
 };
 
 JS_ALWAYS_INLINE CallReceiver
 CallReceiverFromArgv(Value *argv)
 {
     CallReceiver receiver;
     receiver.clearUsedRval();
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1530,17 +1530,17 @@ class AutoArrayCycleDetector
 static bool
 array_join_sub(JSContext *cx, CallArgs &args, bool locale)
 {
     // This method is shared by Array.prototype.join and
     // Array.prototype.toLocaleString. The steps in ES5 are nearly the same, so
     // the annotations in this function apply to both toLocaleString and join.
 
     // Step 1
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     AutoArrayCycleDetector detector(cx, obj);
     if (!detector.init())
         return false;
 
     if (detector.foundCycle()) {
@@ -1618,17 +1618,17 @@ array_join_sub(JSContext *cx, CallArgs &
                 return false;
 
             JSBool hole;
             if (!GetElement(cx, obj, index, &hole, &elt))
                 return false;
 
             if (!hole && !elt.isNullOrUndefined()) {
                 if (locale) {
-                    JSObject *robj = ToObject(cx, elt.address());
+                    JSObject *robj = ToObject(cx, elt);
                     if (!robj)
                         return false;
                     RootedId id(cx, NameToId(cx->runtime->atomState.toLocaleStringAtom));
                     if (!robj->callMethod(cx, id, 0, NULL, &elt))
                         return false;
                 }
                 if (!ValueToStringBuffer(cx, elt, sb))
                     return false;
@@ -1652,17 +1652,17 @@ array_join_sub(JSContext *cx, CallArgs &
 
 /* 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);
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     RootedValue join(cx, args.calleev());
     if (!obj->getProperty(cx, cx->runtime->atomState.joinAtom, &join))
         return false;
 
     if (!js_IsCallable(join)) {
@@ -1672,18 +1672,18 @@ array_toString(JSContext *cx, unsigned a
         args.rval().setString(str);
         return true;
     }
 
     InvokeArgsGuard ag;
     if (!cx->stack.pushInvokeArgs(cx, 0, &ag))
         return false;
 
-    ag.calleev() = join;
-    ag.thisv().setObject(*obj);
+    ag.setCallee(join);
+    ag.setThis(ObjectValue(*obj));
 
     /* Do the call. */
     if (!Invoke(cx, ag))
         return false;
     args.rval().set(ag.rval());
     return true;
 }
 
@@ -1803,17 +1803,17 @@ InitArrayElements(JSContext *cx, HandleO
 
     return true;
 }
 
 static JSBool
 array_reverse(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     uint32_t len;
     if (!js_GetLengthProperty(cx, obj, &len))
         return false;
 
     do {
@@ -2073,17 +2073,17 @@ SortComparatorFunction::operator()(const
 
     if (!JS_CHECK_OPERATION_LIMIT(cx))
         return false;
 
     if (!ag.pushed() && !cx->stack.pushInvokeArgs(cx, 2, &ag))
         return false;
 
     ag.setCallee(fval);
-    ag.thisv() = UndefinedValue();
+    ag.setThis(UndefinedValue());
     ag[0] = a;
     ag[1] = b;
 
     if (!Invoke(cx, ag))
         return false;
 
     double cmp;
     if (!ToNumber(cx, ag.rval(), &cmp))
@@ -2113,17 +2113,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();
     }
 
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, 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);
@@ -2353,17 +2353,17 @@ js_NewbornArrayPush(JSContext *cx, Handl
 {
     return NewbornArrayPushImpl(cx, obj, vp);
 }
 
 JSBool
 js::array_push(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, 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);
@@ -2428,17 +2428,17 @@ array_pop_dense(JSContext *cx, HandleObj
 
     return js_SetLengthProperty(cx, obj, index);
 }
 
 JSBool
 js::array_pop(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, 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
@@ -2457,17 +2457,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);
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return JS_FALSE;
 
     uint32_t length;
     if (!js_GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
 
     if (length == 0) {
@@ -2509,17 +2509,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);
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     uint32_t length;
     if (!js_GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
 
     double newlen = length;
@@ -2631,17 +2631,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. */
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Steps 3-4. */
     uint32_t len;
     if (!js_GetLengthProperty(cx, obj, &len))
         return false;
 
@@ -2850,45 +2850,47 @@ mjit::stubs::ArrayConcatTwoArrays(VMFram
 #endif /* JS_METHODJIT */
 
 /*
  * Python-esque sequence operations.
  */
 JSBool
 js::array_concat(JSContext *cx, unsigned argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     /* Treat our |this| object as the first argument; see ECMA 15.4.4.4. */
-    Value *p = JS_ARGV(cx, vp) - 1;
+    Value *p = args.array() - 1;
 
     /* Create a new Array object and root it using *vp. */
-    RootedObject aobj(cx, ToObject(cx, &vp[1]));
+    RootedObject aobj(cx, ToObject(cx, args.thisv()));
     if (!aobj)
         return false;
 
     RootedObject nobj(cx);
     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;
         TryReuseArrayType(aobj, nobj);
         nobj->setArrayLength(cx, length);
-        vp->setObject(*nobj);
+        args.rval().setObject(*nobj);
         if (argc == 0)
             return JS_TRUE;
         argc--;
         p++;
     } else {
         nobj = NewDenseEmptyArray(cx);
         if (!nobj)
             return JS_FALSE;
-        vp->setObject(*nobj);
+        args.rval().setObject(*nobj);
         length = 0;
     }
 
     /* Loop over [0, argc] to concat args into nobj, expanding all Arrays. */
     for (unsigned i = 0; i <= argc; i++) {
         if (!JS_CHECK_OPERATION_LIMIT(cx))
             return false;
         HandleValue v = HandleValue::fromMarkedLocation(&p[i]);
@@ -2927,17 +2929,17 @@ js::array_concat(JSContext *cx, unsigned
 static JSBool
 array_slice(JSContext *cx, unsigned argc, Value *vp)
 {
     uint32_t length, begin, end, slot;
     JSBool hole;
 
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     if (!js_GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
     begin = 0;
     end = length;
 
@@ -3006,23 +3008,22 @@ enum IndexOfKind {
     IndexOf,
     LastIndexOf
 };
 
 static JSBool
 array_indexOfHelper(JSContext *cx, IndexOfKind mode, CallArgs &args)
 {
     uint32_t length, i, stop;
-    Value tosearch;
     int direction;
     JSBool hole;
 
-    RootedValue elt(cx);
-
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedValue tosearch(cx), elt(cx);
+
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
     if (!js_GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
     if (length == 0)
         goto not_found;
 
     if (args.length() <= 1) {
@@ -3134,17 +3135,17 @@ class ArraySomeBehavior
     static Value lateExitValue() { return BooleanValue(false); }
 };
 
 template <class Behavior>
 static inline bool
 array_readonlyCommon(JSContext *cx, CallArgs &args)
 {
     /* Step 1. */
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Step 2-3. */
     uint32_t len;
     if (!js_GetLengthProperty(cx, obj, &len))
         return false;
 
@@ -3175,17 +3176,17 @@ array_readonlyCommon(JSContext *cx, Call
         if (!GetElement(cx, obj, k, &kNotPresent, &kValue))
             return false;
 
         /* Step c.ii-iii. */
         if (!kNotPresent) {
             if (!ag.pushed() && !cx->stack.pushInvokeArgs(cx, 3, &ag))
                 return false;
             ag.setCallee(ObjectValue(*callable));
-            ag.thisv() = thisv;
+            ag.setThis(thisv);
             ag[0] = kValue;
             ag[1] = NumberValue(k);
             ag[2] = ObjectValue(*obj);
             if (!Invoke(cx, ag))
                 return false;
 
             if (Behavior::shouldExit(ag.rval(), args.rval()))
                 return true;
@@ -3226,17 +3227,17 @@ array_forEach(JSContext *cx, unsigned ar
 
 /* ES5 15.4.4.19. */
 static JSBool
 array_map(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Step 2-3. */
     uint32_t len;
     if (!js_GetLengthProperty(cx, obj, &len))
         return false;
 
@@ -3276,17 +3277,17 @@ array_map(JSContext *cx, unsigned argc, 
         if (!GetElement(cx, obj, k, &kNotPresent, &kValue))
             return false;
 
         /* Step c.ii-iii. */
         if (!kNotPresent) {
             if (!ag.pushed() && !cx->stack.pushInvokeArgs(cx, 3, &ag))
                 return false;
             ag.setCallee(ObjectValue(*callable));
-            ag.thisv() = thisv;
+            ag.setThis(thisv);
             ag[0] = kValue;
             ag[1] = NumberValue(k);
             ag[2] = ObjectValue(*obj);
             if (!Invoke(cx, ag))
                 return false;
             kValue = ag.rval();
             if (!SetArrayElement(cx, arr, k, kValue))
                 return false;
@@ -3303,17 +3304,17 @@ array_map(JSContext *cx, unsigned argc, 
 
 /* ES5 15.4.4.20. */
 static JSBool
 array_filter(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Step 2-3. */
     uint32_t len;
     if (!js_GetLengthProperty(cx, obj, &len))
         return false;
 
@@ -3356,17 +3357,17 @@ array_filter(JSContext *cx, unsigned arg
         if (!GetElement(cx, obj, k, &kNotPresent, &kValue))
             return false;
 
         /* Step c.ii-iii. */
         if (!kNotPresent) {
             if (!ag.pushed() && !cx->stack.pushInvokeArgs(cx, 3, &ag))
                 return false;
             ag.setCallee(ObjectValue(*callable));
-            ag.thisv() = thisv;
+            ag.setThis(thisv);
             ag[0] = kValue;
             ag[1] = NumberValue(k);
             ag[2] = ObjectValue(*obj);
             if (!Invoke(cx, ag))
                 return false;
 
             if (ToBoolean(ag.rval())) {
                 if(!SetArrayElement(cx, arr, to, kValue))
@@ -3411,31 +3412,31 @@ class ArrayReduceRightBehavior
     }
 };
 
 template<class Behavior>
 static inline bool
 array_reduceCommon(JSContext *cx, CallArgs &args)
 {
     /* Step 1. */
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Step 2-3. */
     uint32_t len;
     if (!js_GetLengthProperty(cx, obj, &len))
         return false;
 
     /* Step 4. */
     if (args.length() == 0) {
         js_ReportMissingArg(cx, args.calleev(), 0);
         return false;
     }
-    JSObject *callable = ValueToCallable(cx, &args[0]);
+    RootedObject callable(cx, ValueToCallable(cx, &args[0]));
     if (!callable)
         return false;
 
     /* Step 5. */
     if (len == 0 && args.length() < 2) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_EMPTY_ARRAY_REDUCE);
         return false;
     }
@@ -3474,17 +3475,17 @@ array_reduceCommon(JSContext *cx, CallAr
         if (!GetElement(cx, obj, k, &kNotPresent, &kValue))
             return false;
 
         /* Step c.ii. */
         if (!kNotPresent) {
             if (!ag.pushed() && !cx->stack.pushInvokeArgs(cx, 4, &ag))
                 return false;
             ag.setCallee(ObjectValue(*callable));
-            ag.thisv() = UndefinedValue();
+            ag.setThis(UndefinedValue());
             ag[0] = accumulator;
             ag[1] = kValue;
             ag[2] = NumberValue(k);
             ag[3] = ObjectValue(*obj);
             if (!Invoke(cx, ag))
                 return false;
             accumulator = ag.rval();
         }
@@ -3806,19 +3807,19 @@ NewSlowEmptyArray(JSContext *cx)
 #ifdef DEBUG
 JSBool
 js_ArrayInfo(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     JSObject *array;
 
     for (unsigned i = 0; i < args.length(); i++) {
-        Value arg = args[i];
-
-        char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, arg, NULL);
+        RootedValue arg(cx, args[i]);
+
+        char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, arg, NullPtr());
         if (!bytes)
             return JS_FALSE;
         if (arg.isPrimitive() ||
             !(array = arg.toObjectOrNull())->isArray()) {
             fprintf(stderr, "%s: not array\n", bytes);
             cx->free_(bytes);
             continue;
         }
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -293,16 +293,19 @@ AtomizeInline(JSContext *cx, const jscha
     }
 
     SwitchToCompartment sc(cx, cx->runtime->atomsCompartment);
 
     JSFixedString *key;
 
     SkipRoot skip(cx, &chars);
 
+    /* Workaround for hash values in AddPtr being inadvertently poisoned. */
+    SkipRoot skip2(cx, &p);
+
     if (ocb == TakeCharOwnership) {
         key = js_NewString(cx, const_cast<jschar *>(chars), length);
         if (!key)
             return NULL;
         *pchars = NULL; /* Called should not free *pchars. */
     } else {
         JS_ASSERT(ocb == CopyChars);
         key = js_NewStringCopyN(cx, chars, length);
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -200,18 +200,18 @@ ToBooleanSlow(const Value &v)
 }
 
 bool
 BooleanGetPrimitiveValueSlow(JSContext *cx, JSObject &obj, Value *vp)
 {
     InvokeArgsGuard ag;
     if (!cx->stack.pushInvokeArgs(cx, 0, &ag))
         return false;
-    ag.calleev() = cx->compartment->maybeGlobal()->booleanValueOf();
-    ag.thisv().setObject(obj);
+    ag.setCallee(cx->compartment->maybeGlobal()->booleanValueOf());
+    ag.setThis(ObjectValue(obj));
     if (!Invoke(cx, ag))
         return false;
     *vp = ag.rval();
     return true;
 }
 
 }  /* namespace js */
 
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -805,18 +805,18 @@ js_ReportErrorAgain(JSContext *cx, const
 
 void
 js_ReportIsNotDefined(JSContext *cx, const char *name)
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_DEFINED, name);
 }
 
 JSBool
-js_ReportIsNullOrUndefined(JSContext *cx, int spindex, const Value &v,
-                           JSString *fallback)
+js_ReportIsNullOrUndefined(JSContext *cx, int spindex, HandleValue v,
+                           HandleString fallback)
 {
     char *bytes;
     JSBool ok;
 
     bytes = DecompileValueGenerator(cx, spindex, v, fallback);
     if (!bytes)
         return JS_FALSE;
 
@@ -839,21 +839,21 @@ js_ReportIsNullOrUndefined(JSContext *cx
                                           js_null_str, NULL);
     }
 
     cx->free_(bytes);
     return ok;
 }
 
 void
-js_ReportMissingArg(JSContext *cx, const Value &v, unsigned arg)
+js_ReportMissingArg(JSContext *cx, HandleValue v, unsigned arg)
 {
     char argbuf[11];
     char *bytes;
-    JSAtom *atom;
+    RootedAtom atom(cx);
 
     JS_snprintf(argbuf, sizeof argbuf, "%u", arg);
     bytes = NULL;
     if (IsFunctionObject(v)) {
         atom = v.toObject().toFunction()->atom;
         bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK,
                                         v, atom);
         if (!bytes)
@@ -862,17 +862,17 @@ js_ReportMissingArg(JSContext *cx, const
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                          JSMSG_MISSING_FUN_ARG, argbuf,
                          bytes ? bytes : "");
     cx->free_(bytes);
 }
 
 JSBool
 js_ReportValueErrorFlags(JSContext *cx, unsigned flags, const unsigned errorNumber,
-                         int spindex, const Value &v, JSString *fallback,
+                         int spindex, HandleValue v, HandleString fallback,
                          const char *arg1, const char *arg2)
 {
     char *bytes;
     JSBool ok;
 
     JS_ASSERT(js_ErrorFormatString[errorNumber].argCount >= 1);
     JS_ASSERT(js_ErrorFormatString[errorNumber].argCount <= 3);
     bytes = DecompileValueGenerator(cx, spindex, v, fallback);
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1723,30 +1723,30 @@ js_ReportErrorAgain(JSContext *cx, const
 
 extern void
 js_ReportIsNotDefined(JSContext *cx, const char *name);
 
 /*
  * Report an attempt to access the property of a null or undefined value (v).
  */
 extern JSBool
-js_ReportIsNullOrUndefined(JSContext *cx, int spindex, const js::Value &v,
-                           JSString *fallback);
+js_ReportIsNullOrUndefined(JSContext *cx, int spindex, js::HandleValue v,
+                           js::HandleString fallback);
 
 extern void
-js_ReportMissingArg(JSContext *cx, const js::Value &v, unsigned arg);
+js_ReportMissingArg(JSContext *cx, js::HandleValue v, unsigned arg);
 
 /*
  * Report error using js_DecompileValueGenerator(cx, spindex, v, fallback) as
  * the first argument for the error message. If the error message has less
  * then 3 arguments, use null for arg1 or arg2.
  */
 extern JSBool
 js_ReportValueErrorFlags(JSContext *cx, unsigned flags, const unsigned errorNumber,
-                         int spindex, const js::Value &v, JSString *fallback,
+                         int spindex, js::HandleValue v, js::HandleString fallback,
                          const char *arg1, const char *arg2);
 
 #define js_ReportValueError(cx,errorNumber,spindex,v,fallback)                \
     ((void)js_ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber,          \
                                     spindex, v, fallback, NULL, NULL))
 
 #define js_ReportValueError2(cx,errorNumber,spindex,v,fallback,arg1)          \
     ((void)js_ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber,          \
@@ -1883,16 +1883,29 @@ class AutoObjectVector : public AutoVect
         : AutoVectorRooter<JSObject *>(cx, OBJVECTOR)
     {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
+class AutoStringVector : public AutoVectorRooter<JSString *>
+{
+  public:
+    explicit AutoStringVector(JSContext *cx
+                              JS_GUARD_OBJECT_NOTIFIER_PARAM)
+        : AutoVectorRooter<JSString *>(cx, STRINGVECTOR)
+    {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
+    }
+
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
 class AutoShapeVector : public AutoVectorRooter<Shape *>
 {
   public:
     explicit AutoShapeVector(JSContext *cx
                              JS_GUARD_OBJECT_NOTIFIER_PARAM)
         : AutoVectorRooter<Shape *>(cx, SHAPEVECTOR)
     {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -2584,55 +2584,57 @@ date_toISOString(JSContext *cx, unsigned
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod(cx, IsDate, date_toISOString_impl, args);
 }
 
 /* ES5 15.9.5.44. */
 static JSBool
 date_toJSON(JSContext *cx, unsigned argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     /* Step 1. */
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Step 2. */
     Value tv = ObjectValue(*obj);
     if (!ToPrimitive(cx, JSTYPE_NUMBER, &tv))
         return false;
 
     /* Step 3. */
     if (tv.isDouble() && !MOZ_DOUBLE_IS_FINITE(tv.toDouble())) {
-        vp->setNull();
+        args.rval().setNull();
         return true;
     }
 
     /* Step 4. */
     RootedValue toISO(cx);
     if (!obj->getProperty(cx, cx->runtime->atomState.toISOStringAtom, &toISO))
         return false;
 
     /* Step 5. */
     if (!js_IsCallable(toISO)) {
         JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
                                      JSMSG_BAD_TOISOSTRING_PROP);
         return false;
     }
 
     /* Step 6. */
-    InvokeArgsGuard args;
-    if (!cx->stack.pushInvokeArgs(cx, 0, &args))
+    InvokeArgsGuard ag;
+    if (!cx->stack.pushInvokeArgs(cx, 0, &ag))
         return false;
 
-    args.calleev() = toISO;
-    args.thisv().setObject(*obj);
-
-    if (!Invoke(cx, args))
+    ag.setCallee(toISO);
+    ag.setThis(ObjectValue(*obj));
+
+    if (!Invoke(cx, ag))
         return false;
-    *vp = args.rval();
+    args.rval().set(ag.rval());
     return true;
 }
 
 /* for Date.toLocaleString; interface to PRMJTime date struct.
  */
 static void
 new_explode(double timeval, PRMJTime *split, JSContext *cx)
 {
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -681,17 +681,17 @@ exn_toString(JSContext *cx, unsigned arg
  * Return a string that may eval to something similar to the original object.
  */
 static JSBool
 exn_toSource(JSContext *cx, unsigned argc, Value *vp)
 {
     JS_CHECK_RECURSION(cx, return false);
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     RootedValue nameVal(cx);
     RootedString name(cx);
     if (!obj->getProperty(cx, cx->runtime->atomState.nameAtom, &nameVal) ||
         !(name = ToString(cx, nameVal)))
     {
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -464,17 +464,18 @@ fun_hasInstance(JSContext *cx, HandleObj
     if (!obj->getProperty(cx, cx->runtime->atomState.classPrototypeAtom, &pval))
         return JS_FALSE;
 
     if (pval.isPrimitive()) {
         /*
          * Throw a runtime error if instanceof is called on a function that
          * has a non-object as its .prototype value.
          */
-        js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, ObjectValue(*obj), NULL);
+        RootedValue val(cx, ObjectValue(*obj));
+        js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, val, NullPtr());
         return JS_FALSE;
     }
 
     *bp = js_IsDelegate(cx, &pval.toObject(), *v);
     return JS_TRUE;
 }
 
 inline void
@@ -740,49 +741,52 @@ fun_toStringHelper(JSContext *cx, JSObje
 
     RootedFunction fun(cx, obj->toFunction());
     return FunctionToString(cx, fun, false, indent != JS_DONT_PRETTY_PRINT);
 }
 
 static JSBool
 fun_toString(JSContext *cx, unsigned argc, Value *vp)
 {
-    JS_ASSERT(IsFunctionObject(vp[0]));
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JS_ASSERT(IsFunctionObject(args.calleev()));
+
     uint32_t indent = 0;
 
-    if (argc != 0 && !ToUint32(cx, vp[2], &indent))
+    if (args.length() != 0 && !ToUint32(cx, args[0], &indent))
         return false;
 
-    JSObject *obj = ToObject(cx, &vp[1]);
+    JSObject *obj = ToObject(cx, args.thisv());
     if (!obj)
         return false;
 
     JSString *str = fun_toStringHelper(cx, obj, indent);
     if (!str)
         return false;
 
-    vp->setString(str);
+    args.rval().setString(str);
     return true;
 }
 
 #if JS_HAS_TOSOURCE
 static JSBool
 fun_toSource(JSContext *cx, unsigned argc, Value *vp)
 {
-    JS_ASSERT(IsFunctionObject(vp[0]));
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JS_ASSERT(IsFunctionObject(args.calleev()));
 
-    JSObject *obj = ToObject(cx, &vp[1]);
+    JSObject *obj = ToObject(cx, args.thisv());
     if (!obj)
         return false;
 
     JSString *str = fun_toStringHelper(cx, obj, JS_DONT_PRETTY_PRINT);
     if (!str)
         return false;
 
-    vp->setString(str);
+    args.rval().setString(str);
     return true;
 }
 #endif
 
 JSBool
 js_fun_call(JSContext *cx, unsigned argc, Value *vp)
 {
     Value fval = vp[1];
@@ -804,18 +808,18 @@ js_fun_call(JSContext *cx, unsigned argc
     }
 
     /* Allocate stack space for fval, obj, and the args. */
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, argc, &args))
         return JS_FALSE;
 
     /* Push fval, thisv, and the args. */
-    args.calleev() = fval;
-    args.thisv() = thisv;
+    args.setCallee(fval);
+    args.setThis(thisv);
     PodCopy(args.array(), argv, argc);
 
     bool ok = Invoke(cx, args);
     *vp = args.rval();
     return ok;
 }
 
 /* ES5 15.3.4.3 */
@@ -850,18 +854,18 @@ js_fun_apply(JSContext *cx, unsigned arg
         /* Steps 4-6. */
         unsigned length = cx->fp()->numActualArgs();
         JS_ASSERT(length <= StackSpace::ARGS_LENGTH_MAX);
 
         if (!cx->stack.pushInvokeArgs(cx, length, &args))
             return false;
 
         /* Push fval, obj, and aobj's elements as args. */
-        args.calleev() = fval;
-        args.thisv() = vp[2];
+        args.setCallee(fval);
+        args.setThis(vp[2]);
 
         /* Steps 7-8. */
         cx->fp()->forEachUnaliasedActual(CopyTo(args.array()));
     } else {
         /* Step 3. */
         if (!vp[3].isObject()) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_APPLY_ARGS, js_apply_str);
             return false;
@@ -881,18 +885,18 @@ js_fun_apply(JSContext *cx, unsigned arg
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TOO_MANY_FUN_APPLY_ARGS);
             return false;
         }
 
         if (!cx->stack.pushInvokeArgs(cx, length, &args))
             return false;
 
         /* Push fval, obj, and aobj's elements as args. */
-        args.calleev() = fval;
-        args.thisv() = vp[2];
+        args.setCallee(fval);
+        args.setThis(vp[2]);
 
         /* Steps 7-8. */
         if (!GetElements(cx, aobj, length, args.array()))
             return false;
     }
 
     /* Step 9. */
     if (!Invoke(cx, args))
@@ -1012,20 +1016,20 @@ CallOrConstructBoundFunction(JSContext *
         return false;
 
     /* 15.3.4.5.1, 15.3.4.5.2 step 4. */
     for (unsigned i = 0; i < argslen; i++)
         args[i] = fun->getBoundFunctionArgument(i);
     PodCopy(args.array() + argslen, vp + 2, argc);
 
     /* 15.3.4.5.1, 15.3.4.5.2 step 5. */
-    args.calleev().setObject(*target);
+    args.setCallee(ObjectValue(*target));
 
     if (!constructing)
-        args.thisv() = boundThis;
+        args.setThis(boundThis);
 
     if (constructing ? !InvokeConstructor(cx, args) : !Invoke(cx, args))
         return false;
 
     *vp = args.rval();
     return true;
 }
 
@@ -1055,17 +1059,17 @@ fun_isGenerator(JSContext *cx, unsigned 
 
 /* ES5 15.3.4.5. */
 static JSBool
 fun_bind(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
-    Value &thisv = args.thisv();
+    Value thisv = args.thisv();
 
     /* Step 2. */
     if (!js_IsCallable(thisv)) {
         ReportIncompatibleMethod(cx, args, &FunctionClass);
         return false;
     }
 
     /* Step 3. */
@@ -1512,17 +1516,17 @@ js_DefineFunction(JSContext *cx, HandleO
         return NULL;
 
     return fun;
 }
 
 void
 js::ReportIncompatibleMethod(JSContext *cx, CallReceiver call, Class *clasp)
 {
-    Value &thisv = call.thisv();
+    Value thisv = call.thisv();
 
 #ifdef DEBUG
     if (thisv.isObject()) {
         JS_ASSERT(thisv.toObject().getClass() != clasp ||
                   !thisv.toObject().getProto() ||
                   thisv.toObject().getProto()->getClass() != clasp);
     } else if (thisv.isString()) {
         JS_ASSERT(clasp != &StringClass);
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -105,35 +105,37 @@ CallThisObjectHook(JSContext *cx, JSObje
  */
 bool
 js::BoxNonStrictThis(JSContext *cx, const CallReceiver &call)
 {
     /*
      * Check for SynthesizeFrame poisoning and fast constructors which
      * didn't check their callee properly.
      */
-    Value &thisv = call.thisv();
+    Value thisv = call.thisv();
     JS_ASSERT(!thisv.isMagic());
 
 #ifdef DEBUG
     JSFunction *fun = call.callee().isFunction() ? call.callee().toFunction() : NULL;
     JS_ASSERT_IF(fun && fun->isInterpreted(), !fun->inStrictMode());
 #endif
 
     if (thisv.isNullOrUndefined()) {
         JSObject *thisp = call.callee().global().thisObject(cx);
-        JS_ASSERT(!IsPoisonedPtr(thisp));
         if (!thisp)
             return false;
-        call.thisv().setObject(*thisp);
+        call.setThis(ObjectValue(*thisp));
         return true;
     }
 
-    if (!thisv.isObject())
-        return !!js_PrimitiveToObject(cx, &thisv);
+    if (!thisv.isObject()) {
+        if (!js_PrimitiveToObject(cx, &thisv))
+            return false;
+        call.setThis(thisv);
+    }
 
     return true;
 }
 
 #if JS_HAS_NO_SUCH_METHOD
 
 const uint32_t JSSLOT_FOUND_FUNCTION  = 0;
 const uint32_t JSSLOT_SAVED_ID        = 1;
@@ -200,44 +202,48 @@ NoSuchMethod(JSContext *cx, unsigned arg
     if (!cx->stack.pushInvokeArgs(cx, 2, &args))
         return JS_FALSE;
 
     JS_ASSERT(vp[0].isObject());
     JS_ASSERT(vp[1].isObject());
     JSObject *obj = &vp[0].toObject();
     JS_ASSERT(obj->getClass() == &js_NoSuchMethodClass);
 
-    args.calleev() = obj->getSlot(JSSLOT_FOUND_FUNCTION);
-    args.thisv() = vp[1];
+    args.setCallee(obj->getSlot(JSSLOT_FOUND_FUNCTION));
+    args.setThis(vp[1]);
     args[0] = obj->getSlot(JSSLOT_SAVED_ID);
     JSObject *argsobj = NewDenseCopiedArray(cx, argc, vp + 2);
     if (!argsobj)
         return JS_FALSE;
     args[1].setObject(*argsobj);
     JSBool ok = Invoke(cx, args);
     vp[0] = args.rval();
     return ok;
 }
 
 #endif /* JS_HAS_NO_SUCH_METHOD */
 
 bool
 js::ReportIsNotFunction(JSContext *cx, const Value &v, MaybeConstruct construct)
 {
     unsigned error = construct ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION;
-    js_ReportValueError3(cx, error, JSDVG_SEARCH_STACK, v, NULL, NULL, NULL);
+
+    RootedValue val(cx, v);
+    js_ReportValueError3(cx, error, JSDVG_SEARCH_STACK, val, NullPtr(), NULL, NULL);
     return false;
 }
 
 bool
 js::ReportIsNotFunction(JSContext *cx, const Value *vp, MaybeConstruct construct)
 {
     ptrdiff_t spIndex = cx->stack.spIndexOf(vp);
     unsigned error = construct ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION;
-    js_ReportValueError3(cx, error, spIndex, *vp, NULL, NULL, NULL);
+
+    RootedValue val(cx, *vp);
+    js_ReportValueError3(cx, error, spIndex, val, NullPtr(), NULL, NULL);
     return false;
 }
 
 JSObject *
 js::ValueToCallable(JSContext *cx, const Value *vp, MaybeConstruct construct)
 {
     if (vp->isObject()) {
         JSObject *callable = &vp->toObject();
@@ -316,30 +322,30 @@ js::InvokeKernel(JSContext *cx, CallArgs
 
     /* We should never enter a new script while cx->iterValue is live. */
     JS_ASSERT(cx->iterValue.isMagic(JS_NO_ITER_VALUE));
 
     /* MaybeConstruct is a subset of InitialFrameFlags */
     InitialFrameFlags initial = (InitialFrameFlags) construct;
 
     if (args.calleev().isPrimitive())
-        return ReportIsNotFunction(cx, &args.calleev(), construct);
+        return ReportIsNotFunction(cx, args.calleev().address(), construct);
 
     JSObject &callee = args.callee();
     Class *clasp = callee.getClass();
 
     /* Invoke non-functions. */
     if (JS_UNLIKELY(clasp != &FunctionClass)) {
 #if JS_HAS_NO_SUCH_METHOD
         if (JS_UNLIKELY(clasp == &js_NoSuchMethodClass))
             return NoSuchMethod(cx, args.length(), args.base());
 #endif
         JS_ASSERT_IF(construct, !clasp->construct);
         if (!clasp->call)
-            return ReportIsNotFunction(cx, &args.calleev(), construct);
+            return ReportIsNotFunction(cx, args.calleev().address(), construct);
         return CallJSNative(cx, clasp->call, args);
     }
 
     /* Invoke native functions. */
     RootedFunction fun(cx, callee.toFunction());
     JS_ASSERT_IF(construct, !fun->isNativeConstructor());
     if (fun->isNative())
         return CallJSNative(cx, fun->native(), args);
@@ -364,86 +370,86 @@ js::InvokeKernel(JSContext *cx, CallArgs
 bool
 js::Invoke(JSContext *cx, const Value &thisv, const Value &fval, unsigned argc, Value *argv,
            Value *rval)
 {
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, argc, &args))
         return false;
 
-    args.calleev() = fval;
-    args.thisv() = thisv;
+    args.setCallee(fval);
+    args.setThis(thisv);
     PodCopy(args.array(), argv, argc);
 
     if (args.thisv().isObject()) {
         /*
          * We must call the thisObject hook in case we are not called from the
          * interpreter, where a prior bytecode has computed an appropriate
          * |this| already.
          */
         JSObject *thisp = args.thisv().toObject().thisObject(cx);
         if (!thisp)
              return false;
-        args.thisv().setObject(*thisp);
+        args.setThis(ObjectValue(*thisp));
     }
 
     if (!Invoke(cx, args))
         return false;
 
     *rval = args.rval();
     return true;
 }
 
 bool
 js::InvokeConstructorKernel(JSContext *cx, CallArgs args)
 {
     JS_ASSERT(!FunctionClass.construct);
 
-    args.thisv().setMagic(JS_IS_CONSTRUCTING);
+    args.setThis(MagicValue(JS_IS_CONSTRUCTING));
 
     if (!args.calleev().isObject())
-        return ReportIsNotFunction(cx, &args.calleev(), CONSTRUCT);
+        return ReportIsNotFunction(cx, args.calleev().address(), CONSTRUCT);
 
     JSObject &callee = args.callee();
     if (callee.isFunction()) {
         JSFunction *fun = callee.toFunction();
 
         if (fun->isNativeConstructor()) {
             Probes::calloutBegin(cx, fun);
             bool ok = CallJSNativeConstructor(cx, fun->native(), args);
             Probes::calloutEnd(cx, fun);
             return ok;
         }
 
         if (!fun->isInterpretedConstructor())
-            return ReportIsNotFunction(cx, &args.calleev(), CONSTRUCT);
+            return ReportIsNotFunction(cx, args.calleev().address(), CONSTRUCT);
 
         if (!InvokeKernel(cx, args, CONSTRUCT))
             return false;
 
         JS_ASSERT(args.rval().isObject());
         return true;
     }
 
     Class *clasp = callee.getClass();
     if (!clasp->construct)
-        return ReportIsNotFunction(cx, &args.calleev(), CONSTRUCT);
+        return ReportIsNotFunction(cx, args.calleev().address(), CONSTRUCT);
 
     return CallJSNativeConstructor(cx, clasp->construct, args);
 }
 
 bool
 js::InvokeConstructor(JSContext *cx, const Value &fval, unsigned argc, Value *argv, Value *rval)
 {
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, argc, &args))
         return false;
 
-    args.calleev() = fval;
-    args.thisv().setMagic(JS_THIS_POISON);
+    args.setCallee(fval);
+    args.setThis(MagicValue(JS_THIS_POISON));
     PodCopy(args.array(), argv, argc);
 
     if (!InvokeConstructor(cx, args))
         return false;
 
     *rval = args.rval();
     return true;
 }
@@ -525,18 +531,20 @@ js::Execute(JSContext *cx, HandleScript 
 }
 
 JSBool
 js::HasInstance(JSContext *cx, HandleObject obj, const Value *v, JSBool *bp)
 {
     Class *clasp = obj->getClass();
     if (clasp->hasInstance)
         return clasp->hasInstance(cx, obj, v, bp);
+
+    RootedValue val(cx, ObjectValue(*obj));
     js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
-                        JSDVG_SEARCH_STACK, ObjectValue(*obj), NULL);
+                        JSDVG_SEARCH_STACK, val, NullPtr());
     return JS_FALSE;
 }
 
 bool
 js::LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, bool *result)
 {
 #if JS_HAS_XML_SUPPORT
     if (JS_UNLIKELY(lval.isObject() && lval.toObject().isXML()) ||
@@ -875,18 +883,18 @@ DoIncDec(JSContext *cx, HandleScript scr
 #define PUSH_OBJECT(obj)         do { regs.sp++->setObject(obj); assertSameCompartment(cx, regs.sp[-1]); } while (0)
 #define PUSH_OBJECT_OR_NULL(obj) do { regs.sp++->setObjectOrNull(obj); assertSameCompartment(cx, regs.sp[-1]); } while (0)
 #define PUSH_HOLE()              regs.sp++->setMagic(JS_ARRAY_HOLE)
 #define POP_COPY_TO(v)           v = *--regs.sp
 #define POP_RETURN_VALUE()       regs.fp()->setReturnValue(*--regs.sp)
 
 #define FETCH_OBJECT(cx, n, obj)                                              \
     JS_BEGIN_MACRO                                                            \
-        Value *vp_ = &regs.sp[n];                                             \
-        obj = ToObject(cx, (vp_));                                            \
+        HandleValue val = HandleValue::fromMarkedLocation(&regs.sp[n]);       \
+        obj = ToObject(cx, (val));                                            \
         if (!obj)                                                             \
             goto error;                                                       \
     JS_END_MACRO
 
 /*
  * Threaded interpretation via computed goto appears to be well-supported by
  * GCC 3 and higher.  IBM's C compiler when run with the right options (e.g.,
  * -qlanglvl=extended) also supports threading.  Ditto the SunPro C compiler.
@@ -1670,19 +1678,19 @@ END_CASE(JSOP_AND)
             }                                                                 \
             len = 1 + JSOP_IFEQ_LENGTH;                                       \
             DO_NEXT_OP(len);                                                  \
         }                                                                     \
     JS_END_MACRO
 
 BEGIN_CASE(JSOP_IN)
 {
-    const Value &rref = regs.sp[-1];
+    HandleValue rref = HandleValue::fromMarkedLocation(&regs.sp[-1]);
     if (!rref.isObject()) {
-        js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, NULL);
+        js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, NullPtr());
         goto error;
     }
     RootedObject &obj = rootObject0;
     obj = &rref.toObject();
     RootedId &id = rootId0;
     FETCH_ELEMENT_ID(obj, -2, id);
     RootedObject &obj2 = rootObject1;
     RootedShape &prop = rootShape0;
@@ -2199,18 +2207,19 @@ END_CASE(JSOP_DELELEM)
 BEGIN_CASE(JSOP_TOID)
 {
     /*
      * Increment or decrement requires use to lookup the same property twice, but we need to avoid
      * the oberservable stringification the second time.
      * There must be an object value below the id, which will not be popped
      * but is necessary in interning the id for XML.
      */
-    Value objval = regs.sp[-2];
-    Value idval = regs.sp[-1];
+    RootedValue &objval = rootValue0, &idval = rootValue1;
+    objval = regs.sp[-2];
+    idval = regs.sp[-1];
 
     MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-1]);
     if (!ToIdOperation(cx, objval, idval, res))
         goto error;
 }
 END_CASE(JSOP_TOID)
 
 BEGIN_CASE(JSOP_TYPEOFEXPR)
@@ -2295,49 +2304,53 @@ BEGIN_CASE(JSOP_THIS)
     PUSH_COPY(regs.fp()->thisValue());
 END_CASE(JSOP_THIS)
 
 BEGIN_CASE(JSOP_GETPROP)
 BEGIN_CASE(JSOP_GETXPROP)
 BEGIN_CASE(JSOP_LENGTH)
 BEGIN_CASE(JSOP_CALLPROP)
 {
+    RootedValue &lval = rootValue0;
+    lval = regs.sp[-1];
+
     RootedValue rval(cx);
-    if (!GetPropertyOperation(cx, script, regs.pc, regs.sp[-1], rval.address()))
+    if (!GetPropertyOperation(cx, regs.pc, &lval, &rval))
         goto error;
 
     TypeScript::Monitor(cx, script, regs.pc, rval);
 
     regs.sp[-1] = rval;
     assertSameCompartment(cx, regs.sp[-1]);
 }
 END_CASE(JSOP_GETPROP)
 
 BEGIN_CASE(JSOP_SETGNAME)
 BEGIN_CASE(JSOP_SETNAME)
 BEGIN_CASE(JSOP_SETPROP)
 {
-    const Value &rval = regs.sp[-1];
-    const Value &lval = regs.sp[-2];
+    HandleValue lval = HandleValue::fromMarkedLocation(&regs.sp[-2]);
+    HandleValue rval = HandleValue::fromMarkedLocation(&regs.sp[-1]);
 
     if (!SetPropertyOperation(cx, regs.pc, lval, rval))
         goto error;
 
     regs.sp[-2] = regs.sp[-1];
     regs.sp--;
 }
 END_CASE(JSOP_SETPROP)
 
 BEGIN_CASE(JSOP_GETELEM)
 BEGIN_CASE(JSOP_CALLELEM)
 {
-    Value &lref = regs.sp[-2];
-    Value &rref = regs.sp[-1];
+    MutableHandleValue lval = MutableHandleValue::fromMarkedLocation(&regs.sp[-2]);
+    HandleValue rval = HandleValue::fromMarkedLocation(&regs.sp[-1]);
+
     MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-2]);
-    if (!GetElementOperation(cx, op, lref, rref, res))
+    if (!GetElementOperation(cx, op, lval, rval, res))
         goto error;
     TypeScript::Monitor(cx, script, regs.pc, res);
     regs.sp--;
 }
 END_CASE(JSOP_GETELEM)
 
 BEGIN_CASE(JSOP_SETELEM)
 {
@@ -3258,19 +3271,20 @@ BEGIN_CASE(JSOP_THROW)
     POP_COPY_TO(v);
     cx->setPendingException(v);
     /* let the code at error try to catch the exception. */
     goto error;
 }
 
 BEGIN_CASE(JSOP_INSTANCEOF)
 {
-    const Value &rref = regs.sp[-1];
+    RootedValue &rref = rootValue0;
+    rref = regs.sp[-1];
     if (rref.isPrimitive()) {
-        js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, -1, rref, NULL);
+        js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, -1, rref, NullPtr());
         goto error;
     }
     RootedObject &obj = rootObject0;
     obj = &rref.toObject();
     const Value &lref = regs.sp[-2];
     JSBool cond = JS_FALSE;
     if (!HasInstance(cx, obj, &lref, &cond))
         goto error;
@@ -3698,18 +3712,19 @@ BEGIN_CASE(JSOP_GENERATOR)
         goto inline_return;
     goto exit;
 }
 
 BEGIN_CASE(JSOP_YIELD)
     JS_ASSERT(!cx->isExceptionPending());
     JS_ASSERT(regs.fp()->isNonEvalFunctionFrame());
     if (cx->innermostGenerator()->state == JSGEN_CLOSING) {
-        js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, JSDVG_SEARCH_STACK,
-                            ObjectValue(regs.fp()->callee()), NULL);
+        RootedValue &val = rootValue0;
+        val.setObject(regs.fp()->callee());
+        js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, JSDVG_SEARCH_STACK, val, NullPtr());
         goto error;
     }
     regs.fp()->setReturnValue(regs.sp[-1]);
     regs.fp()->setYielding();
     regs.pc += JSOP_YIELD_LENGTH;
     interpReturnOK = true;
     goto exit;
 
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -139,32 +139,32 @@ GuardFunApplyArgumentsOptimization(JSCon
  * temporary object that the specification does.
  *
  * For objects, return the object itself. For string, boolean, and number
  * primitive values, return the appropriate constructor's prototype. For
  * undefined and null, throw an error and return NULL, attributing the
  * problem to the value at |spindex| on the stack.
  */
 JS_ALWAYS_INLINE JSObject *
-ValuePropertyBearer(JSContext *cx, StackFrame *fp, const Value &v, int spindex)
+ValuePropertyBearer(JSContext *cx, StackFrame *fp, HandleValue v, int spindex)
 {
     if (v.isObject())
         return &v.toObject();
 
     GlobalObject &global = fp->global();
 
     if (v.isString())
         return global.getOrCreateStringPrototype(cx);
     if (v.isNumber())
         return global.getOrCreateNumberPrototype(cx);
     if (v.isBoolean())
         return global.getOrCreateBooleanPrototype(cx);
 
     JS_ASSERT(v.isNull() || v.isUndefined());
-    js_ReportIsNullOrUndefined(cx, spindex, v, NULL);
+    js_ReportIsNullOrUndefined(cx, spindex, v, NullPtr());
     return NULL;
 }
 
 inline bool
 NativeGet(JSContext *cx, Handle<JSObject*> obj, Handle<JSObject*> pobj, Shape *shape,
           unsigned getHow, Value *vp)
 {
     if (shape->isDataDescriptor() && shape->hasDefaultGetter()) {
@@ -200,101 +200,99 @@ GetPropertyGenericMaybeCallXML(JSContext
     if (op == JSOP_CALLPROP && obj->isXML())
         return js_GetXMLMethod(cx, obj, id, vp);
 #endif
 
     return obj->getGeneric(cx, id, vp);
 }
 
 inline bool
-GetPropertyOperation(JSContext *cx, JSScript *script, jsbytecode *pc, Value &lval, Value *vp)
+GetPropertyOperation(JSContext *cx, jsbytecode *pc, MutableHandleValue lval, MutableHandleValue vp)
 {
-    JS_ASSERT(vp != &lval);
+    JS_ASSERT(vp.address() != lval.address());
 
     JSOp op = JSOp(*pc);
 
     if (op == JSOP_LENGTH) {
         /* Optimize length accesses on strings, arrays, and arguments. */
         if (lval.isString()) {
-            *vp = Int32Value(lval.toString()->length());
+            vp.setInt32(lval.toString()->length());
             return true;
         }
-        if (IsOptimizedArguments(cx->fp(), &lval)) {
-            *vp = Int32Value(cx->fp()->numActualArgs());
+        if (IsOptimizedArguments(cx->fp(), lval.address())) {
+            vp.setInt32(cx->fp()->numActualArgs());
             return true;
         }
         if (lval.isObject()) {
             JSObject *obj = &lval.toObject();
             if (obj->isArray()) {
                 uint32_t length = obj->getArrayLength();
-                *vp = NumberValue(length);
+                vp.setNumber(length);
                 return true;
             }
 
             if (obj->isArguments()) {
                 ArgumentsObject *argsobj = &obj->asArguments();
                 if (!argsobj->hasOverriddenLength()) {
                     uint32_t length = argsobj->initialLength();
                     JS_ASSERT(length < INT32_MAX);
-                    *vp = Int32Value(int32_t(length));
+                    vp.setInt32(int32_t(length));
                     return true;
                 }
             }
 
             if (obj->isTypedArray()) {
-                *vp = Int32Value(TypedArray::length(obj));
+                vp.setInt32(TypedArray::length(obj));
                 return true;
             }
         }
     }
 
-    RootedObject obj(cx, ValueToObject(cx, lval));
+    RootedObject obj(cx, ToObjectFromStack(cx, lval));
     if (!obj)
         return false;
 
     PropertyCacheEntry *entry;
     Rooted<JSObject*> obj2(cx);
     PropertyName *name;
     JS_PROPERTY_CACHE(cx).test(cx, pc, obj.get(), obj2.get(), entry, name);
     if (!name) {
         AssertValidPropertyCacheHit(cx, obj, obj2, entry);
-        if (!NativeGet(cx, obj, obj2, entry->prop, JSGET_CACHE_RESULT, vp))
+        if (!NativeGet(cx, obj, obj2, entry->prop, JSGET_CACHE_RESULT, vp.address()))
             return false;
         return true;
     }
 
     RootedId id(cx, NameToId(name));
-    RootedValue value(cx);
 
     if (obj->getOps()->getProperty) {
-        if (!GetPropertyGenericMaybeCallXML(cx, op, obj, id, &value))
+        if (!GetPropertyGenericMaybeCallXML(cx, op, obj, id, vp))
             return false;
     } else {
-        if (!GetPropertyHelper(cx, obj, id, JSGET_CACHE_RESULT, &value))
+        if (!GetPropertyHelper(cx, obj, id, JSGET_CACHE_RESULT, vp))
             return false;
     }
 
 #if JS_HAS_NO_SUCH_METHOD
     if (op == JSOP_CALLPROP &&
-        JS_UNLIKELY(value.isPrimitive()) &&
+        JS_UNLIKELY(vp.isPrimitive()) &&
         lval.isObject())
     {
-        if (!OnUnknownMethod(cx, obj, IdToValue(id), &value))
+        if (!OnUnknownMethod(cx, obj, IdToValue(id), vp))
             return false;
     }
 #endif
 
-    *vp = value;
     return true;
 }
 
 inline bool
-SetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, const Value &rval)
+SetPropertyOperation(JSContext *cx, jsbytecode *pc, HandleValue lval, HandleValue rval)
 {
-    RootedObject obj(cx, ValueToObject(cx, lval));
+    RootedObject obj(cx, ToObjectFromStack(cx, lval));
     if (!obj)
         return false;
 
     JS_ASSERT_IF(*pc == JSOP_SETNAME || *pc == JSOP_SETGNAME, lval.isObject());
     JS_ASSERT_IF(*pc == JSOP_SETGNAME, obj == &cx->fp()->global());
 
     PropertyCacheEntry *entry;
     JSObject *obj2;
@@ -500,30 +498,28 @@ AddOperation(JSContext *cx, const Value 
 #if JS_HAS_XML_SUPPORT
     if (IsXML(lhs) && IsXML(rhs)) {
         if (!js_ConcatenateXML(cx, &lhs.toObject(), &rhs.toObject(), res))
             return false;
         types::TypeScript::MonitorUnknown(cx);
     } else
 #endif
     {
-        RootedValue lval_(cx, lhs);
-        RootedValue rval_(cx, rhs);
-        Value &lval = lval_.get();
-        Value &rval = rval_.get();
+        RootedValue lval(cx, lhs);
+        RootedValue rval(cx, rhs);
 
         /*
          * 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))
+        if (!ToPrimitive(cx, lval.address()))
             return false;
-        if (!ToPrimitive(cx, &rval))
+        if (!ToPrimitive(cx, rval.address()))
             return false;
         bool lIsString, rIsString;
         if ((lIsString = lval.isString()) | (rIsString = rval.isString())) {
             RootedString lstr(cx), rstr(cx);
             if (lIsString) {
                 lstr = lval.toString();
             } else {
                 lstr = ToString(cx, lval);
@@ -624,24 +620,24 @@ FetchElementId(JSContext *cx, JSObject *
     if (ValueFitsInInt32(idval, &i_) && INT_FITS_IN_JSID(i_)) {
         *idp = INT_TO_JSID(i_);
         return true;
     }
     return !!InternNonIntElementId(cx, obj, idval, idp, vp);
 }
 
 static JS_ALWAYS_INLINE bool
-ToIdOperation(JSContext *cx, const Value &objval, const Value &idval, MutableHandleValue res)
+ToIdOperation(JSContext *cx, HandleValue objval, HandleValue idval, MutableHandleValue res)
 {
     if (idval.isInt32()) {
         res.set(idval);
         return true;
     }
 
-    JSObject *obj = ValueToObject(cx, objval);
+    JSObject *obj = ToObjectFromStack(cx, objval);
     if (!obj)
         return false;
 
     jsid dummy;
     if (!InternNonIntElementId(cx, obj, idval, &dummy, res))
         return false;
 
     if (!res.isInt32())
@@ -705,50 +701,51 @@ GetObjectElementOperation(JSContext *cx,
         }
     }
 
     assertSameCompartment(cx, res);
     return true;
 }
 
 static JS_ALWAYS_INLINE bool
-GetElementOperation(JSContext *cx, JSOp op, Value &lref, const Value &rref, MutableHandleValue res)
+GetElementOperation(JSContext *cx, JSOp op, MutableHandleValue lref, HandleValue rref,
+                    MutableHandleValue res)
 {
     JS_ASSERT(op == JSOP_GETELEM || op == JSOP_CALLELEM);
 
     if (lref.isString() && rref.isInt32()) {
         JSString *str = lref.toString();
         int32_t i = rref.toInt32();
         if (size_t(i) < str->length()) {
             str = cx->runtime->staticStrings.getUnitStringForElement(cx, str, size_t(i));
             if (!str)
                 return false;
             res.setString(str);
             return true;
         }
     }
 
     StackFrame *fp = cx->fp();
-    if (IsOptimizedArguments(fp, &lref)) {
+    if (IsOptimizedArguments(fp, lref.address())) {
         if (rref.isInt32()) {
             int32_t i = rref.toInt32();
             if (i >= 0 && uint32_t(i) < fp->numActualArgs()) {
                 res.set(fp->unaliasedActual(i));
                 return true;
             }
         }
 
         if (!JSScript::argumentsOptimizationFailed(cx, fp->script()))
             return false;
 
-        lref = ObjectValue(fp->argsObj());
+        lref.set(ObjectValue(fp->argsObj()));
     }
 
     bool isObject = lref.isObject();
-    RootedObject obj(cx, ValueToObject(cx, lref));
+    RootedObject obj(cx, ToObjectFromStack(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))
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -338,17 +338,17 @@ js::GetPropertyNames(JSContext *cx, JSOb
 size_t sCustomIteratorCount = 0;
 
 static inline bool
 GetCustomIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleValue vp)
 {
     JS_CHECK_RECURSION(cx, return false);
 
     /* Check whether we have a valid __iterator__ method. */
-    PropertyName *name = cx->runtime->atomState.iteratorIntrinsicAtom;
+    RootedPropertyName name(cx, cx->runtime->atomState.iteratorIntrinsicAtom);
     if (!GetMethod(cx, obj, name, 0, vp))
         return false;
 
     /* If there is no custom __iterator__ method, we are done here. */
     if (!vp.isObject()) {
         vp.setUndefined();
         return true;
     }
@@ -363,18 +363,19 @@ GetCustomIterator(JSContext *cx, HandleO
     if (vp.isPrimitive()) {
         /*
          * We are always coming from js::ValueToIterator, and we are no longer on
          * trace, so the object we are iterating over is on top of the stack (-1).
          */
         JSAutoByteString bytes;
         if (!js_AtomToPrintableString(cx, name, &bytes))
             return false;
+        RootedValue val(cx, ObjectValue(*obj));
         js_ReportValueError2(cx, JSMSG_BAD_TRAP_RETURN_VALUE,
-                             -1, ObjectValue(*obj), NULL, bytes.ptr());
+                             -1, val, NullPtr(), bytes.ptr());
         return false;
     }
     return true;
 }
 
 template <typename T>
 static inline bool
 Compare(T *a, T *b, size_t c)
@@ -573,29 +574,32 @@ GetIterator(JSContext *cx, HandleObject 
         RootedValue method(cx);
         if (!obj->getProperty(cx, obj, cx->runtime->atomState.iteratorAtom, &method))
             return false;
 
         // Throw if obj.iterator isn't callable. js::Invoke is about to check
         // for this kind of error anyway, but it would throw an inscrutable
         // error message about |method| rather than this nice one about |obj|.
         if (!method.isObject() || !method.toObject().isCallable()) {
-            char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, ObjectOrNullValue(obj), NULL);
+            RootedValue val(cx, ObjectOrNullValue(obj));
+            char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, val, NullPtr());
             if (!bytes)
                 return false;
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_ITERABLE, bytes);
             cx->free_(bytes);
             return false;
         }
 
         if (!Invoke(cx, ObjectOrNullValue(obj), method, 0, NULL, vp.address()))
             return false;
 
-        if (!ToObject(cx, vp.address()))
+        JSObject *obj = ToObject(cx, vp);
+        if (!obj)
             return false;
+        vp.setObject(*obj);
         return true;
     }
 
     Vector<Shape *, 8> shapes(cx);
     uint32_t key = 0;
 
     bool keysOnly = (flags == JSITER_ENUMERATE);
 
@@ -841,17 +845,17 @@ Class PropertyIteratorObject::class_ = {
     }
 };
 
 const uint32_t CLOSED_INDEX = UINT32_MAX;
 
 JSObject *
 ElementIteratorObject::create(JSContext *cx, Handle<Value> target)
 {
-    GlobalObject *global = GetCurrentGlobal(cx);
+    Rooted<GlobalObject*> global(cx, GetCurrentGlobal(cx));
     Rooted<JSObject*> proto(cx, global->getOrCreateElementIteratorPrototype(cx));
     if (!proto)
         return NULL;
     JSObject *iterobj = NewObjectWithGivenProto(cx, &ElementIteratorClass, proto, global);
     if (iterobj) {
         iterobj->setReservedSlot(TargetSlot, target);
         iterobj->setReservedSlot(IndexSlot, Int32Value(0));
     }
@@ -869,26 +873,26 @@ ElementIteratorObject::next(JSContext *c
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod(cx, IsElementIterator, next_impl, args);
 }
 
 bool
 ElementIteratorObject::next_impl(JSContext *cx, CallArgs args)
 {
-    JSObject *iterobj = &args.thisv().toObject();
+    RootedObject iterobj(cx, &args.thisv().toObject());
     uint32_t i, length;
-    Value target = iterobj->getReservedSlot(TargetSlot);
+    RootedValue target(cx, iterobj->getReservedSlot(TargetSlot));
     Rooted<JSObject*> obj(cx);
 
     // Get target.length.
     if (target.isString()) {
         length = uint32_t(target.toString()->length());
     } else {
-        obj = ValueToObject(cx, target);
+        obj = ToObjectFromStack(cx, target);
         if (!obj)
             goto close;
         if (!js_GetLengthProperty(cx, obj, &length))
             goto close;
     }
 
     // Check target.length.
     i = uint32_t(iterobj->getReservedSlot(IndexSlot).toInt32());
@@ -1600,18 +1604,19 @@ generator_send_impl(JSContext *cx, CallA
 
     JSGenerator *gen = (JSGenerator *) thisObj->getPrivate();
     if (!gen || gen->state == JSGEN_CLOSED) {
         /* This happens when obj is the generator prototype. See bug 352885. */
         return js_ThrowStopIteration(cx);
     }
 
     if (gen->state == JSGEN_NEWBORN && args.hasDefined(0)) {
+        RootedValue val(cx, args[0]);
         js_ReportValueError(cx, JSMSG_BAD_GENERATOR_SEND,
-                            JSDVG_SEARCH_STACK, args[0], NULL);
+                            JSDVG_SEARCH_STACK, val, NullPtr());
         return false;
     }
 
     if (!SendToGenerator(cx, JSGENOP_SEND, thisObj, gen,
                          args.length() > 0 ? args[0] : UndefinedValue()))
     {
         return false;
     }
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -324,33 +324,35 @@ js_TraceSharpMap(JSTracer *trc, JSSharpO
         JS_ASSERT(tmp == r.front().key);
     }
 }
 
 #if JS_HAS_TOSOURCE
 static JSBool
 obj_toSource(JSContext *cx, unsigned argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     bool comma = false;
     const jschar *vchars;
     size_t vlength;
     Value *val;
     JSString *gsop[2];
     SkipRoot skipGsop(cx, &gsop, 2);
 
     JS_CHECK_RECURSION(cx, return JS_FALSE);
 
     Value localroot[4];
     PodArrayZero(localroot);
     AutoArrayRooter tvr(cx, ArrayLength(localroot), localroot);
 
     /* If outermost, we need parentheses to be an expression, not a block. */
     bool outermost = (cx->sharpObjectMap.depth == 0);
 
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     JSIdArray *ida;
     bool alreadySeen = false;
     bool isSharp = false;
     if (!js_EnterSharpObject(cx, obj, &ida, &alreadySeen, &isSharp))
         return false;
@@ -359,17 +361,17 @@ obj_toSource(JSContext *cx, unsigned arg
         /*
          * We've already seen obj, so don't serialize it again (particularly as
          * we might recur in the process): just serialize an empty object.
          */
         JS_ASSERT(alreadySeen);
         JSString *str = js_NewStringCopyZ(cx, "{}");
         if (!str)
             return false;
-        vp->setString(str);
+        args.rval().setString(str);
         return true;
     }
 
     JS_ASSERT(!isSharp);
     if (alreadySeen) {
         JSSharpTable::Ptr p = cx->sharpObjectMap.table.lookup(obj);
         JS_ASSERT(p);
         JS_ASSERT(!p->value.isSharp);
@@ -532,17 +534,17 @@ obj_toSource(JSContext *cx, unsigned arg
     if (!buf.append('}'))
         return false;
     if (outermost && !buf.append(')'))
         return false;
 
     JSString *str = buf.finishString();
     if (!str)
         return false;
-    vp->setString(str);
+    args.rval().setString(str);
     return true;
 }
 #endif /* JS_HAS_TOSOURCE */
 
 namespace js {
 
 JSString *
 obj_toStringHelper(JSContext *cx, JSObject *obj)
@@ -589,68 +591,69 @@ InformalValueTypeName(const Value &v)
 }
 
 } /* namespace js */
 
 /* ES5 15.2.4.2.  Note steps 1 and 2 are errata. */
 static JSBool
 obj_toString(JSContext *cx, unsigned argc, Value *vp)
 {
-    Value &thisv = vp[1];
+    CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
-    if (thisv.isUndefined()) {
-        vp->setString(cx->runtime->atomState.objectUndefinedAtom);
+    if (args.thisv().isUndefined()) {
+        args.rval().setString(cx->runtime->atomState.objectUndefinedAtom);
         return true;
     }
 
     /* Step 2. */
-    if (thisv.isNull()) {
-        vp->setString(cx->runtime->atomState.objectNullAtom);
+    if (args.thisv().isNull()) {
+        args.rval().setString(cx->runtime->atomState.objectNullAtom);
         return true;
     }
 
     /* Step 3. */
-    JSObject *obj = ToObject(cx, &thisv);
+    JSObject *obj = ToObject(cx, args.thisv());
     if (!obj)
         return false;
 
     /* Steps 4-5. */
     JSString *str = js::obj_toStringHelper(cx, obj);
     if (!str)
         return false;
-    vp->setString(str);
+    args.rval().setString(str);
     return true;
 }
 
 /* ES5 15.2.4.3. */
 static JSBool
 obj_toLocaleString(JSContext *cx, unsigned argc, Value *vp)
 {
     JS_CHECK_RECURSION(cx, return false);
 
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
-    JSObject *obj = ToObject(cx, &args.thisv());
+    JSObject *obj = ToObject(cx, args.thisv());
     if (!obj)
         return false;
 
     /* Steps 2-4. */
     RootedId id(cx, NameToId(cx->runtime->atomState.toStringAtom));
     return obj->callMethod(cx, id, 0, NULL, args.rval());
 }
 
 static JSBool
 obj_valueOf(JSContext *cx, unsigned argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, args.thisv());
     if (!obj)
         return false;
-    vp->setObject(*obj);
+    args.rval().setObject(*obj);
     return true;
 }
 
 #if JS_HAS_OBJ_WATCHPOINT
 
 static JSBool
 obj_watch_handler(JSContext *cx, JSObject *obj_, jsid id_, jsval old,
                   jsval *nvp, void *closure)
@@ -679,55 +682,59 @@ obj_watch_handler(JSContext *cx, JSObjec
 
     Value argv[] = { IdToValue(id), old, *nvp };
     return Invoke(cx, ObjectValue(*obj), ObjectOrNullValue(callable), ArrayLength(argv), argv, nvp);
 }
 
 static JSBool
 obj_watch(JSContext *cx, unsigned argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     if (argc <= 1) {
-        js_ReportMissingArg(cx, *vp, 1);
+        js_ReportMissingArg(cx, args.calleev(), 1);
         return false;
     }
 
-    RootedObject callable(cx, ValueToCallable(cx, &vp[3]));
+    RootedObject callable(cx, ValueToCallable(cx, &args[1]));
     if (!callable)
         return false;
 
     RootedId propid(cx);
-    if (!ValueToId(cx, vp[2], propid.address()))
+    if (!ValueToId(cx, args[0], propid.address()))
         return false;
 
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     Value tmp;
     unsigned attrs;
     if (!CheckAccess(cx, obj, propid, JSACC_WATCH, &tmp, &attrs))
         return false;
 
-    vp->setUndefined();
+    args.rval().setUndefined();
 
     if (obj->isDenseArray() && !JSObject::makeDenseArraySlow(cx, obj))
         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]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
-    vp->setUndefined();
+    args.rval().setUndefined();
     jsid id;
     if (argc != 0) {
-        if (!ValueToId(cx, vp[2], &id))
+        if (!ValueToId(cx, args[0], &id))
             return false;
     } else {
         id = JSID_VOID;
     }
     return JS_ClearWatchPoint(cx, obj, id, NULL, NULL);
 }
 
 #endif /* JS_HAS_OBJ_WATCHPOINT */
@@ -736,45 +743,49 @@ obj_unwatch(JSContext *cx, unsigned argc
  * Prototype and property query methods, to complement the 'in' and
  * 'instanceof' operators.
  */
 
 /* Proposed ECMA 15.2.4.5. */
 static JSBool
 obj_hasOwnProperty(JSContext *cx, unsigned argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
-    return js_HasOwnPropertyHelper(cx, obj->getOps()->lookupGeneric, argc, vp);
+    return js_HasOwnPropertyHelper(cx, obj->getOps()->lookupGeneric, argc, args.rval().address());
 }
 
 JSBool
 js_HasOwnPropertyHelper(JSContext *cx, LookupGenericOp lookup, unsigned argc,
                         Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     RootedId id(cx);
-    if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), id.address()))
+    if (!ValueToId(cx, args.length() ? args[0] : UndefinedValue(), id.address()))
         return JS_FALSE;
 
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
     RootedObject obj2(cx);
     RootedShape prop(cx);
     if (obj->isProxy()) {
         bool has;
         if (!Proxy::hasOwn(cx, obj, id, &has))
             return false;
-        vp->setBoolean(has);
+        args.rval().setBoolean(has);
         return true;
     }
     if (!js_HasOwnProperty(cx, lookup, obj, id, &obj2, &prop))
         return JS_FALSE;
-    vp->setBoolean(!!prop);
+    args.rval().setBoolean(!!prop);
     return JS_TRUE;
 }
 
 JSBool
 js_HasOwnProperty(JSContext *cx, LookupGenericOp lookup, HandleObject obj, HandleId id,
                   MutableHandleObject objp, MutableHandleShape propp)
 {
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING);
@@ -803,48 +814,52 @@ js_HasOwnProperty(JSContext *cx, LookupG
         propp.set(NULL);
     return true;
 }
 
 /* ES5 15.2.4.6. */
 static JSBool
 obj_isPrototypeOf(JSContext *cx, unsigned argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     /* Step 1. */
-    if (argc < 1 || !vp[2].isObject()) {
-        vp->setBoolean(false);
+    if (args.length() < 1 || !args[0].isObject()) {
+        args.rval().setBoolean(false);
         return true;
     }
 
     /* Step 2. */
-    JSObject *obj = ToObject(cx, &vp[1]);
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Step 3. */
-    vp->setBoolean(js_IsDelegate(cx, obj, vp[2]));
+    args.rval().setBoolean(js_IsDelegate(cx, obj, args[0]));
     return true;
 }
 
 /* ES5 15.2.4.7. */
 static JSBool
 obj_propertyIsEnumerable(JSContext *cx, unsigned argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     /* Step 1. */
     RootedId id(cx);
-    if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), id.address()))
+    if (!ValueToId(cx, args.length() ? args[0] : UndefinedValue(), id.address()))
         return false;
 
     /* Step 2. */
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Steps 3-5. */
-    return js_PropertyIsEnumerable(cx, obj, id, vp);
+    return js_PropertyIsEnumerable(cx, obj, id, args.rval().address());
 }
 
 JSBool
 js_PropertyIsEnumerable(JSContext *cx, HandleObject obj, HandleId id, Value *vp)
 {
     RootedObject pobj(cx);
     RootedShape prop(cx);
     if (!obj->lookupGeneric(cx, id, &pobj, &prop))
@@ -936,76 +951,80 @@ JS_FRIEND_API(JSBool)
 js::obj_defineSetter(JSContext *cx, unsigned argc, Value *vp)
 {
     return DefineAccessor<Setter>(cx, argc, vp);
 }
 
 static JSBool
 obj_lookupGetter(JSContext *cx, unsigned argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     RootedId id(cx);
-    if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), id.address()))
+    if (!ValueToId(cx, args.length() ? args[0] : UndefinedValue(), id.address()))
         return JS_FALSE;
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return JS_FALSE;
     if (obj->isProxy()) {
         // The vanilla getter lookup code below requires that the object is
         // native. Handle proxies separately.
-        vp->setUndefined();
+        args.rval().setUndefined();
         AutoPropertyDescriptorRooter desc(cx);
         if (!Proxy::getPropertyDescriptor(cx, obj, id, false, &desc))
             return JS_FALSE;
         if (desc.obj && (desc.attrs & JSPROP_GETTER) && desc.getter)
-            *vp = CastAsObjectJsval(desc.getter);
+            args.rval().set(CastAsObjectJsval(desc.getter));
         return JS_TRUE;
     }
     RootedObject pobj(cx);
     RootedShape shape(cx);
     if (!obj->lookupGeneric(cx, id, &pobj, &shape))
         return JS_FALSE;
-    vp->setUndefined();
+    args.rval().setUndefined();
     if (shape) {
         if (pobj->isNative()) {
             if (shape->hasGetterValue())
-                *vp = shape->getterValue();
+                args.rval().set(shape->getterValue());
         }
     }
     return JS_TRUE;
 }
 
 static JSBool
 obj_lookupSetter(JSContext *cx, unsigned argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     RootedId id(cx);
-    if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), id.address()))
+    if (!ValueToId(cx, args.length() ? args[0] : UndefinedValue(), id.address()))
         return JS_FALSE;
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return JS_FALSE;
     if (obj->isProxy()) {
         // The vanilla setter lookup code below requires that the object is
         // native. Handle proxies separately.
-        vp->setUndefined();
+        args.rval().setUndefined();
         AutoPropertyDescriptorRooter desc(cx);
         if (!Proxy::getPropertyDescriptor(cx, obj, id, false, &desc))
             return JS_FALSE;
         if (desc.obj && (desc.attrs & JSPROP_SETTER) && desc.setter)
-            *vp = CastAsObjectJsval(desc.setter);
+            args.rval().set(CastAsObjectJsval(desc.setter));
         return JS_TRUE;
     }
     RootedObject pobj(cx);
     RootedShape shape(cx);
     if (!obj->lookupGeneric(cx, id, &pobj, &shape))
         return JS_FALSE;
-    vp->setUndefined();
+    args.rval().setUndefined();
     if (shape) {
         if (pobj->isNative()) {
             if (shape->hasSetterValue())
-                *vp = shape->setterValue();
+                args.rval().set(shape->setterValue());
         }
     }
     return JS_TRUE;
 }
 #endif /* OLD_GETTER_SETTER_METHODS */
 
 /* ES5 15.2.3.2. */
 JSBool
@@ -1015,17 +1034,18 @@ obj_getPrototypeOf(JSContext *cx, unsign
 
     /* Step 1. */
     if (args.length() == 0) {
         js_ReportMissingArg(cx, args.calleev(), 0);
         return false;
     }
 
     if (args[0].isPrimitive()) {
-        char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, vp[2], NULL);
+        RootedValue val(cx, args[0]);
+        char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, val, NullPtr());
         if (!bytes)
             return false;
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_UNEXPECTED_TYPE, bytes, "not an object");
         JS_free(cx, bytes);
         return false;
     }
 
@@ -1033,18 +1053,18 @@ obj_getPrototypeOf(JSContext *cx, unsign
 
     /*
      * Implement [[Prototype]]-getting -- particularly across compartment
      * boundaries -- by calling a cached __proto__ getter function.
      */
     InvokeArgsGuard nested;
     if (!cx->stack.pushInvokeArgs(cx, 0, &nested))
         return false;
-    nested.calleev() = cx->global()->protoGetter();
-    nested.thisv() = args[0];
+    nested.setCallee(cx->global()->protoGetter());
+    nested.setThis(args[0]);
     if (!Invoke(cx, nested))
         return false;
     args.rval().set(nested.rval());
     return true;
 }
 
 namespace js {
 
@@ -1184,19 +1204,19 @@ GetFirstArgumentAsObject(JSContext *cx, 
                          MutableHandleObject objp)
 {
     if (argc == 0) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
                              method, "0", "s");
         return false;
     }
 
-    const Value &v = vp[2];
+    RootedValue v(cx, vp[2]);
     if (!v.isObject()) {
-        char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL);
+        char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NullPtr());
         if (!bytes)
             return false;
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE,
                              bytes, "not an object");
         JS_free(cx, bytes);
         return false;
     }
 
@@ -1392,19 +1412,20 @@ Throw(JSContext *cx, jsid id, unsigned e
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, errorNumber, bytes.ptr());
     return false;
 }
 
 bool
 Throw(JSContext *cx, JSObject *obj, unsigned errorNumber)
 {
     if (js_ErrorFormatString[errorNumber].argCount == 1) {
+        RootedValue val(cx, ObjectValue(*obj));
         js_ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber,
-                                 JSDVG_IGNORE_STACK, ObjectValue(*obj),
-                                 NULL, NULL, NULL);
+                                 JSDVG_IGNORE_STACK, val, NullPtr(),
+                                 NULL, NULL);
     } else {
         JS_ASSERT(js_ErrorFormatString[errorNumber].argCount == 0);
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, errorNumber);
     }
     return false;
 }
 
 } /* namespace js */
@@ -1919,29 +1940,32 @@ js_PopulateObject(JSContext *cx, HandleO
 {
     return DefineProperties(cx, newborn, props);
 }
 
 /* ES5 15.2.3.7: Object.defineProperties(O, Properties) */
 static JSBool
 obj_defineProperties(JSContext *cx, unsigned argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     /* Steps 1 and 7. */
     RootedObject obj(cx);
-    if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.defineProperties", &obj))
+    if (!GetFirstArgumentAsObject(cx, args.length(), vp, "Object.defineProperties", &obj))
         return false;
-    vp->setObject(*obj);
+    args.rval().setObject(*obj);
 
     /* Step 2. */
-    if (argc < 2) {
+    if (args.length() < 2) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
                              "Object.defineProperties", "0", "s");
         return false;
     }
-    RootedObject props(cx, ToObject(cx, &vp[3]));
+    RootedValue val(cx, args[1]);
+    RootedObject props(cx, ToObject(cx, val));
     if (!props)
         return false;
 
     /* Steps 3-6. */
     return DefineProperties(cx, obj, props);
 }
 
 /* ES5 15.2.3.5: Object.create(O [, Properties]) */
@@ -1950,19 +1974,19 @@ obj_create(JSContext *cx, unsigned argc,
 {
     if (argc == 0) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
                              "Object.create", "0", "s");
         return false;
     }
 
     CallArgs args = CallArgsFromVp(argc, vp);
-    const Value &v = args[0];
+    RootedValue v(cx, args[0]);
     if (!v.isObjectOrNull()) {
-        char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL);
+        char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NullPtr());
         if (!bytes)
             return false;
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE,
                              bytes, "not an object or null");
         JS_free(cx, bytes);
         return false;
     }
 
@@ -4692,19 +4716,20 @@ js_GetPropertyHelperInline(JSContext *cx
             } else if (cx->resolveFlags & JSRESOLVE_DETECTING) {
                 return JS_TRUE;
             }
 
             unsigned flags = JSREPORT_WARNING | JSREPORT_STRICT;
             cx->stack.currentScript()->warnedAboutUndefinedProp = true;
 
             /* Ok, bad undefined property reference: whine about it. */
+            RootedValue val(cx, IdToValue(id));
             if (!js_ReportValueErrorFlags(cx, flags, JSMSG_UNDEFINED_PROP,
-                                          JSDVG_IGNORE_STACK, IdToValue(id),
-                                          NULL, NULL, NULL))
+                                          JSDVG_IGNORE_STACK, val, NullPtr(),
+                                          NULL, NULL))
             {
                 return false;
             }
         }
         return JS_TRUE;
     }
 
     if (!obj2->isNative()) {
@@ -4804,35 +4829,38 @@ js::CheckUndeclaredVarAssignment(JSConte
                                          | JSREPORT_STRICT_MODE_ERROR),
                                         js_GetErrorMessage, NULL,
                                         JSMSG_UNDECLARED_VAR, bytes.ptr());
 }
 
 bool
 JSObject::reportReadOnly(JSContext *cx, jsid id, unsigned report)
 {
+    RootedValue val(cx, IdToValue(id));
     return js_ReportValueErrorFlags(cx, report, JSMSG_READ_ONLY,
-                                    JSDVG_IGNORE_STACK, IdToValue(id), NULL,
+                                    JSDVG_IGNORE_STACK, val, NullPtr(),
                                     NULL, NULL);
 }
 
 bool
 JSObject::reportNotConfigurable(JSContext *cx, jsid id, unsigned report)
 {
+    RootedValue val(cx, IdToValue(id));
     return js_ReportValueErrorFlags(cx, report, JSMSG_CANT_DELETE,
-                                    JSDVG_IGNORE_STACK, IdToValue(id), NULL,
+                                    JSDVG_IGNORE_STACK, val, NullPtr(),
                                     NULL, NULL);
 }
 
 bool
 JSObject::reportNotExtensible(JSContext *cx, unsigned report)
 {
+    RootedValue val(cx, ObjectValue(*this));
     return js_ReportValueErrorFlags(cx, report, JSMSG_OBJECT_NOT_EXTENSIBLE,
-                                    JSDVG_IGNORE_STACK, ObjectValue(*this),
-                                    NULL, NULL, NULL);
+                                    JSDVG_IGNORE_STACK, val, NullPtr(),
+                                    NULL, NULL);
 }
 
 bool
 JSObject::callMethod(JSContext *cx, HandleId id, unsigned argc, Value *argv, MutableHandleValue vp)
 {
     RootedValue fval(cx);
     Rooted<JSObject*> obj(cx, this);
     return GetMethod(cx, obj, id, 0, &fval) &&
@@ -5260,26 +5288,27 @@ DefaultValue(JSContext *cx, HandleObject
         id = NameToId(cx->runtime->atomState.toStringAtom);
         if (!MaybeCallMethod(cx, obj, id, vp))
             return false;
         if (vp.isPrimitive())
             return true;
     }
 
     /* Avoid recursive death when decompiling in js_ReportValueError. */
-    JSString *str;
+    RootedString str(cx);
     if (hint == JSTYPE_STRING) {
         str = JS_InternString(cx, clasp->name);
         if (!str)
             return false;
     } else {
         str = NULL;
     }
 
-    js_ReportValueError2(cx, JSMSG_CANT_CONVERT_TO, JSDVG_SEARCH_STACK, ObjectValue(*obj), str,
+    RootedValue val(cx, ObjectValue(*obj));
+    js_ReportValueError2(cx, JSMSG_CANT_CONVERT_TO, JSDVG_SEARCH_STACK, val, str,
                          (hint == JSTYPE_VOID) ? "primitive type" : JS_TYPE_STR(hint));
     return false;
 }
 
 } /* namespace js */
 
 JS_FRIEND_API(JSBool)
 JS_EnumerateState(JSContext *cx, JSHandleObject obj, JSIterateOp enum_op, Value *statep, jsid *idp)
@@ -5484,44 +5513,47 @@ js_ValueToObjectOrNull(JSContext *cx, co
     objp.set(obj);
     return true;
 }
 
 namespace js {
 
 /* Callers must handle the already-object case . */
 JSObject *
-ToObjectSlow(JSContext *cx, Value *vp)
-{
-    JS_ASSERT(!vp->isMagic());
-    JS_ASSERT(!vp->isObject());
-
-    if (vp->isNullOrUndefined()) {
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CONVERT_TO,
-                            vp->isNull() ? "null" : "undefined", "object");
+ToObjectSlow(JSContext *cx, HandleValue val, bool reportScanStack)
+{
+    JS_ASSERT(!val.isMagic());
+    JS_ASSERT(!val.isObject());
+
+    if (val.isNullOrUndefined()) {
+        if (reportScanStack) {
+            js_ReportIsNullOrUndefined(cx, JSDVG_SEARCH_STACK, val, NullPtr());
+        } else {
+            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CONVERT_TO,
+                                 val.isNull() ? "null" : "undefined", "object");
+        }
         return NULL;
     }
 
-    JSObject *obj = PrimitiveToObject(cx, *vp);
-    if (obj)
-        vp->setObject(*obj);
-    return obj;
+    return PrimitiveToObject(cx, val);
 }
 
 }
 
 JSObject *
 js_ValueToNonNullObject(JSContext *cx, const Value &v)
 {
     RootedObject obj(cx);
 
     if (!js_ValueToObjectOrNull(cx, v, &obj))
         return NULL;
-    if (!obj)
-        js_ReportIsNullOrUndefined(cx, JSDVG_SEARCH_STACK, v, NULL);
+    if (!obj) {
+        RootedValue val(cx, v);
+        js_ReportIsNullOrUndefined(cx, JSDVG_SEARCH_STACK, val, NullPtr());
+    }
     return obj;
 }
 
 void
 js_GetObjectSlotName(JSTracer *trc, char *buf, size_t bufsize)
 {
     JS_ASSERT(trc->debugPrinter == js_GetObjectSlotName);
 
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -1329,37 +1329,39 @@ js_ValueToObjectOrNull(JSContext *cx, co
 
 /* Throws if v could not be converted to an object. */
 extern JSObject *
 js_ValueToNonNullObject(JSContext *cx, const js::Value &v);
 
 namespace js {
 
 /*
- * Invokes the ES5 ToObject algorithm on *vp, writing back the object to vp.
- * If *vp might already be an object, use ToObject.
+ * Invokes the ES5 ToObject algorithm on vp, returning the result. If vp might
+ * already be an object, use ToObject. reportCantConvert controls how null and
+ * undefined errors are reported.
  */
 extern JSObject *
-ToObjectSlow(JSContext *cx, Value *vp);
+ToObjectSlow(JSContext *cx, HandleValue vp, bool reportScanStack);
 
+/* For object conversion in e.g. native functions. */
 JS_ALWAYS_INLINE JSObject *
-ToObject(JSContext *cx, Value *vp)
+ToObject(JSContext *cx, HandleValue vp)
 {
-    if (vp->isObject())
-        return &vp->toObject();
-    return ToObjectSlow(cx, vp);
+    if (vp.isObject())
+        return &vp.toObject();
+    return ToObjectSlow(cx, vp, false);
 }
 
-/* As for ToObject, but preserves the original value. */
-inline JSObject *
-ValueToObject(JSContext *cx, const Value &v)
+/* For converting stack values to objects. */
+JS_ALWAYS_INLINE JSObject *
+ToObjectFromStack(JSContext *cx, HandleValue vp)
 {
-    if (v.isObject())
-        return &v.toObject();
-    return js_ValueToNonNullObject(cx, v);
+    if (vp.isObject())
+        return &vp.toObject();
+    return ToObjectSlow(cx, vp, true);
 }
 
 } /* namespace js */
 
 extern void
 js_GetObjectSlotName(JSTracer *trc, char *buf, size_t bufsize);
 
 extern bool
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -290,18 +290,18 @@ PreprocessValue(JSContext *cx, HandleObj
             keyStr = KeyStringifier<KeyType>::toString(cx, key);
             if (!keyStr)
                 return false;
 
             InvokeArgsGuard args;
             if (!cx->stack.pushInvokeArgs(cx, 1, &args))
                 return false;
 
-            args.calleev() = toJSON;
-            args.thisv() = vp;
+            args.setCallee(toJSON);
+            args.setThis(vp);
             args[0] = StringValue(keyStr);
 
             if (!Invoke(cx, args))
                 return false;
             vp.set(args.rval());
         }
     }
 
@@ -312,18 +312,18 @@ PreprocessValue(JSContext *cx, HandleObj
             if (!keyStr)
                 return false;
         }
 
         InvokeArgsGuard args;
         if (!cx->stack.pushInvokeArgs(cx, 2, &args))
             return false;
 
-        args.calleev() = ObjectValue(*scx->replacer);
-        args.thisv() = ObjectValue(*holder);
+        args.setCallee(ObjectValue(*scx->replacer));
+        args.setThis(ObjectValue(*holder));
         args[0] = StringValue(keyStr);
         args[1] = vp;
 
         if (!Invoke(cx, args))
             return false;
         vp.set(args.rval());
     }
 
@@ -833,18 +833,18 @@ Walk(JSContext *cx, HandleObject holder,
     RootedString key(cx, IdToString(cx, name));
     if (!key)
         return false;
 
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, 2, &args))
         return false;
 
-    args.calleev() = reviver;
-    args.thisv() = ObjectValue(*holder);
+    args.setCallee(reviver);
+    args.setThis(ObjectValue(*holder));
     args[0] = StringValue(key);
     args[1] = val;
 
     if (!Invoke(cx, args))
         return false;
     vp.set(args.rval());
     return true;
 }
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -6195,19 +6195,20 @@ DecompileExpressionFromStack(JSContext *
         return false;
     if (!ea.decompilePC(valuepc))
         return false;
 
     return ea.getOutput(res);
 }
 
 char *
-js_DecompileValueGenerator(JSContext *cx, int spindex, jsval v,
-                           JSString *fallback)
+js::DecompileValueGenerator(JSContext *cx, int spindex, HandleValue v,
+                            HandleString fallbackArg)
 {
+    RootedString fallback(cx, fallbackArg);
     {
         char *result;
         if (!DecompileExpressionFromStack(cx, spindex, v, &result))
             return NULL;
         if (result) {
             if (strcmp(result, "(intermediate value)"))
                 return result;
             cx->free_(result);
--- a/js/src/jsopcode.h
+++ b/js/src/jsopcode.h
@@ -317,32 +317,16 @@ js_DecompileFunction(JSPrinter *jp);
 typedef JSBool (* JSDecompilerPtr)(JSPrinter *);
 
 extern JSString *
 js_DecompileToString(JSContext *cx, const char *name, JSFunction *fun,
                      unsigned indent, JSBool pretty, JSBool grouped, JSBool strict,
                      JSDecompilerPtr decompiler);
 
 /*
- * Find the source expression that resulted in v, and return a newly allocated
- * C-string containing it.  Fall back on v's string conversion (fallback) if we
- * can't find the bytecode that generated and pushed v on the operand stack.
- *
- * Search the current stack frame if spindex is JSDVG_SEARCH_STACK.  Don't
- * look for v on the stack if spindex is JSDVG_IGNORE_STACK.  Otherwise,
- * spindex is the negative index of v, measured from cx->fp->sp, or from a
- * lower frame's sp if cx->fp is native.
- *
- * The caller must call JS_free on the result after a succsesful call.
- */
-extern char *
-js_DecompileValueGenerator(JSContext *cx, int spindex, jsval v,
-                           JSString *fallback);
-
-/*
  * Given bytecode address pc in script's main program code, return the operand
  * stack depth just before (JSOp) *pc executes.
  */
 extern unsigned
 js_ReconstructStackDepth(JSContext *cx, JSScript *script, jsbytecode *pc);
 
 #ifdef _MSC_VER
 #pragma warning(pop)
@@ -356,22 +340,30 @@ JS_END_EXTERN_C
 /*
  * Get the length of variable-length bytecode like JSOP_TABLESWITCH.
  */
 extern size_t
 js_GetVariableBytecodeLength(jsbytecode *pc);
 
 namespace js {
 
-static inline char *
-DecompileValueGenerator(JSContext *cx, int spindex, const Value &v,
-                        JSString *fallback)
-{
-    return js_DecompileValueGenerator(cx, spindex, v, fallback);
-}
+/*
+ * Find the source expression that resulted in v, and return a newly allocated
+ * C-string containing it.  Fall back on v's string conversion (fallback) if we
+ * can't find the bytecode that generated and pushed v on the operand stack.
+ *
+ * Search the current stack frame if spindex is JSDVG_SEARCH_STACK.  Don't
+ * look for v on the stack if spindex is JSDVG_IGNORE_STACK.  Otherwise,
+ * spindex is the negative index of v, measured from cx->fp->sp, or from a
+ * lower frame's sp if cx->fp is native.
+ *
+ * The caller must call JS_free on the result after a succsesful call.
+ */
+char *
+DecompileValueGenerator(JSContext *cx, int spindex, HandleValue v, HandleString fallback);
 
 /*
  * Sprintf, but with unlimited and automatically allocated buffering.
  */
 class Sprinter
 {
   public:
     struct InvariantChecker
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -347,18 +347,20 @@ BaseProxyHandler::nativeCall(JSContext *
     ReportIncompatible(cx, args);
     return false;
 }
 
 bool
 BaseProxyHandler::hasInstance(JSContext *cx, JSObject *proxy, const Value *vp, bool *bp)
 {
     JS_ASSERT(OperationInProgress(cx, proxy));
+
+    RootedValue val(cx, ObjectValue(*proxy));
     js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
-                        JSDVG_SEARCH_STACK, ObjectValue(*proxy), NULL);
+                        JSDVG_SEARCH_STACK, val, NullPtr());
     return false;
 }
 
 JSType
 BaseProxyHandler::typeOf(JSContext *cx, JSObject *proxy)
 {
     JS_ASSERT(OperationInProgress(cx, proxy));
     return IsFunctionProxy(proxy) ? JSTYPE_FUNCTION : JSTYPE_OBJECT;
@@ -488,17 +490,17 @@ IndirectProxyHandler::construct(JSContex
         fval = GetCall(proxy);
     return InvokeConstructor(cx, fval, argc, argv, rval);
 }
 
 bool
 IndirectProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
                                     CallArgs args)
 {
-    args.thisv() = ObjectValue(*GetProxyTargetObject(&args.thisv().toObject()));
+    args.setThis(ObjectValue(*GetProxyTargetObject(&args.thisv().toObject())));
     if (!test(args.thisv())) {
         ReportIncompatible(cx, args);
         return false;
     }
 
     return CallNativeImpl(cx, impl, args);
 }
 
@@ -820,18 +822,19 @@ ScriptedProxyHandler::~ScriptedProxyHand
 }
 
 static bool
 ReturnedValueMustNotBePrimitive(JSContext *cx, JSObject *proxy, JSAtom *atom, const Value &v)
 {
     if (v.isPrimitive()) {
         JSAutoByteString bytes;
         if (js_AtomToPrintableString(cx, atom, &bytes)) {
+            RootedValue val(cx, ObjectOrNullValue(proxy));
             js_ReportValueError2(cx, JSMSG_BAD_TRAP_RETURN_VALUE,
-                                 JSDVG_SEARCH_STACK, ObjectOrNullValue(proxy), NULL, bytes.ptr());
+                                 JSDVG_SEARCH_STACK, val, NullPtr(), bytes.ptr());
         }
         return false;
     }
     return true;
 }
 
 static JSObject *
 GetProxyHandlerObject(JSContext *cx, JSObject *proxy)
@@ -1069,20 +1072,22 @@ class AutoPendingProxyOperation {
         if (!proto)                                                          \
             return true;                                                     \
         assertSameCompartment(cx, proxy, proto);                             \
         return protoCall;                                                    \
     JS_END_MACRO                                                             \
 
 
 bool
-Proxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
+Proxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy_, jsid id_, bool set,
                              PropertyDescriptor *desc)
 {
     JS_CHECK_RECURSION(cx, return false);
+    RootedObject proxy(cx, proxy_);
+    RootedId id(cx, id_);
     AutoPendingProxyOperation pending(cx, proxy);
     BaseProxyHandler *handler = GetProxyHandler(proxy);
     if (!handler->hasPrototype())
         return handler->getPropertyDescriptor(cx, proxy, id, set, desc);
     if (!handler->getOwnPropertyDescriptor(cx, proxy, id, set, desc))
         return false;
     if (desc->obj)
         return true;
@@ -1188,19 +1193,21 @@ Proxy::enumerate(JSContext *cx, JSObject
         return false;
     AutoIdVector protoProps(cx);
     INVOKE_ON_PROTOTYPE(cx, handler, proxy,
                         GetPropertyNames(cx, proto, 0, &protoProps) &&
                         AppendUnique(cx, props, protoProps));
 }
 
 bool
-Proxy::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
+Proxy::has(JSContext *cx, JSObject *proxy_, jsid id_, bool *bp)
 {
     JS_CHECK_RECURSION(cx, return false);
+    RootedObject proxy(cx, proxy_);
+    RootedId id(cx, id_);
     AutoPendingProxyOperation pending(cx, proxy);
     BaseProxyHandler *handler = GetProxyHandler(proxy);
     if (!handler->hasPrototype())
         return handler->has(cx, proxy, id, bp);
     if (!handler->hasOwn(cx, proxy, id, bp))
         return false;
     if (*bp)
         return true;
@@ -1253,24 +1260,24 @@ Proxy::getElementIfPresent(JSContext *cx
 
 bool
 Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, bool strict,
            MutableHandleValue vp)
 {
     JS_CHECK_RECURSION(cx, return false);
     AutoPendingProxyOperation pending(cx, proxy);
     BaseProxyHandler *handler = GetProxyHandler(proxy);
-    JSObject *proto;
+    RootedObject proto(cx);
     if (handler->hasPrototype()) {
         // If we're using a prototype, we still want to use the proxy trap unless
         // we have a non-own property with a setter.
         bool hasOwn;
         AutoPropertyDescriptorRooter desc(cx);
         if (handler->hasOwn(cx, proxy, id, &hasOwn) && !hasOwn &&
-            handler->getPrototypeOf(cx, proxy, &proto) && proto &&
+            handler->getPrototypeOf(cx, proxy, proto.address()) && proto &&
             JS_GetPropertyDescriptorById(cx, proto, id, JSRESOLVE_QUALIFIED, &desc) &&
             desc.obj && desc.setter)
         {
             return proto->setGeneric(cx, receiver, id, vp, strict);
         } else if (cx->isExceptionPending()) {
             return false;
         }
     }
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -181,17 +181,17 @@ class NodeBuilder
 
             if (funv.isNullOrUndefined()) {
                 callbacks[i].setNull();
                 continue;
             }
 
             if (!funv.isObject() || !funv.toObject().isFunction()) {
                 js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NOT_FUNCTION,
-                                         JSDVG_SEARCH_STACK, funv, NULL, NULL, NULL);
+                                         JSDVG_SEARCH_STACK, funv, NullPtr(), NULL, NULL);
                 return false;
             }
 
             callbacks[i] = funv;
         }
 
         return true;
     }
@@ -3178,22 +3178,22 @@ reflect_parse(JSContext *cx, uint32_t ar
 
     char *filename = NULL;
     AutoReleaseNullablePtr filenamep(cx, filename);
     uint32_t lineno = 1;
     bool loc = true;
 
     JSObject *builder = NULL;
 
-    Value arg = argc > 1 ? JS_ARGV(cx, vp)[1] : UndefinedValue();
+    RootedValue arg(cx, argc > 1 ? JS_ARGV(cx, vp)[1] : UndefinedValue());
 
     if (!arg.isNullOrUndefined()) {
         if (!arg.isObject()) {
             js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
-                                     JSDVG_SEARCH_STACK, arg, NULL, "not an object", NULL);
+                                     JSDVG_SEARCH_STACK, arg, NullPtr(), "not an object", NULL);
             return JS_FALSE;
         }
 
         RootedObject config(cx, &arg.toObject());
 
         RootedValue prop(cx);
 
         /* config.loc */
@@ -3240,17 +3240,17 @@ reflect_parse(JSContext *cx, uint32_t ar
         RootedId builderId(cx, NameToId(cx->runtime->atomState.builderAtom));
         RootedValue nullValue(cx, NullValue());
         if (!baseops::GetPropertyDefault(cx, config, builderId, 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);
+                                         JSDVG_SEARCH_STACK, prop, NullPtr(), "not an object", NULL);
                 return JS_FALSE;
             }
             builder = &prop.toObject();
         }
     }
 
     /* Extract the builder methods first to report errors before parsing. */
     ASTSerializer serialize(cx, loc, filename, lineno);
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -435,31 +435,31 @@ ThisToStringForStringProto(JSContext *cx
         return call.thisv().toString();
 
     if (call.thisv().isObject()) {
         RootedObject obj(cx, &call.thisv().toObject());
         if (obj->isString()) {
             Rooted<jsid> id(cx, NameToId(cx->runtime->atomState.toStringAtom));
             if (ClassMethodIsNative(cx, obj, &StringClass, id, js_str_toString)) {
                 JSString *str = obj->asString().unbox();
-                call.thisv().setString(str);
+                call.setThis(StringValue(str));
                 return str;
             }
         }
     } else if (call.thisv().isNullOrUndefined()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CONVERT_TO,
                              call.thisv().isNull() ? "null" : "undefined", "object");
         return NULL;
     }
 
     JSString *str = ToStringSlow(cx, call.thisv());
     if (!str)
         return NULL;
 
-    call.thisv().setString(str);
+    call.setThis(StringValue(str));
     return str;
 }
 
 static bool
 IsString(const Value &v)
 {
     return v.isString() || (v.isObject() && v.toObject().hasClass(&StringClass));
 }
@@ -1017,17 +1017,17 @@ StringMatch(const jschar *text, uint32_t
                         :
 #endif
                           UnrolledMatch<ManualCmp>(text, textlen, pat, patlen);
 }
 
 static const size_t sRopeMatchThresholdRatioLog2 = 5;
 
 /*
- * RopeMatch takes the text to search, the patern to search for in the text.
+ * RopeMatch takes the text to search and the pattern to search for in the text.
  * RopeMatch returns false on OOM and otherwise returns the match index through
  * the 'match' outparam (-1 for not found).
  */
 static bool
 RopeMatch(JSContext *cx, JSString *textstr, const jschar *pat, uint32_t patlen, int *match)
 {
     JS_ASSERT(textstr->isRope());
 
@@ -1143,16 +1143,19 @@ str_contains(JSContext *cx, unsigned arg
         return false;
 
     // Step 5
     uint32_t textlen = str->length();
     const jschar *text = str->getChars(cx);
     if (!text)
         return false;
 
+    // XXX fix for moving GC.
+    SkipRoot skip(cx, &text);
+
     if (args.hasDefined(1)) {
         // Step 4
         double posDouble;
         if (!ToInteger(cx, args[1], &posDouble))
             return false;
 
         // Step 6
         text += uint32_t(Min(double(textlen), Max(0.0, posDouble)));
@@ -1320,16 +1323,19 @@ str_startsWith(JSContext *cx, unsigned a
         return false;
 
     // Step 5
     uint32_t textlen = str->length();
     const jschar *text = str->getChars(cx);
     if (!text)
         return false;
 
+    // XXX fix for moving GC.
+    SkipRoot skip(cx, &text);
+
     if (args.hasDefined(1)) {
         // Step 4
         double posDouble;
         if (!ToInteger(cx, args[1], &posDouble))
             return false;
 
         // Step 6
         uint32_t position = Min(double(textlen), Max(0.0, posDouble));
@@ -1363,16 +1369,19 @@ str_endsWith(JSContext *cx, unsigned arg
         return false;
 
     // Step 4
     uint32_t textlen = str->length();
     const jschar *text = str->getChars(cx);
     if (!text)
         return false;
 
+    // XXX fix for moving GC.
+    SkipRoot skip(cx, &text);
+
     if (args.hasDefined(1)) {
         // Step 5
         double endPosDouble;
         if (!ToInteger(cx, args[1], &endPosDouble))
             return false;
 
         // Step 6
         textlen = Min(double(textlen), Max(0.0, endPosDouble));
@@ -1973,17 +1982,17 @@ FindReplaceLength(JSContext *cx, RegExpS
         unsigned p = res->parenCount();
         unsigned argc = 1 + p + 2;
 
         InvokeArgsGuard &args = rdata.args;
         if (!args.pushed() && !cx->stack.pushInvokeArgs(cx, argc, &args))
             return false;
 
         args.setCallee(ObjectValue(*lambda));
-        args.thisv() = UndefinedValue();
+        args.setThis(UndefinedValue());
 
         /* Push $&, $1, $2, ... */
         unsigned argi = 0;
         if (!res->createLastMatch(cx, &args[argi++]))
             return false;
 
         for (size_t i = 0; i < res->parenCount(); ++i) {
             if (!res->createParen(cx, i + 1, &args[argi++]))
@@ -2291,18 +2300,18 @@ str_replace_flat_lambda(JSContext *cx, C
         return false;
 
     /* lambda(matchStr, matchStart, textstr) */
     static const uint32_t lambdaArgc = 3;
     if (!cx->stack.pushInvokeArgs(cx, lambdaArgc, &rdata.args))
         return false;
 
     CallArgs &args = rdata.args;
-    args.calleev().setObject(*rdata.lambda);
-    args.thisv().setUndefined();
+    args.setCallee(ObjectValue(*rdata.lambda));
+    args.setThis(UndefinedValue());
 
     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;
@@ -2764,17 +2773,17 @@ js::str_split(JSContext *cx, unsigned ar
     args.rval().setObject(*aobj);
     return true;
 }
 
 static JSBool
 str_substr(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    JSString *str = ThisToStringForStringProto(cx, args);
+    RootedString str(cx, ThisToStringForStringProto(cx, args));
     if (!str)
         return false;
 
     int32_t length, len, begin;
     if (args.length() > 0) {
         length = int32_t(str->length());
         if (!ValueToIntegerRange(cx, args[0], &begin))
             return false;
--- a/js/src/jsstrinlines.h
+++ b/js/src/jsstrinlines.h
@@ -41,33 +41,33 @@ class RopeBuilder {
 };
 
 class StringSegmentRange
 {
     /*
      * If malloc() shows up in any profiles from this vector, we can add a new
      * StackAllocPolicy which stashes a reusable freed-at-gc buffer in the cx.
      */
-    Vector<JSString *, 32> stack;
-    JSLinearString *cur;
+    AutoStringVector stack;
+    Rooted<JSLinearString*> cur;
 
     bool settle(JSString *str) {
         while (str->isRope()) {
             JSRope &rope = str->asRope();
             if (!stack.append(rope.rightChild()))
                 return false;
             str = rope.leftChild();
         }
         cur = &str->asLinear();
         return true;
     }
 
   public:
     StringSegmentRange(JSContext *cx)
-      : stack(cx), cur(NULL)
+      : stack(cx), cur(cx)
     {}
 
     JS_WARN_UNUSED_RESULT bool init(JSString *str) {
         JS_ASSERT(stack.empty());
         return settle(str);
     }
 
     bool empty() const {
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -138,36 +138,35 @@ ArrayBufferObject::byteLengthGetter(JSCo
 }
 
 bool
 ArrayBufferObject::fun_slice_impl(JSContext *cx, CallArgs args)
 {
     JS_ASSERT(IsArrayBuffer(args.thisv()));
 
     Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
-    ArrayBufferObject &arrayBuffer = thisObj->asArrayBuffer();
 
     // these are the default values
-    uint32_t length = arrayBuffer.byteLength();
+    uint32_t length = thisObj->asArrayBuffer().byteLength();
     uint32_t begin = 0, end = length;
 
     if (args.length() > 0) {
         if (!ToClampedIndex(cx, args[0], length, &begin))
             return false;
 
         if (args.length() > 1) {
             if (!ToClampedIndex(cx, args[1], length, &end))
                 return false;
         }
     }
 
     if (begin > end)
         begin = end;
 
-    JSObject *nobj = createSlice(cx, arrayBuffer, begin, end);
+    JSObject *nobj = createSlice(cx, thisObj->asArrayBuffer(), begin, end);
     if (!nobj)
         return false;
     args.rval().setObject(*nobj);
     return true;
 }
 
 JSBool
 ArrayBufferObject::fun_slice(JSContext *cx, unsigned argc, Value *vp)
@@ -1673,18 +1672,18 @@ class TypedArrayTemplate
                 Rooted<JSObject*> proto(cx, GetProtoForClass(cx, fastClass()));
                 if (!proto)
                     return NULL;
 
                 InvokeArgsGuard ag;
                 if (!cx->stack.pushInvokeArgs(cx, 3, &ag))
                     return NULL;
 
-                ag.calleev() = cx->compartment->maybeGlobal()->createArrayFromBuffer<NativeType>();
-                ag.thisv() = ObjectValue(*bufobj);
+                ag.setCallee(cx->compartment->maybeGlobal()->createArrayFromBuffer<NativeType>());
+                ag.setThis(ObjectValue(*bufobj));
                 ag[0] = Int32Value(byteOffsetInt);
                 ag[1] = Int32Value(lengthInt);
                 ag[2] = ObjectValue(*proto);
 
                 if (!Invoke(cx, ag))
                     return NULL;
                 return &ag.rval().toObject();
             }
@@ -2257,18 +2256,18 @@ DataViewObject::class_constructor(JSCont
         Rooted<GlobalObject*> global(cx, cx->compartment->maybeGlobal());
         Rooted<JSObject*> proto(cx, global->getOrCreateDataViewPrototype(cx));
         if (!proto)
             return false;
 
         InvokeArgsGuard ag;
         if (!cx->stack.pushInvokeArgs(cx, argc + 1, &ag))
             return false;
-        ag.calleev() = global->createDataViewForThis();
-        ag.thisv() = ObjectValue(*bufobj);
+        ag.setCallee(global->createDataViewForThis());
+        ag.setThis(ObjectValue(*bufobj));
         PodCopy(ag.array(), args.array(), args.length());
         ag[argc] = ObjectValue(*proto);
         if (!Invoke(cx, ag))
             return false;
         args.rval().set(ag.rval());
         return true;
     }
 
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -200,17 +200,17 @@ static JSPropertySpec namespace_props[] 
     {js_prefix_str, 0, NAMESPACE_ATTRS, JSOP_WRAPPER(NamePrefix_getter), JSOP_NULLWRAPPER},
     {js_uri_str,    0, NAMESPACE_ATTRS, JSOP_WRAPPER(NameURI_getter), JSOP_NULLWRAPPER},
     {0,0,0,JSOP_NULLWRAPPER, JSOP_NULLWRAPPER}
 };
 
 static JSBool
 namespace_toString(JSContext *cx, unsigned argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    JSObject *obj = ToObject(cx, HandleValue::fromMarkedLocation(&vp[1]));
     if (!obj)
         return JS_FALSE;
     if (!obj->isNamespace()) {
         ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &NamespaceClass);
         return JS_FALSE;
     }
     *vp = obj->getNameURIVal();
     return JS_TRUE;
@@ -390,17 +390,17 @@ ConvertQNameToString(JSContext *cx, JSOb
         }
     }
     return str;
 }
 
 static JSBool
 qname_toString(JSContext *cx, unsigned argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    JSObject *obj = ToObject(cx, HandleValue::fromMarkedLocation(&vp[1]));
     if (!obj)
         return false;
 
     if (!obj->isQName()) {
         ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &QNameClass);
         return false;
     }
 
@@ -1892,18 +1892,19 @@ ToXML(JSContext *cx, jsval v)
             return NULL;
     } else {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_SYNTAX_ERROR);
         return NULL;
     }
     return obj;
 
 bad:
+    RootedValue val(cx, v);
     js_ReportValueError(cx, JSMSG_BAD_XML_CONVERSION,
-                        JSDVG_IGNORE_STACK, v, NULL);
+                        JSDVG_IGNORE_STACK, val, NullPtr());
     return NULL;
 }
 
 static JSBool
 Append(JSContext *cx, JSXML *list, JSXML *kid);
 
 static JSObject *
 ToXMLList(JSContext *cx, jsval v)
@@ -1968,18 +1969,19 @@ ToXMLList(JSContext *cx, jsval v)
                 break;
             }
         }
     }
 
     return listobj;
 
 bad:
+    RootedValue val(cx, v);
     js_ReportValueError(cx, JSMSG_BAD_XMLLIST_CONVERSION,
-                        JSDVG_IGNORE_STACK, v, NULL);
+                        JSDVG_IGNORE_STACK, val, NullPtr());
     return NULL;
 }
 
 /*
  * ECMA-357 10.2.1 Steps 5-7 pulled out as common subroutines of XMLToXMLString
  * and their library-public js_* counterparts.  The guts of MakeXMLCDataString,
  * MakeXMLCommentString, and MakeXMLPIString are further factored into a common
  * MakeXMLSpecialString subroutine.
@@ -2784,18 +2786,19 @@ ToAttributeName(JSContext *cx, jsval v)
     JSAtom *name;
     if (JSVAL_IS_STRING(v)) {
         name = ToAtom(cx, v);
         if (!name)
             return NULL;
         uri = prefix = cx->runtime->emptyString;
     } else {
         if (JSVAL_IS_PRIMITIVE(v)) {
+            RootedValue val(cx, v);
             js_ReportValueError(cx, JSMSG_BAD_XML_ATTR_NAME,
-                                JSDVG_IGNORE_STACK, v, NULL);
+                                JSDVG_IGNORE_STACK, val, NullPtr());
             return NULL;
         }
 
         obj = JSVAL_TO_OBJECT(v);
         clasp = obj->getClass();
         if (clasp == &AttributeNameClass)
             return obj;
 
@@ -2820,17 +2823,18 @@ ToAttributeName(JSContext *cx, jsval v)
     if (!qn)
         return NULL;
     return qn;
 }
 
 static void
 ReportBadXMLName(JSContext *cx, const Value &idval)
 {
-    js_ReportValueError(cx, JSMSG_BAD_XML_NAME, JSDVG_IGNORE_STACK, idval, NULL);
+    RootedValue val(cx, idval);
+    js_ReportValueError(cx, JSMSG_BAD_XML_NAME, JSDVG_IGNORE_STACK, val, NullPtr());
 }
 
 namespace js {
 
 bool
 GetLocalNameFromFunctionQName(JSObject *qn, JSAtom **namep, JSContext *cx)
 {
     JSAtom *atom = cx->runtime->atomState.functionNamespaceURIAtom;
@@ -5367,17 +5371,17 @@ StartNonListXMLMethod(JSContext *cx, jsv
 {
     JSXML *xml;
     JSFunction *fun;
     char numBuf[12];
 
     JS_ASSERT(!JSVAL_IS_PRIMITIVE(*vp));
     JS_ASSERT(JSVAL_TO_OBJECT(*vp)->isFunction());
 
-    objp.set(ToObject(cx, &vp[1]));
+    objp.set(ToObject(cx, HandleValue::fromMarkedLocation(&vp[1])));
     if (!objp)
         return NULL;
     if (!objp->isXML()) {
         ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &XMLClass);
         return NULL;
     }
     xml = (JSXML *) objp->getPrivate();
     if (!xml || xml->xml_class != JSXML_CLASS_LIST)
@@ -5401,17 +5405,17 @@ StartNonListXMLMethod(JSContext *cx, jsv
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NON_LIST_XML_METHOD,
                              funName, numBuf);
     }
     return NULL;
 }
 
 /* Beware: these two are not bracketed by JS_BEGIN/END_MACRO. */
 #define XML_METHOD_PROLOG                                                     \
-    JSObject *obj = ToObject(cx, &vp[1]);                                     \
+    JSObject *obj = ToObject(cx, HandleValue::fromMarkedLocation(&vp[1]));                                     \
     if (!obj)                                                                 \
         return JS_FALSE;                                                      \
     if (!obj->isXML()) {                                                      \
         ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &XMLClass);      \
         return JS_FALSE;                                                      \
     }                                                                         \
     JSXML *xml = (JSXML *)obj->getPrivate();                                  \
     if (!xml)                                                                 \
@@ -5485,43 +5489,44 @@ xml_appendChild(JSContext *cx, unsigned 
 
 /* XML and XMLList */
 static JSBool
 xml_attribute(JSContext *cx, unsigned argc, jsval *vp)
 {
     JSObject *qn;
 
     if (argc == 0) {
-        js_ReportMissingArg(cx, *vp, 0);
+        RootedValue val(cx, *vp);
+        js_ReportMissingArg(cx, val, 0);
         return JS_FALSE;
     }
 
     qn = ToAttributeName(cx, vp[2]);
     if (!qn)
         return JS_FALSE;
     vp[2] = OBJECT_TO_JSVAL(qn);        /* local root */
 
     RootedId id(cx, OBJECT_TO_JSID(qn));
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, HandleValue::fromMarkedLocation(&vp[1])));
     if (!obj)
         return JS_FALSE;
     return GetProperty(cx, obj, id, MutableHandleValue::fromMarkedLocation(vp));
 }
 
 /* XML and XMLList */
 static JSBool
 xml_attributes(JSContext *cx, unsigned argc, jsval *vp)
 {
     jsval name = STRING_TO_JSVAL(cx->runtime->atomState.starAtom);
     JSObject *qn = ToAttributeName(cx, name);
     if (!qn)
         return JS_FALSE;
 
     RootedId id(cx, OBJECT_TO_JSID(qn));
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, HandleValue::fromMarkedLocation(&vp[1])));
     if (!obj)
         return JS_FALSE;
     return GetProperty(cx, obj, id, MutableHandleValue::fromMarkedLocation(vp));
 }
 
 static JSXML *
 xml_list_helper(JSContext *cx, JSXML *xml, jsval *rval)
 {
@@ -5671,17 +5676,17 @@ xml_childIndex(JSContext *cx, unsigned a
         *vp = DOUBLE_TO_JSVAL(i);
     return JS_TRUE;
 }
 
 /* XML and XMLList */
 static JSBool
 xml_children(JSContext *cx, unsigned argc, jsval *vp)
 {
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, HandleValue::fromMarkedLocation(&vp[1])));
     if (!obj)
         return false;
     RootedId name(cx, NameToId(cx->runtime->atomState.starAtom));
     return GetProperty(cx, obj, name, MutableHandleValue::fromMarkedLocation(vp));
 }
 
 /* XML and XMLList */
 static JSBool
@@ -5878,17 +5883,17 @@ xml_elements(JSContext *cx, unsigned arg
 
 /* XML and XMLList */
 static JSBool
 xml_hasOwnProperty(JSContext *cx, unsigned argc, jsval *vp)
 {
     jsval name;
     JSBool found;
 
-    JSObject *obj = ToObject(cx, &vp[1]);
+    JSObject *obj = ToObject(cx, HandleValue::fromMarkedLocation(&vp[1]));
     if (!obj)
         return JS_FALSE;
     if (!obj->isXML()) {
         ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &XMLClass);
         return JS_FALSE;
     }
 
     name = argc != 0 ? vp[2] : JSVAL_VOID;
@@ -6920,17 +6925,17 @@ xml_toString_helper(JSContext *cx, JSXML
         }
     }
     return str;
 }
 
 static JSBool
 xml_toSource(JSContext *cx, unsigned argc, jsval *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    JSObject *obj = ToObject(cx, HandleValue::fromMarkedLocation(&vp[1]));
     if (!obj)
         return JS_FALSE;
     JSString *str = ToXMLString(cx, OBJECT_TO_JSVAL(obj), TO_SOURCE_FLAG);
     if (!str)
         return JS_FALSE;
     *vp = STRING_TO_JSVAL(str);
     return JS_TRUE;
 }
@@ -6947,31 +6952,31 @@ xml_toString(JSContext *cx, unsigned arg
     *vp = STRING_TO_JSVAL(str);
     return JS_TRUE;
 }
 
 /* XML and XMLList */
 static JSBool
 xml_toXMLString(JSContext *cx, unsigned argc, jsval *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    JSObject *obj = ToObject(cx, HandleValue::fromMarkedLocation(&vp[1]));
     if (!obj)
         return JS_FALSE;
     JSString *str = ToXMLString(cx, OBJECT_TO_JSVAL(obj), 0);
     if (!str)
         return JS_FALSE;
     *vp = STRING_TO_JSVAL(str);
     return JS_TRUE;
 }
 
 /* XML and XMLList */
 static JSBool
 xml_valueOf(JSContext *cx, unsigned argc, jsval *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    JSObject *obj = ToObject(cx, HandleValue::fromMarkedLocation(&vp[1]));
     if (!obj)
         return false;
     *vp = OBJECT_TO_JSVAL(obj);
     return true;
 }
 
 static JSFunctionSpec xml_methods[] = {
     JS_FN("addNamespace",          xml_addNamespace,          1,0),
@@ -7061,29 +7066,29 @@ SetDefaultXMLSettings(JSContext *cx, Han
 
 static JSBool
 xml_settings(JSContext *cx, unsigned argc, jsval *vp)
 {
     RootedObject settings(cx, JS_NewObject(cx, NULL, NULL, NULL));
     if (!settings)
         return false;
     *vp = OBJECT_TO_JSVAL(settings);
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, HandleValue::fromMarkedLocation(&vp[1])));
     if (!obj)
         return false;
     return CopyXMLSettings(cx, obj, settings);
 }
 
 static JSBool
 xml_setSettings(JSContext *cx, unsigned argc, jsval *vp)
 {
     jsval v;
     JSBool ok;
 
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, HandleValue::fromMarkedLocation(&vp[1])));
     if (!obj)
         return JS_FALSE;
     v = (argc == 0) ? JSVAL_VOID : vp[2];
     if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) {
         ok = SetDefaultXMLSettings(cx, obj);
     } else {
         if (JSVAL_IS_PRIMITIVE(v)) {
             vp[0] = JSVAL_VOID;
@@ -7877,17 +7882,18 @@ js_StepXMLListFilter(JSContext *cx, JSBo
 
     sp = cx->regs().sp;
     if (!initialized) {
         /*
          * We haven't iterated yet, so initialize the filter based on the
          * value stored in sp[-2].
          */
         if (!VALUE_IS_XML(sp[-2])) {
-            js_ReportValueError(cx, JSMSG_NON_XML_FILTER, -2, sp[-2], NULL);
+            RootedValue val(cx, sp[-2]);
+            js_ReportValueError(cx, JSMSG_NON_XML_FILTER, -2, val, NullPtr());
             return JS_FALSE;
         }
         obj = JSVAL_TO_OBJECT(sp[-2]);
         xml = (JSXML *) obj->getPrivate();
 
         if (xml->xml_class == JSXML_CLASS_LIST) {
             list = xml;
         } else {
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -1000,17 +1000,18 @@ js_InternalInterpret(void *returnData, v
         switch (op) {
           case JSOP_INSTANCEOF: {
             /*
              * If we recompiled from a getprop used within JSOP_INSTANCEOF,
              * the stack looks like 'LHS RHS protov'. Inline the remaining
              * portion of fun_hasInstance.
              */
             if (f.regs.sp[0].isPrimitive()) {
-                js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, f.regs.sp[-1], NULL);
+                RootedValue val(cx, f.regs.sp[-1]);
+                js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, val, NullPtr());
                 return js_InternalThrow(f);
             }
             nextsp[-1].setBoolean(js_IsDelegate(cx, &f.regs.sp[0].toObject(), f.regs.sp[-2]));
             f.regs.pc = nextpc;
             break;
           }
 
           default:
--- a/js/src/methodjit/MonoIC.cpp
+++ b/js/src/methodjit/MonoIC.cpp
@@ -766,17 +766,17 @@ class CallCompiler : public BaseCompiler
         RootedFunction fun(cx);
         if (!IsFunctionObject(args.calleev(), fun.address()))
             return false;
 
         if ((!callingNew && !fun->isNative()) || (callingNew && !fun->isNativeConstructor()))
             return false;
 
         if (callingNew)
-            args.thisv().setMagic(JS_IS_CONSTRUCTING);
+            args.setThis(MagicValue(JS_IS_CONSTRUCTING));
 
         RecompilationMonitor monitor(cx);
 
         if (!CallJSNative(cx, fun->native(), args))
             THROWV(true);
 
         types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
 
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -1943,52 +1943,54 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic
                     JSString *str = obj->asString().unbox();
                     f.regs.sp[-1].setInt32(str->length());
                 }
                 return;
             }
         }
     }
 
+    RootedValue objval(f.cx, f.regs.sp[-1]);
+
     if (f.regs.sp[-1].isString()) {
         GetPropCompiler cc(f, NULL, *pic, name, stub);
         if (name == f.cx->runtime->atomState.lengthAtom) {
             LookupStatus status = cc.generateStringLengthStub();
             if (status == Lookup_Error)
                 THROW();
             JSString *str = f.regs.sp[-1].toString();
             f.regs.sp[-1].setInt32(str->length());
         } else {
             LookupStatus status = cc.generateStringPropertyStub();
             if (status == Lookup_Error)
                 THROW();
-            JSObject *obj = ValueToObject(f.cx, f.regs.sp[-1]);
+            JSObject *obj = ToObjectFromStack(f.cx, objval);
             if (!obj)
                 THROW();
             if (!obj->getProperty(f.cx, name, MutableHandleValue::fromMarkedLocation(&f.regs.sp[-1])))
                 THROW();
         }
         return;
     }
 
     RecompilationMonitor monitor(f.cx);
 
-    RootedObject obj(f.cx, ValueToObject(f.cx, f.regs.sp[-1]));
+    RootedObject obj(f.cx, ToObjectFromStack(f.cx, objval));
     if (!obj)
         THROW();
 
     if (!monitor.recompiled() && pic->shouldUpdate(f)) {
         GetPropCompiler cc(f, obj, *pic, name, stub);
         if (!cc.update())
             THROW();
     }
 
     RootedValue v(f.cx);
     if (cached) {
-        if (!GetPropertyOperation(f.cx, f.script(), f.pc(), f.regs.sp[-1], v.address()))
+        if (!GetPropertyOperation(f.cx, f.pc(), &objval, &v))
             THROW();
     } else {
         if (!obj->getProperty(f.cx, name, &v))
             THROW();
     }
 
     f.regs.sp[-1] = v;
 }
@@ -2008,17 +2010,18 @@ ic::SetProp(VMFrame &f, ic::PICInfo *pic
     VoidStubPIC stub = STRICT_VARIANT(f.script(), DisabledSetPropIC);
 
     // Save this in case the compiler triggers a recompilation of this script.
     RootedPropertyName name(f.cx, pic->name);
     VoidStubName nstub = STRICT_VARIANT(f.script(), stubs::SetName);
 
     RecompilationMonitor monitor(f.cx);
 
-    JSObject *obj = ValueToObject(f.cx, f.regs.sp[-2]);
+    RootedValue objval(f.cx, f.regs.sp[-2]);
+    JSObject *obj = ToObjectFromStack(f.cx, objval);
     if (!obj)
         THROW();
 
     // Note, we can't use SetName for PROPINC PICs because the property
     // cache can't handle a GET and SET from the same scripted PC.
     if (!monitor.recompiled() && pic->shouldUpdate(f)) {
         SetPropCompiler cc(f, obj, *pic, name, stub);
         LookupStatus status = cc.update();
@@ -2545,22 +2548,22 @@ ic::GetElement(VMFrame &f, ic::GetElemen
 
     // Right now, we don't optimize for strings or lazy arguments.
     if (!f.regs.sp[-2].isObject()) {
         ic->disable(f, "non-object");
         stubs::GetElem(f);
         return;
     }
 
-    RootedValue idval_(cx, f.regs.sp[-1]);
-    Value &idval = idval_.get();
+    RootedValue idval(cx, f.regs.sp[-1]);
 
     RecompilationMonitor monitor(cx);
 
-    RootedObject obj(cx, ValueToObject(cx, f.regs.sp[-2]));
+    RootedValue objval(f.cx, f.regs.sp[-2]);
+    RootedObject obj(cx, ToObjectFromStack(cx, objval));
     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");
@@ -2578,17 +2581,17 @@ ic::GetElement(VMFrame &f, ic::GetElemen
     }
 
     MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&f.regs.sp[-2]);
 
     if (!monitor.recompiled() && ic->shouldUpdate(f)) {
 #ifdef DEBUG
         f.regs.sp[-2] = MagicValue(JS_GENERIC_MAGIC);
 #endif
-        LookupStatus status = ic->update(f, obj, idval_, id, res);
+        LookupStatus status = ic->update(f, obj, idval, id, res);
         if (status != Lookup_Uncacheable && status != Lookup_NoProperty) {
             if (status == Lookup_Error)
                 THROW();
 
             // If the result can be cached, the value was already retrieved.
             JS_ASSERT(!f.regs.sp[-2].isMagic());
             return;
         }
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -67,18 +67,18 @@ stubs::BindGlobalName(VMFrame &f)
     return &f.fp()->global();
 }
 
 template<JSBool strict>
 void JS_FASTCALL
 stubs::SetName(VMFrame &f, PropertyName *name)
 {
     JSContext *cx = f.cx;
-    const Value &rval = f.regs.sp[-1];
-    const Value &lval = f.regs.sp[-2];
+    HandleValue rval = HandleValue::fromMarkedLocation(&f.regs.sp[-1]);
+    HandleValue lval = HandleValue::fromMarkedLocation(&f.regs.sp[-2]);
 
     if (!SetPropertyOperation(cx, f.pc(), lval, rval))
         THROW();
 
     f.regs.sp[-2] = f.regs.sp[-1];
 }
 
 template void JS_FASTCALL stubs::SetName<true>(VMFrame &f, PropertyName *origName);
@@ -101,38 +101,38 @@ stubs::Name(VMFrame &f)
     if (!NameOperation(f.cx, f.script(), f.pc(), &rval))
         THROW();
     f.regs.sp[0] = rval;
 }
 
 void JS_FASTCALL
 stubs::GetElem(VMFrame &f)
 {
-    Value &lref = f.regs.sp[-2];
-    Value &rref = f.regs.sp[-1];
+    MutableHandleValue lval = MutableHandleValue::fromMarkedLocation(&f.regs.sp[-2]);
+    HandleValue rval = HandleValue::fromMarkedLocation(&f.regs.sp[-1]);
     MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&f.regs.sp[-2]);
 
-    if (!GetElementOperation(f.cx, JSOp(*f.pc()), lref, rref, res))
+    if (!GetElementOperation(f.cx, JSOp(*f.pc()), lval, rval, res))
         THROW();
 }
 
 template<JSBool strict>
 void JS_FASTCALL
 stubs::SetElem(VMFrame &f)
 {
     JSContext *cx = f.cx;
     FrameRegs &regs = f.regs;
 
-    Value &objval = regs.sp[-3];
+    HandleValue objval = HandleValue::fromMarkedLocation(&regs.sp[-3]);
     Value &idval  = regs.sp[-2];
     RootedValue rval(cx, regs.sp[-1]);
 
     RootedId id(cx);
 
-    Rooted<JSObject*> obj(cx, ValueToObject(cx, objval));
+    Rooted<JSObject*> obj(cx, ToObjectFromStack(cx, objval));
     if (!obj)
         THROW();
 
     if (!FetchElementId(f.cx, obj, idval, id.address(),
                         MutableHandleValue::fromMarkedLocation(&regs.sp[-2])))
     {
         THROW();
     }
@@ -169,20 +169,20 @@ stubs::SetElem(VMFrame &f)
 }
 
 template void JS_FASTCALL stubs::SetElem<true>(VMFrame &f);
 template void JS_FASTCALL stubs::SetElem<false>(VMFrame &f);
 
 void JS_FASTCALL
 stubs::ToId(VMFrame &f)
 {
-    Value &objval = f.regs.sp[-2];
+    HandleValue objval = HandleValue::fromMarkedLocation(&f.regs.sp[-2]);
     MutableHandleValue idval = MutableHandleValue::fromMarkedLocation(&f.regs.sp[-1]);
 
-    JSObject *obj = ValueToObject(f.cx, objval);
+    JSObject *obj = ToObjectFromStack(f.cx, objval);
     if (!obj)
         THROW();
 
     RootedId id(f.cx);
     if (!FetchElementId(f.cx, obj, idval, id.address(), idval))
         THROW();
 
     if (!idval.isInt32())
@@ -978,18 +978,20 @@ stubs::Lambda(VMFrame &f, JSFunction *fu
 }
 
 void JS_FASTCALL
 stubs::GetProp(VMFrame &f, PropertyName *name)
 {
     JSContext *cx = f.cx;
     FrameRegs &regs = f.regs;
 
+    MutableHandleValue objval = MutableHandleValue::fromMarkedLocation(&f.regs.sp[-1]);
+
     RootedValue rval(cx);
-    if (!GetPropertyOperation(cx, f.script(), f.pc(), f.regs.sp[-1], rval.address()))
+    if (!GetPropertyOperation(cx, f.pc(), objval, &rval))
         THROW();
 
     regs.sp[-1] = rval;
 }
 
 void JS_FASTCALL
 stubs::GetPropNoCache(VMFrame &f, PropertyName *name)
 {
@@ -1137,20 +1139,20 @@ stubs::Arguments(VMFrame &f)
 }
 
 JSBool JS_FASTCALL
 stubs::InstanceOf(VMFrame &f)
 {
     JSContext *cx = f.cx;
     FrameRegs &regs = f.regs;
 
-    const Value &rref = regs.sp[-1];
+    RootedValue rref(cx, regs.sp[-1]);
     if (rref.isPrimitive()) {
         js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
-                            -1, rref, NULL);
+                            -1, rref, NullPtr());
         THROWV(JS_FALSE);
     }
     RootedObject obj(cx, &rref.toObject());
     const Value &lref = regs.sp[-2];
     JSBool cond = JS_FALSE;
     if (!HasInstance(cx, obj, &lref, &cond))
         THROWV(JS_FALSE);
     f.regs.sp[-2].setBoolean(cond);
@@ -1162,17 +1164,18 @@ stubs::FastInstanceOf(VMFrame &f)
 {
     const Value &lref = f.regs.sp[-1];
 
     if (lref.isPrimitive()) {
         /*
          * Throw a runtime error if instanceof is called on a function that
          * has a non-object as its .prototype value.
          */
-        js_ReportValueError(f.cx, JSMSG_BAD_PROTOTYPE, -1, f.regs.sp[-2], NULL);
+        RootedValue val(f.cx, f.regs.sp[-2]);
+        js_ReportValueError(f.cx, JSMSG_BAD_PROTOTYPE, -1, val, NullPtr());
         THROW();
     }
 
     f.regs.sp[-3].setBoolean(js_IsDelegate(f.cx, &lref.toObject(), f.regs.sp[-3]));
 }
 
 void JS_FASTCALL
 stubs::EnterBlock(VMFrame &f, JSObject *obj)
@@ -1360,17 +1363,18 @@ stubs::DelName(VMFrame &f, PropertyName 
 
 template<JSBool strict>
 void JS_FASTCALL
 stubs::DelProp(VMFrame &f, PropertyName *name_)
 {
     JSContext *cx = f.cx;
     RootedPropertyName name(cx, name_);
 
-    JSObject *obj = ValueToObject(cx, f.regs.sp[-1]);
+    RootedValue objval(cx, f.regs.sp[-1]);
+    JSObject *obj = ToObjectFromStack(cx, objval);
     if (!obj)
         THROW();
 
     RootedValue rval(cx);
     if (!obj->deleteProperty(cx, name, &rval, strict))
         THROW();
 
     f.regs.sp[-1] = rval;
@@ -1380,17 +1384,18 @@ template void JS_FASTCALL stubs::DelProp
 template void JS_FASTCALL stubs::DelProp<false>(VMFrame &f, PropertyName *name);
 
 template<JSBool strict>
 void JS_FASTCALL
 stubs::DelElem(VMFrame &f)
 {
     JSContext *cx = f.cx;
 
-    JSObject *obj = ValueToObject(cx, f.regs.sp[-2]);
+    RootedValue objval(cx, f.regs.sp[-2]);
+    JSObject *obj = ToObjectFromStack(cx, objval);
     if (!obj)
         THROW();
 
     const Value &propval = f.regs.sp[-1];
     MutableHandleValue rval = MutableHandleValue::fromMarkedLocation(&f.regs.sp[-2]);
 
     if (!obj->deleteByValue(cx, propval, rval, strict))
         THROW();
@@ -1429,17 +1434,18 @@ stubs::SetConst(VMFrame &f, PropertyName
 
 JSBool JS_FASTCALL
 stubs::In(VMFrame &f)
 {
     JSContext *cx = f.cx;
 
     const Value &rref = f.regs.sp[-1];
     if (!rref.isObject()) {
-        js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, NULL);
+        RootedValue val(cx, rref);
+        js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, val, NullPtr());
         THROWV(JS_FALSE);
     }
 
     RootedObject obj(cx, &rref.toObject());
     RootedId id(cx);
     if (!FetchElementId(f.cx, obj, f.regs.sp[-2], id.address(),
                         MutableHandleValue::fromMarkedLocation(&f.regs.sp[-2])))
     {
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -2529,19 +2529,19 @@ NewSandbox(JSContext *cx, bool lazy)
     if (!cx->compartment->wrap(cx, obj.address()))
         return NULL;
     return obj;
 }
 
 static JSBool
 EvalInContext(JSContext *cx, unsigned argc, jsval *vp)
 {
-    JSString *str;
+    RootedString str(cx);
     RootedObject sobj(cx);
-    if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "S / o", &str, sobj.address()))
+    if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "S / o", str.address(), sobj.address()))
         return false;
 
     size_t srclen;
     const jschar *src = JS_GetStringCharsAndLength(cx, str, &srclen);
     if (!src)
         return false;
 
     SkipRoot skip(cx, &src);
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -100,18 +100,19 @@ ReportObjectRequired(JSContext *cx)
 
 bool
 ValueToIdentifier(JSContext *cx, const Value &v, jsid *idp)
 {
     jsid id;
     if (!ValueToId(cx, v, &id))
         return false;
     if (!JSID_IS_ATOM(id) || !IsIdentifier(JSID_TO_ATOM(id))) {
+        RootedValue val(cx, v);
         js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
-                                 JSDVG_SEARCH_STACK, v, NULL, "not an identifier", NULL);
+                                 JSDVG_SEARCH_STACK, val, NullPtr(), "not an identifier", NULL);
         return false;
     }
     *idp = id;
     return true;
 }
 
 /*
  * A range of all the Debugger.Frame objects for a particular StackFrame.
@@ -1467,17 +1468,16 @@ Debugger::sweepAll(FreeOp *fop)
             /*
              * dbg is being GC'd. Detach it from its debuggees. The debuggee
              * might be GC'd too. Since detaching requires access to both
              * objects, this must be done before finalize time.
              */
             for (GlobalObjectSet::Enum e(dbg->debuggees); !e.empty(); e.popFront())
                 dbg->removeDebuggeeGlobal(fop, e.front(), NULL, &e);
         }
-
     }
 
     for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); c++) {
         /* For each debuggee being GC'd, detach it from all its debuggers. */
         GlobalObjectSet &debuggees = (*c)->getDebuggees();
         for (GlobalObjectSet::Enum e(debuggees); !e.empty(); e.popFront()) {
             GlobalObject *global = e.front();
             if (!IsObjectMarked(&global))
@@ -1966,22 +1966,28 @@ Debugger::removeDebuggeeGlobal(FreeOp *f
     }
     JS_ASSERT(p != v->end());
 
     /*
      * The relation must be removed from up to three places: *v and debuggees
      * for sure, and possibly the compartment's debuggee set.
      */
     v->erase(p);
-    if (v->empty())
-        global->compartment()->removeDebuggee(fop, global, compartmentEnum);
     if (debugEnum)
         debugEnum->removeFront();
     else
         debuggees.remove(global);
+
+    /*
+     * The debuggee needs to be removed from the compartment last, as this can
+     * trigger GCs if the compartment's debug mode is being changed, and the
+     * global cannot be rooted on the stack without a cx.
+     */
+    if (v->empty())
+        global->compartment()->removeDebuggee(fop, global, compartmentEnum);
 }
 
 /*
  * A class for parsing 'findScripts' query arguments and searching for
  * scripts that match the criteria they represent.
  */
 class Debugger::ScriptQuery {
   public:
@@ -3166,17 +3172,17 @@ DebuggerArguments_getArg(JSContext *cx, 
                              "Arguments", "getArgument", argsobj->getClass()->name);
         return false;
     }
 
     /*
      * Put the Debugger.Frame into the this-value slot, then use THIS_FRAME
      * to check that it is still live and get the fp.
      */
-    args.thisv() = argsobj->getReservedSlot(JSSLOT_DEBUGARGUMENTS_FRAME);
+    args.setThis(argsobj->getReservedSlot(JSSLOT_DEBUGARGUMENTS_FRAME));
     THIS_FRAME(cx, argc, vp, "get argument", ca2, thisobj, fp);
 
     /*
      * Since getters can be extracted and applied to other objects,
      * there is no guarantee this object has an ith argument.
      */
     JS_ASSERT(i >= 0);
     Value arg;
@@ -3902,17 +3908,19 @@ DebuggerObject_defineProperty(JSContext 
     return true;
 }
 
 static JSBool
 DebuggerObject_defineProperties(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "defineProperties", args, dbg, obj);
     REQUIRE_ARGC("Debugger.Object.defineProperties", 1);
-    RootedObject props(cx, ToObject(cx, &args[0]));
+
+    RootedValue arg(cx, args[0]);
+    RootedObject props(cx, ToObject(cx, arg));
     if (!props)
         return false;
 
     AutoIdVector ids(cx);
     AutoPropDescArrayRooter descs(cx);
     if (!ReadPropertyDescriptors(cx, props, false, &ids, &descs))
         return false;
     size_t n = ids.length();
--- a/js/src/vm/ObjectImpl.cpp
+++ b/js/src/vm/ObjectImpl.cpp
@@ -413,20 +413,21 @@ DenseElementsHeader::defineElement(JSCon
     /*
      * If the element doesn't exist, we can only add it if the object is
      * extensible.
      */
     if (!obj->isExtensible()) {
         *succeeded = false;
         if (!shouldThrow)
             return true;
+        RootedValue val(cx, ObjectValue(*obj));
         MOZ_ALWAYS_FALSE(js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_OBJECT_NOT_EXTENSIBLE,
                                                   JSDVG_IGNORE_STACK,
-                                                  ObjectValue(*obj),
-                                                  NULL, NULL, NULL));
+                                                  val, NullPtr(),
+                                                  NULL, NULL));
         return false;
     }
 
     /* Otherwise we ensure space for it exists and that it's initialized. */
     ObjectImpl::DenseElementsResult res = obj->ensureDenseElementsInitialized(cx, index, 0);
 
     /* Propagate any error. */
     if (res == ObjectImpl::Failure)
@@ -461,20 +462,21 @@ js::ArrayBufferDelegate(JSContext *cx, H
 template <typename T>
 bool
 TypedElementsHeader<T>::defineElement(JSContext *cx, Handle<ObjectImpl*> obj,
                                       uint32_t index, const PropDesc &desc, bool shouldThrow,
                                       unsigned resolveFlags, bool *succeeded)
 {
     /* XXX jwalden This probably isn't how typed arrays should behave... */
     *succeeded = false;
+
+    RootedValue val(cx, ObjectValue(*obj));
     js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_OBJECT_NOT_EXTENSIBLE,
                              JSDVG_IGNORE_STACK,
-                             ObjectValue(*obj),
-                             NULL, NULL, NULL);
+                             val, NullPtr(), NULL, NULL);
     return false;
 }
 
 bool
 ArrayBufferElementsHeader::defineElement(JSContext *cx, Handle<ObjectImpl*> obj,
                                          uint32_t index, const PropDesc &desc, bool shouldThrow,
                                          unsigned resolveFlags, bool *succeeded)
 {
@@ -624,18 +626,18 @@ js::GetElement(JSContext *cx, Handle<Obj
                 return true;
             }
 
             InvokeArgsGuard args;
             if (!cx->stack.pushInvokeArgs(cx, 0, &args))
                 return false;
 
             /* Push get, receiver, and no args. */
-            args.calleev() = get;
-            args.thisv() = ObjectValue(*current);
+            args.setCallee(get);
+            args.setThis(ObjectValue(*current));
 
             bool ok = Invoke(cx, args);
             *vp = args.rval();
             return ok;
         }
 
         /* Otherwise it's a PropertyOp-based property.  XXX handle this! */
         MOZ_NOT_REACHED("NYI: handle PropertyOp'd properties here");
@@ -856,18 +858,18 @@ js::SetElement(JSContext *cx, Handle<Obj
                     return true;
                 }
 
                 InvokeArgsGuard args;
                 if (!cx->stack.pushInvokeArgs(cx, 1, &args))
                     return false;
 
                 /* Push set, receiver, and v as the sole argument. */
-                args.calleev() = setter;
-                args.thisv() = ObjectValue(*current);
+                args.setCallee(setter);
+                args.setThis(ObjectValue(*current));
                 args[0] = v;
 
                 *succeeded = true;
                 return Invoke(cx, args);
             }
 
             MOZ_NOT_REACHED("NYI: setting PropertyOp-based property");
             return false;
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -1364,18 +1364,19 @@ class DebugScopeProxy : public BaseProxy
         }
 
         RootedObject scopeObj(cx, &scope);
         return GetPropertyNames(cx, scopeObj, JSITER_OWNONLY, &props);
     }
 
     bool delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp) MOZ_OVERRIDE
     {
+        RootedValue val(cx, IdToValue(id));
         return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_CANT_DELETE,
-                                        JSDVG_IGNORE_STACK, IdToValue(id), NULL,
+                                        JSDVG_IGNORE_STACK, val, NullPtr(),
                                         NULL, NULL);
     }
 
     bool enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props) MOZ_OVERRIDE
     {
         ScopeObject &scope = proxy->asDebugScope().scope();
 
         if (isMissingArgumentsBinding(scope) &&