Bug 833396 - Fix some rooting issues found by static analysis r=sphink
authorJon Coppeard <jcoppeard@mozilla.com>
Mon, 21 Jan 2013 17:41:49 +0000
changeset 119731 7227a6cb2e2ef1c81c973769bc35e02019032c44
parent 119730 7f0e88c3339bb68a647ae4ca95e46278d08bc05b
child 119732 781a5c27a1e5cbd639557c33139542661a99fa4e
push id24219
push userryanvm@gmail.com
push dateThu, 24 Jan 2013 17:36:06 +0000
treeherdermozilla-central@fa969919b1bb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssphink
bugs833396
milestone21.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
Bug 833396 - Fix some rooting issues found by static analysis r=sphink
js/src/jsdbgapi.cpp
js/src/jsfun.cpp
js/src/jsinfer.cpp
js/src/jsiter.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/json.cpp
js/src/jsopcode.cpp
js/src/jsproxy.cpp
js/src/jsscope.cpp
js/src/jsscript.cpp
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -81,18 +81,18 @@ js::ScriptDebugPrologue(JSContext *cx, A
             frame.setHookData(hook(cx, Jsvalify(frame.asStackFrame()), true, 0,
                                    cx->runtime->debugHooks.executeHookData));
     } else {
         if (JSInterpreterHook hook = cx->runtime->debugHooks.callHook)
             frame.setHookData(hook(cx, Jsvalify(frame.asStackFrame()), true, 0,
                                    cx->runtime->debugHooks.callHookData));
     }
 
-    Value rval;
-    JSTrapStatus status = Debugger::onEnterFrame(cx, &rval);
+    RootedValue rval(cx);
+    JSTrapStatus status = Debugger::onEnterFrame(cx, rval.address());
     switch (status) {
       case JSTRAP_CONTINUE:
         break;
       case JSTRAP_THROW:
         cx->setPendingException(rval);
         break;
       case JSTRAP_ERROR:
         cx->clearPendingException();
@@ -201,28 +201,32 @@ CheckDebugMode(JSContext *cx)
     if (!debugMode) {
         JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage,
                                      NULL, JSMSG_NEED_DEBUG_MODE);
     }
     return debugMode;
 }
 
 JS_PUBLIC_API(JSBool)
-JS_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep)
+JS_SetSingleStepMode(JSContext *cx, JSScript *scriptArg, JSBool singleStep)
 {
+    RootedScript script(cx, scriptArg);
     assertSameCompartment(cx, script);
+
     if (!CheckDebugMode(cx))
         return JS_FALSE;
 
     return script->setStepModeFlag(cx, singleStep);
 }
 
 JS_PUBLIC_API(JSBool)
-JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc, JSTrapHandler handler, jsval closure)
+JS_SetTrap(JSContext *cx, JSScript *scriptArg, jsbytecode *pc, JSTrapHandler handler, jsval closureArg)
 {
+    RootedScript script(cx, scriptArg);
+    RootedValue closure(cx, closureArg);
     assertSameCompartment(cx, script, closure);
 
     if (!CheckDebugMode(cx))
         return false;
 
     BreakpointSite *site = script->getOrCreateBreakpointSite(cx, pc);
     if (!site)
         return false;
@@ -281,20 +285,18 @@ JS_ClearInterrupt(JSRuntime *rt, JSInter
 /************************************************************************/
 
 JS_PUBLIC_API(JSBool)
 JS_SetWatchPoint(JSContext *cx, JSObject *obj_, jsid id,
                  JSWatchPointHandler handler, JSObject *closure_)
 {
     assertSameCompartment(cx, obj_);
 
-    RootedObject obj(cx, obj_), closure(cx, closure_);
-
-    JSObject *origobj = obj;
-    obj = GetInnerObject(cx, obj);
+    RootedObject origobj(cx, obj_), closure(cx, closure_);
+    RootedObject obj(cx, GetInnerObject(cx, origobj));
     if (!obj)
         return false;
 
     RootedValue v(cx);
     unsigned attrs;
 
     RootedId propid(cx);
 
@@ -826,17 +828,17 @@ static JSBool
 GetPropertyDesc(JSContext *cx, JSObject *obj_, HandleShape shape, JSPropertyDesc *pd)
 {
     assertSameCompartment(cx, obj_);
     pd->id = IdToJsval(shape->propid());
 
     RootedObject obj(cx, obj_);
 
     JSBool wasThrowing = cx->isExceptionPending();
-    Value lastException = UndefinedValue();
+    RootedValue lastException(cx, UndefinedValue());
     if (wasThrowing)
         lastException = cx->getPendingException();
     cx->clearPendingException();
 
     Rooted<jsid> id(cx, shape->propid());
     RootedValue value(cx);
     if (!baseops::GetProperty(cx, obj, id, &value)) {
         if (!cx->isExceptionPending()) {
@@ -913,32 +915,39 @@ JS_GetPropertyDescArray(JSContext *cx, J
         pda->length = 0;
         pda->array = NULL;
         return true;
     }
 
     pd = cx->pod_malloc<JSPropertyDesc>(obj->propertyCount());
     if (!pd)
         return false;
-    for (Shape::Range r = obj->lastProperty()->all(); !r.empty(); r.popFront()) {
-        pd[i].id = JSVAL_NULL;
-        pd[i].value = JSVAL_NULL;
-        pd[i].alias = JSVAL_NULL;
-        if (!js_AddRoot(cx, &pd[i].id, NULL))
-            goto bad;
-        if (!js_AddRoot(cx, &pd[i].value, NULL))
-            goto bad;
-        RootedShape shape(cx, const_cast<Shape *>(&r.front()));
-        if (!GetPropertyDesc(cx, obj, shape, &pd[i]))
-            goto bad;
-        if ((pd[i].flags & JSPD_ALIAS) && !js_AddRoot(cx, &pd[i].alias, NULL))
-            goto bad;
-        if (++i == obj->propertyCount())
-            break;
+
+    {
+        Shape::Range r(obj->lastProperty()->all());
+        Shape::Range::AutoRooter rooter(cx, &r);
+        RootedShape shape(cx);
+        for (; !r.empty(); r.popFront()) {
+            pd[i].id = JSVAL_NULL;
+            pd[i].value = JSVAL_NULL;
+            pd[i].alias = JSVAL_NULL;
+            if (!js_AddRoot(cx, &pd[i].id, NULL))
+                goto bad;
+            if (!js_AddRoot(cx, &pd[i].value, NULL))
+                goto bad;
+            shape = const_cast<Shape *>(&r.front());
+            if (!GetPropertyDesc(cx, obj, shape, &pd[i]))
+                goto bad;
+            if ((pd[i].flags & JSPD_ALIAS) && !js_AddRoot(cx, &pd[i].alias, NULL))
+                goto bad;
+            if (++i == obj->propertyCount())
+                break;
+        }
     }
+
     pda->length = i;
     pda->array = pd;
     return true;
 
 bad:
     pda->length = i + 1;
     pda->array = pd;
     JS_PutPropertyDescArray(cx, pda);
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -819,28 +819,26 @@ fun_toSource(JSContext *cx, unsigned arg
     args.rval().setString(str);
     return true;
 }
 #endif
 
 JSBool
 js_fun_call(JSContext *cx, unsigned argc, Value *vp)
 {
-    Value fval = vp[1];
+    RootedValue fval(cx, vp[1]);
 
     if (!js_IsCallable(fval)) {
         ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &FunctionClass);
         return false;
     }
 
     Value *argv = vp + 2;
-    Value thisv;
-    if (argc == 0) {
-        thisv.setUndefined();
-    } else {
+    RootedValue thisv(cx, UndefinedValue());
+    if (argc != 0) {
         thisv = argv[0];
 
         argc--;
         argv++;
     }
 
     /* Allocate stack space for fval, obj, and the args. */
     InvokeArgsGuard args;
@@ -1056,17 +1054,17 @@ JSFunction::initializeLazyScript(JSConte
     Rooted<JSFunction*> self(cx, this);
     return cx->runtime->cloneSelfHostedFunctionScript(cx, funName, self);
 }
 
 /* ES5 15.3.4.5.1 and 15.3.4.5.2. */
 JSBool
 js::CallOrConstructBoundFunction(JSContext *cx, unsigned argc, Value *vp)
 {
-    JSFunction *fun = vp[0].toObject().toFunction();
+    RootedFunction fun(cx, vp[0].toObject().toFunction());
     JS_ASSERT(fun->isBoundFunction());
 
     bool constructing = IsConstructing(vp);
 
     /* 15.3.4.5.1 step 1, 15.3.4.5.2 step 3. */
     unsigned argslen = fun->getBoundFunctionArgumentCount();
 
     if (argc + argslen > StackSpace::ARGS_LENGTH_MAX) {
@@ -1375,29 +1373,28 @@ js::Function(JSContext *cx, unsigned arg
 
 #ifdef DEBUG
     for (unsigned i = 0; i < formals.length(); ++i) {
         RawString str = formals[i];
         JS_ASSERT(str->asAtom().asPropertyName() == formals[i]);
     }
 #endif
 
-    JS::Anchor<JSString *> strAnchor(NULL);
-
     RootedString str(cx);
     if (!args.length())
         str = cx->runtime->emptyString;
     else
         str = ToString(cx, args[args.length() - 1]);
     if (!str)
         return false;
     JSStableString *stable = str->ensureStable(cx);
     if (!stable)
         return false;
-    strAnchor.set(str);
+
+    JS::Anchor<JSString *> strAnchor(str);
     StableCharPtr chars = stable->chars();
     size_t length = stable->length();
 
     /*
      * NB: (new Function) is not lexically closed by its caller, it's just an
      * anonymous function in the top-level scope that its constructor inhabits.
      * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
      * and so would a call to f from another top-level's script or function.
@@ -1566,17 +1563,17 @@ js_DefineFunction(JSContext *cx, HandleO
         return NULL;
 
     return fun;
 }
 
 void
 js::ReportIncompatibleMethod(JSContext *cx, CallReceiver call, Class *clasp)
 {
-    Value thisv = call.thisv();
+    RootedValue thisv(cx, call.thisv());
 
 #ifdef DEBUG
     if (thisv.isObject()) {
         JS_ASSERT(thisv.toObject().getClass() != clasp ||
                   !thisv.toObject().isNative() ||
                   !thisv.toObject().getProto() ||
                   thisv.toObject().getProto()->getClass() != clasp);
     } else if (thisv.isString()) {
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -1045,18 +1045,18 @@ GetSingletonPropertyType(JSContext *cx, 
             return Type::Int32Type();
         obj = obj->getProto();
     }
 
     while (obj) {
         if (!obj->isNative())
             return Type::UnknownType();
 
-        Value v;
-        if (HasDataProperty(cx, obj, id, &v)) {
+        RootedValue v(cx);
+        if (HasDataProperty(cx, obj, id, v.address())) {
             if (v.isUndefined())
                 return Type::UnknownType();
             return GetValueType(cx, v);
         }
 
         obj = obj->getProto();
     }
 
@@ -2399,17 +2399,16 @@ TypeCompartment::addAllocationSiteTypeOb
             res = p->value;
     }
 
     if (!res) {
         RootedObject proto(cx);
         if (!js_GetClassPrototype(cx, key.kind, &proto, NULL))
             return NULL;
 
-        RootedScript keyScript(cx, key.script);
         Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
         res = newTypeObject(cx, GetClassForProtoKey(key.kind), tagged);
         if (!res) {
             cx->compartment->types.setPendingNukeTypes(cx);
             return NULL;
         }
         key.script = keyScript;
     }
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -50,16 +50,18 @@
 #include "vm/Stack-inl.h"
 #include "vm/String-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
 using mozilla::ArrayLength;
 
+typedef Rooted<PropertyIteratorObject*> RootedPropertyIteratorObject;
+
 static const gc::AllocKind ITERATOR_FINALIZE_KIND = gc::FINALIZE_OBJECT2;
 
 void
 NativeIterator::mark(JSTracer *trc)
 {
     for (HeapPtr<JSFlatString> *str = begin(); str < end(); str++)
         MarkString(trc, str, "prop");
     if (obj)
@@ -1069,17 +1071,17 @@ js::UnwindIteratorForUncatchableExceptio
  * argument is an object which can be called on an id and returns true or
  * false. It also must have a method |matchesAtMostOne| which allows us to
  * stop searching after the first deletion if true.
  */
 template<typename StringPredicate>
 static bool
 SuppressDeletedPropertyHelper(JSContext *cx, HandleObject obj, StringPredicate predicate)
 {
-    PropertyIteratorObject *iterobj = cx->enumerators;
+    RootedPropertyIteratorObject iterobj(cx, cx->enumerators);
     while (iterobj) {
       again:
         NativeIterator *ni = iterobj->getNativeIterator();
         /* This only works for identified surpressed keys, not values. */
         if (ni->isKeyIter() && ni->obj == obj && ni->props_cursor < ni->props_end) {
             /* Check whether id is still to come. */
             HeapPtr<JSFlatString> *props_cursor = ni->current();
             HeapPtr<JSFlatString> *props_end = ni->end();
@@ -1556,17 +1558,17 @@ SendToGenerator(JSContext *cx, JSGenerat
          * or else we might fail to scan some generator values.
          */
         gen->state = futureState;
 
         StackFrame *fp = gfg.fp();
         gen->regs = cx->regs();
 
         cx->enterGenerator(gen);   /* OOM check above. */
-        PropertyIteratorObject *enumerators = cx->enumerators;
+        RootedPropertyIteratorObject enumerators(cx, cx->enumerators);
         cx->enumerators = gen->enumerators;
 
         RootedScript script(cx, fp->script());
         ok = RunScript(cx, script, fp);
 
         gen->enumerators = cx->enumerators;
         cx->enumerators = enumerators;
         cx->leaveGenerator(gen);
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1057,16 +1057,17 @@ JSObject::sealOrFreeze(JSContext *cx, Ha
         for (Shape::Range r = obj->lastProperty()->all(); !r.empty(); r.popFront()) {
             if (!shapes.append(&r.front()))
                 return false;
         }
         Reverse(shapes.begin(), shapes.end());
 
         for (size_t i = 0; i < shapes.length(); i++) {
             StackShape child(shapes[i]);
+            StackShape::AutoRooter rooter(cx, &child);
             child.attrs |= getSealedOrFrozenAttributes(child.attrs, it);
 
             if (!JSID_IS_EMPTY(child.propid))
                 MarkTypePropertyConfigured(cx, obj, child.propid);
 
             last = cx->propertyTree().getChild(cx, last, obj->numFixedSlots(), child);
             if (!last)
                 return false;
@@ -1586,19 +1587,20 @@ JSObject::deleteByValue(JSContext *cx, H
     if (name->isIndex(&index))
         return deleteElement(cx, obj, index, rval, false);
 
     Rooted<PropertyName*> propname(cx, name->asPropertyName());
     return deleteProperty(cx, obj, propname, rval, false);
 }
 
 JS_FRIEND_API(bool)
-JS_CopyPropertiesFrom(JSContext *cx, JSObject *targetArg, JSObject *obj)
+JS_CopyPropertiesFrom(JSContext *cx, JSObject *targetArg, JSObject *objArg)
 {
     RootedObject target(cx, targetArg);
+    RootedObject obj(cx, objArg);
 
     // If we're not native, then we cannot copy properties.
     JS_ASSERT(target->isNative() == obj->isNative());
     if (!target->isNative())
         return true;
 
     AutoShapeVector shapes(cx);
     for (Shape::Range r(obj->lastProperty()); !r.empty(); r.popFront()) {
@@ -1626,17 +1628,17 @@ JS_CopyPropertiesFrom(JSContext *cx, JSO
         id = shape->propid();
         if (!JSObject::defineGeneric(cx, target, id, v, getter, setter, attrs))
             return false;
     }
     return true;
 }
 
 static bool
-CopySlots(JSContext *cx, JSObject *from, JSObject *to)
+CopySlots(JSContext *cx, HandleObject from, HandleObject to)
 {
     JS_ASSERT(!from->isNative() && !to->isNative());
     JS_ASSERT(from->getClass() == to->getClass());
 
     size_t n = 0;
     if (from->isWrapper() &&
         (Wrapper::wrapperHandler(from)->flags() &
          Wrapper::CROSS_COMPARTMENT)) {
@@ -1658,18 +1660,18 @@ CopySlots(JSContext *cx, JSObject *from,
 JSObject *
 js::CloneObject(JSContext *cx, HandleObject obj, Handle<js::TaggedProto> proto, HandleObject parent)
 {
     if (!obj->isNative() && !obj->isProxy()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_CANT_CLONE_OBJECT);
         return NULL;
     }
-    JSObject *clone = NewObjectWithGivenProto(cx, obj->getClass(),
-                                              proto, parent, obj->getAllocKind());
+    RootedObject clone(cx, NewObjectWithGivenProto(cx, obj->getClass(),
+                                                   proto, parent, obj->getAllocKind()));
     if (!clone)
         return NULL;
     if (obj->isNative()) {
         if (clone->isFunction() && (obj->compartment() != clone->compartment())) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_CANT_CLONE_OBJECT);
             return NULL;
         }
@@ -1716,19 +1718,21 @@ struct JSObject::TradeGutsReserved {
         if (newaslots)
             js_free(newaslots);
         if (newbslots)
             js_free(newbslots);
     }
 };
 
 bool
-JSObject::ReserveForTradeGuts(JSContext *cx, JSObject *a, JSObject *b,
+JSObject::ReserveForTradeGuts(JSContext *cx, JSObject *aArg, JSObject *bArg,
                               TradeGutsReserved &reserved)
 {
+    RootedObject a(cx, aArg);
+    RootedObject b(cx, bArg);
     AssertCanGC();
     JS_ASSERT(a->compartment() == b->compartment());
     AutoCompartment ac(cx, a);
 
     /*
      * When performing multiple swaps between objects which may have different
      * numbers of fixed slots, we reserve all space ahead of time so that the
      * swaps can be performed infallibly.
@@ -1746,25 +1750,23 @@ JSObject::ReserveForTradeGuts(JSContext 
         MarkChildren(comp->barrierTracer(), b);
     }
 #endif
 
     /*
      * Swap prototypes and classes on the two objects, so that TradeGuts can
      * preserve the types of the two objects.
      */
-    RootedObject na(cx, a);
-    RootedObject nb(cx, b);
     Class *aClass = a->getClass();
     Class *bClass = b->getClass();
     Rooted<TaggedProto> aProto(cx, a->getTaggedProto());
     Rooted<TaggedProto> bProto(cx, b->getTaggedProto());
-    if (!SetClassAndProto(cx, na, bClass, bProto, false))
+    if (!SetClassAndProto(cx, a, bClass, bProto, false))
         return false;
-    if (!SetClassAndProto(cx, nb, aClass, aProto, false))
+    if (!SetClassAndProto(cx, b, aClass, aProto, false))
         return false;
 
     if (a->sizeOfThis() == b->sizeOfThis())
         return true;
 
     /*
      * If either object is native, it needs a new shape to preserve the
      * invariant that objects with the same shape have the same number of
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -805,21 +805,21 @@ class JSObject : public js::ObjectImpl
                                          unsigned flags, int shortid)
     {
         js::RootedId id(cx, js::NameToId(name));
         return putProperty(cx, obj, id, getter, setter, slot, attrs, flags, shortid);
     }
 
     /* Change the given property into a sibling with the same id in this scope. */
     static js::UnrootedShape changeProperty(JSContext *cx, js::HandleObject obj,
-                                            js::RawShape shape, unsigned attrs, unsigned mask,
+                                            js::HandleShape shape, unsigned attrs, unsigned mask,
                                             JSPropertyOp getter, JSStrictPropertyOp setter);
 
     static inline bool changePropertyAttributes(JSContext *cx, js::HandleObject obj,
-                                                js::Shape *shape, unsigned attrs);
+                                                js::HandleShape shape, unsigned attrs);
 
     /* Remove the property named by id from this object. */
     bool removeProperty(JSContext *cx, jsid id);
 
     /* Clear the scope, making it empty. */
     static void clear(JSContext *cx, js::HandleObject obj);
 
     static inline JSBool lookupGeneric(JSContext *cx, js::HandleObject obj,
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -152,17 +152,17 @@ JSObject::setSpecialAttributes(JSContext
                                js::SpecialId sid, unsigned *attrsp)
 {
     js::RootedId id(cx, SPECIALID_TO_JSID(sid));
     return setGenericAttributes(cx, obj, id, attrsp);
 }
 
 /* static */ inline bool
 JSObject::changePropertyAttributes(JSContext *cx, js::HandleObject obj,
-                                   js::Shape *shape, unsigned attrs)
+                                   js::HandleShape shape, unsigned attrs)
 {
     return !!changeProperty(cx, obj, shape, attrs, 0, shape->getter(), shape->setter());
 }
 
 /* static */ inline JSBool
 JSObject::getGeneric(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
                      js::HandleId id, js::MutableHandleValue vp)
 {
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -677,23 +677,23 @@ js_Stringify(JSContext *cx, MutableHandl
             }
         } else {
             replacer = NULL;
         }
     }
 
     /* Step 5. */
     if (space.isObject()) {
-        JSObject &spaceObj = space.toObject();
-        if (ObjectClassIs(spaceObj, ESClass_Number, cx)) {
+        RootedObject spaceObj(cx, &space.toObject());
+        if (ObjectClassIs(*spaceObj, ESClass_Number, cx)) {
             double d;
             if (!ToNumber(cx, space, &d))
                 return false;
             space = NumberValue(d);
-        } else if (ObjectClassIs(spaceObj, ESClass_String, cx)) {
+        } else if (ObjectClassIs(*spaceObj, ESClass_String, cx)) {
             JSString *str = ToStringSlow(cx, space);
             if (!str)
                 return false;
             space = StringValue(str);
         }
     }
 
     StringBuffer gap(cx);
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -1678,22 +1678,22 @@ DecompileSwitch(SprintStack *ss, TableEn
                 jsbytecode *pc, ptrdiff_t switchLength,
                 ptrdiff_t defaultOffset, JSBool isCondSwitch)
 {
     JSContext *cx;
     JSPrinter *jp;
     ptrdiff_t off, off2, diff, caseExprOff, todo;
     const char *rval;
     unsigned i;
-    jsval key;
     JSString *str;
 
     cx = ss->sprinter.context;
     jp = ss->printer;
 
+    RootedValue key(cx);
     jsbytecode *lvalpc;
     const char *lval = PopStr(ss, JSOP_NOP, &lvalpc);
 
     /* JSOP_CONDSWITCH doesn't pop, unlike JSOP_{LOOKUP,TABLE}SWITCH. */
     if (isCondSwitch)
         ss->top++;
 
     js_printf(jp, "\tswitch (");
@@ -2605,29 +2605,29 @@ InitSprintStack(JSContext *cx, SprintSta
 /*
  * If nb is non-negative, decompile nb bytecodes starting at pc.  Otherwise
  * the decompiler starts at pc and continues until it reaches an opcode for
  * which decompiling would result in the stack depth equaling -(nb + 1).
  */
 static jsbytecode *
 Decompile(SprintStack *ss, jsbytecode *pc, int nb)
 {
-    JSContext *cx;
+    JSContext *cx = ss->sprinter.context;
     JSPrinter *jp, *jp2;
     jsbytecode *startpc, *endpc, *pc2, *done, *lvalpc, *rvalpc, *xvalpc;
     ptrdiff_t tail, todo, len, oplen, cond, next;
     JSOp op, lastop, saveop;
     const JSCodeSpec *cs;
     jssrcnote *sn, *sn2;
     const char *lval, *rval, *xval, *fmt, *token;
     unsigned nuses;
     int i, argc;
-    JSAtom *atom;
+    RootedAtom atom(cx);
     JSObject *obj;
-    JSFunction *fun = NULL; /* init to shut GCC up */
+    RootedFunction fun(cx);
     JSString *str;
     JSBool ok;
     JSBool foreach;
     JSBool defaultsSwitch = false;
 #if JS_HAS_XML_SUPPORT
     JSBool inXML, quoteAttr;
 #else
 #define inXML JS_FALSE
@@ -2717,17 +2717,16 @@ Decompile(SprintStack *ss, jsbytecode *p
             ss->opcodes[ss->top - 1] == JSOP_FUNCALL ||                       \
             ss->opcodes[ss->top - 1] == JSOP_FUNAPPLY) {                      \
             saveop = JSOP_CALL;                                               \
         }                                                                     \
     JS_END_MACRO
 
     jsbytecode *lastlvalpc = NULL, *lastrvalpc = NULL;
 
-    cx = ss->sprinter.context;
     JS_CHECK_RECURSION(cx, return NULL);
 
     jp = ss->printer;
     startpc = pc;
     endpc = (nb < 0) ? jp->script->code + jp->script->length : pc + nb;
     tail = -1;
     todo = -2;                  /* NB: different from Sprint() error return. */
     saveop = JSOP_NOP;
@@ -3610,17 +3609,17 @@ Decompile(SprintStack *ss, jsbytecode *p
                 todo = -2;
                 break;
               }
 
               case JSOP_CALLALIASEDVAR:
               case JSOP_GETALIASEDVAR:
               case JSOP_CALLLOCAL:
               case JSOP_GETLOCAL:
-                if (IsVarSlot(jp, pc, &atom, &i))
+                if (IsVarSlot(jp, pc, atom.address(), &i))
                     goto do_name;
                 LOCAL_ASSERT((unsigned)i < ss->top);
                 sn = js_GetSrcNote(cx, jp->script, pc);
 
 #if JS_HAS_DESTRUCTURING
                 if (sn && SN_TYPE(sn) == SRC_GROUPASSIGN) {
                     /*
                      * Distinguish a js_DecompileValueGenerator call that
@@ -3643,50 +3642,50 @@ Decompile(SprintStack *ss, jsbytecode *p
 #endif
 
                 rval = GetLocal(ss, i);
                 todo = Sprint(&ss->sprinter, ss_format, VarPrefix(sn), rval);
                 break;
 
               case JSOP_SETALIASEDVAR:
               case JSOP_SETLOCAL:
-                if (IsVarSlot(jp, pc, &atom, &i))
+                if (IsVarSlot(jp, pc, atom.address(), &i))
                     goto do_setname;
                 lval = GetLocal(ss, i);
                 rval = PopStrDupe(ss, op, &rvalpc);
                 goto do_setlval;
 
               case JSOP_INCALIASEDVAR:
               case JSOP_DECALIASEDVAR:
-                if (IsVarSlot(jp, pc, &atom, &i))
+                if (IsVarSlot(jp, pc, atom.address(), &i))
                     goto do_incatom;
                 lval = GetLocal(ss, i);
                 goto do_inclval;
 
               case JSOP_INCLOCAL:
               case JSOP_DECLOCAL:
                 /* INCLOCAL/DECLOCAL are followed by GETLOCAL containing the slot. */
                 JS_ASSERT(pc[JSOP_INCLOCAL_LENGTH] == JSOP_GETLOCAL);
-                if (IsVarSlot(jp, pc + JSOP_INCLOCAL_LENGTH, &atom, &i))
+                if (IsVarSlot(jp, pc + JSOP_INCLOCAL_LENGTH, atom.address(), &i))
                     goto do_incatom;
                 lval = GetLocal(ss, i);
                 goto do_inclval;
 
               case JSOP_ALIASEDVARINC:
               case JSOP_ALIASEDVARDEC:
-                if (IsVarSlot(jp, pc, &atom, &i))
+                if (IsVarSlot(jp, pc, atom.address(), &i))
                     goto do_atominc;
                 lval = GetLocal(ss, i);
                 goto do_lvalinc;
 
               case JSOP_LOCALINC:
               case JSOP_LOCALDEC:
                 /* LOCALINC/LOCALDEC are followed by GETLOCAL containing the slot. */
                 JS_ASSERT(pc[JSOP_LOCALINC_LENGTH] == JSOP_GETLOCAL);
-                if (IsVarSlot(jp, pc + JSOP_LOCALINC_LENGTH, &atom, &i))
+                if (IsVarSlot(jp, pc + JSOP_LOCALINC_LENGTH, atom.address(), &i))
                     goto do_atominc;
                 lval = GetLocal(ss, i);
                 goto do_lvalinc;
 
               case JSOP_RETRVAL:
                 todo = -2;
                 break;
 
@@ -4760,20 +4759,21 @@ Decompile(SprintStack *ss, jsbytecode *p
                 todo = ss->sprinter.getOffsetOf(rval);
                 break;
 
               case JSOP_LAMBDA:
 #if JS_HAS_GENERATOR_EXPRS
                 sn = js_GetSrcNote(cx, jp->script, pc);
                 if (sn && SN_TYPE(sn) == SRC_GENEXP) {
                     BindingVector *outerLocalNames;
-                    JSScript *inner, *outer;
+                    JSScript *inner;
+                    RootedScript outer(cx);
                     Vector<DecompiledOpcode> *decompiledOpcodes;
                     SprintStack ss2(cx);
-                    JSFunction *outerfun;
+                    RootedFunction outerfun(cx);
 
                     fun = jp->script->getFunction(GET_UINT32_INDEX(pc));
 
                     /*
                      * All allocation when decompiling is LIFO, using malloc or,
                      * more commonly, arena-allocating from cx->tempLifoAlloc
                      * Therefore after InitSprintStack succeeds, we must release
                      * to mark before returning.
@@ -5531,17 +5531,17 @@ DecompileCode(JSPrinter *jp, JSScript *s
     }
 
     for (unsigned i = 0; i < initialStackDepth; i++) {
         if (!PushStr(&ss, "", JSOP_NOP))
             return false;
     }
 
     /* Call recursive subroutine to do the hard work. */
-    JSScript *oldscript = jp->script;
+    RootedScript oldscript(cx, jp->script);
     BindingVector *oldLocalNames = jp->localNames;
     if (!SetPrinterLocalNames(cx, script, jp))
         return false;
     jp->script = script;
 
     /* Call recursive subroutine to do the hard work. */
     bool ok = Decompile(&ss, pc, len) != NULL;
 
@@ -5975,17 +5975,17 @@ ExpressionDecompiler::decompilePC(jsbyte
       case JSOP_GETALIASEDVAR: {
         JSAtom *atom = ScopeCoordinateName(cx, script, pc);
         JS_ASSERT(atom);
         return write(atom);
       }
       case JSOP_LENGTH:
       case JSOP_GETPROP:
       case JSOP_CALLPROP: {
-        JSAtom *prop = (op == JSOP_LENGTH) ? cx->names().length : loadAtom(pc);
+        RootedAtom prop(cx, (op == JSOP_LENGTH) ? cx->names().length : loadAtom(pc));
         if (!decompilePC(pcstack[-1]))
             return false;
         if (IsIdentifier(prop)) {
             return write(".") &&
                    quote(prop, '\0');
         }
         return write("[") &&
                quote(prop, '\'') &&
@@ -6909,18 +6909,18 @@ js::GetPCCountScriptSummary(JSContext *c
 {
     JSRuntime *rt = cx->runtime;
 
     if (!rt->scriptAndCountsVector || index >= rt->scriptAndCountsVector->length()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BUFFER_TOO_SMALL);
         return NULL;
     }
 
-    ScriptAndCounts sac = (*rt->scriptAndCountsVector)[index];
-    JSScript *script = sac.script;
+    const ScriptAndCounts &sac = (*rt->scriptAndCountsVector)[index];
+    RootedScript script(cx, sac.script);
 
     /*
      * OOM on buffer appends here will not be caught immediately, but since
      * StringBuffer uses a ContextAllocPolicy will trigger an exception on the
      * context if they occur, which we'll catch before returning.
      */
     StringBuffer buf(cx);
 
@@ -7022,17 +7022,17 @@ struct AutoDestroyPrinter
     JSPrinter *jp;
     AutoDestroyPrinter(JSPrinter *jp) : jp(jp) {}
     ~AutoDestroyPrinter() { js_DestroyPrinter(jp); }
 };
 
 static bool
 GetPCCountJSON(JSContext *cx, const ScriptAndCounts &sac, StringBuffer &buf)
 {
-    JSScript *script = sac.script;
+    RootedScript script(cx, sac.script);
 
     buf.append('{');
     AppendJSONProperty(buf, "text", NO_COMMA);
 
     Vector<DecompiledOpcode> decompiledOpcodes(cx);
     if (!decompiledOpcodes.reserve(script->length))
         return false;
 
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -3231,27 +3231,27 @@ proxy_create(JSContext *cx, unsigned arg
 static JSBool
 proxy_createFunction(JSContext *cx, unsigned argc, Value *vp)
 {
     if (argc < 2) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
                              "createFunction", "1", "");
         return false;
     }
-    JSObject *handler = NonNullObject(cx, vp[2]);
+    RootedObject handler(cx, NonNullObject(cx, vp[2]));
     if (!handler)
         return false;
-    JSObject *proto, *parent;
+    RootedObject proto(cx), parent(cx);
     parent = vp[0].toObject().getParent();
     proto = parent->global().getOrCreateFunctionPrototype(cx);
     if (!proto)
         return false;
     parent = proto->getParent();
 
-    JSObject *call = ValueToCallable(cx, &vp[3]);
+    RootedObject call(cx, ValueToCallable(cx, &vp[3]));
     if (!call)
         return false;
     JSObject *construct = NULL;
     if (argc > 2) {
         construct = ValueToCallable(cx, &vp[4]);
         if (!construct)
             return false;
     }
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -730,18 +730,18 @@ JSObject::putProperty(JSContext *cx, Han
     }
 
     obj->checkShapeConsistency();
 
     return shape;
 }
 
 /* static */ UnrootedShape
-JSObject::changeProperty(JSContext *cx, HandleObject obj, RawShape shape, unsigned attrs, unsigned mask,
-                         PropertyOp getter, StrictPropertyOp setter)
+JSObject::changeProperty(JSContext *cx, HandleObject obj, HandleShape shape, unsigned attrs,
+                         unsigned mask, PropertyOp getter, StrictPropertyOp setter)
 {
     JS_ASSERT(obj->nativeContains(cx, shape));
 
     attrs |= shape->attrs & mask;
 
     /* Allow only shared (slotless) => unshared (slotful) transition. */
     JS_ASSERT(!((attrs ^ shape->attrs) & JSPROP_SHARED) ||
               !(attrs & JSPROP_SHARED));
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -45,16 +45,18 @@
 
 #include "frontend/SharedContext-inl.h"
 #include "vm/RegExpObject-inl.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::frontend;
 
+typedef Rooted<GlobalObject *> RootedGlobalObject;
+
 /* static */ unsigned
 Bindings::argumentsVarIndex(JSContext *cx, InternalBindingsHandle bindings)
 {
     HandlePropertyName arguments = cx->names().arguments;
     BindingIter bi(bindings);
     while (bi->name() != arguments)
         bi++;
     return bi.frameIndex();
@@ -2363,17 +2365,17 @@ js::CloneFunctionScript(JSContext *cx, H
 
     RawScript cscript = CloneScript(cx, scope, clone, script);
     if (!cscript)
         return false;
 
     clone->setScript(cscript);
     cscript->setFunction(clone);
 
-    GlobalObject *global = script->compileAndGo ? &script->global() : NULL;
+    RootedGlobalObject global(cx, script->compileAndGo ? &script->global() : NULL);
 
     script = clone->nonLazyScript();
     CallNewScriptHook(cx, script, clone);
     Debugger::onNewScript(cx, script, global);
 
     return true;
 }