Bug 831822 - Fix various rooting hazards and unnecessary roots found by static analysis, r=terrence.
authorBrian Hackett <bhackett1024@gmail.com>
Fri, 18 Jan 2013 06:48:13 -0700
changeset 119254 3f69639fd6e2e1d95d00cb446ed56235b3441d02
parent 119253 4a3bcda8d1f832742645eeccce47d7b91844461b
child 119255 9aad620031209b2abd17b8de5e324f0ddd266a4f
push id24195
push userMs2ger@gmail.com
push dateSat, 19 Jan 2013 16:10:11 +0000
treeherdermozilla-central@02e12a80aef9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs831822
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 831822 - Fix various rooting hazards and unnecessary roots found by static analysis, r=terrence.
js/src/ion/Bailouts.cpp
js/src/ion/IonFrames.cpp
js/src/ion/IonFrames.h
js/src/ion/PcScriptCache-inl.h
js/src/ion/PcScriptCache.h
js/src/ion/VMFunctions.cpp
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jsbool.cpp
js/src/jsbool.h
js/src/jsboolinlines.h
js/src/jsclone.cpp
js/src/jsclone.h
js/src/jscntxt.cpp
js/src/jsfuninlines.h
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jsinferinlines.h
js/src/jsinterp.cpp
js/src/jsinterpinlines.h
js/src/json.cpp
js/src/methodjit/InvokeHelpers.cpp
js/src/vm/RegExpObject-inl.h
js/src/vm/Stack-inl.h
js/src/vm/Stack.h
--- a/js/src/ion/Bailouts.cpp
+++ b/js/src/ion/Bailouts.cpp
@@ -203,17 +203,17 @@ PushInlinedFrame(JSContext *cx, StackFra
     // Bump the stack pointer to make it look like the inline args have been pushed, but they will
     // really get filled in by RestoreOneFrame.
     regs.sp = inlineArgs.end();
 
     InitialFrameFlags flags = INITIAL_NONE;
     if (JSOp(*regs.pc) == JSOP_NEW)
         flags = INITIAL_CONSTRUCT;
 
-    if (!cx->stack.pushInlineFrame(cx, regs, inlineArgs, *fun, script, flags, DONT_REPORT_ERROR))
+    if (!cx->stack.pushInlineFrame(cx, regs, inlineArgs, fun, script, flags, DONT_REPORT_ERROR))
         return NULL;
 
     StackFrame *fp = cx->stack.fp();
     JS_ASSERT(fp == regs.fp());
     JS_ASSERT(fp->prev() == callerFrame);
 
     fp->formals()[-2].setObject(*fun);
 
--- a/js/src/ion/IonFrames.cpp
+++ b/js/src/ion/IonFrames.cpp
@@ -662,17 +662,17 @@ ion::MarkIonActivations(JSRuntime *rt, J
 void
 ion::AutoTempAllocatorRooter::trace(JSTracer *trc)
 {
     for (CompilerRootNode *root = temp->rootList(); root != NULL; root = root->next)
         gc::MarkGCThingRoot(trc, root->address(), "ion-compiler-root");
 }
 
 void
-ion::GetPcScript(JSContext *cx, MutableHandleScript scriptRes, jsbytecode **pcRes)
+ion::GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes)
 {
     JS_ASSERT(cx->fp()->beginsIonActivation());
     IonSpew(IonSpew_Snapshots, "Recover PC & Script from the last frame.");
 
     JSRuntime *rt = cx->runtime;
 
     // Recover the return address.
     IonFrameIterator it(rt->ionTop);
@@ -691,17 +691,17 @@ ion::GetPcScript(JSContext *cx, MutableH
     if (rt->ionPcScriptCache && rt->ionPcScriptCache->get(rt, hash, retAddr, scriptRes, pcRes))
         return;
 
     // Lookup failed: undertake expensive process to recover the innermost inlined frame.
     ++it; // Skip exit frame.
     InlineFrameIterator ifi(cx, &it);
 
     // Set the result.
-    scriptRes.set(ifi.script());
+    *scriptRes = ifi.script();
     if (pcRes)
         *pcRes = ifi.pc();
 
     // Add entry to cache.
     if (rt->ionPcScriptCache)
         rt->ionPcScriptCache->add(hash, retAddr, ifi.pc(), ifi.script());
 }
 
--- a/js/src/ion/IonFrames.h
+++ b/js/src/ion/IonFrames.h
@@ -272,17 +272,17 @@ namespace js {
 namespace ion {
 
 UnrootedScript
 GetTopIonJSScript(JSContext *cx,
                   const SafepointIndex **safepointIndexOut = NULL,
                   void **returnAddrOut = NULL);
 
 void
-GetPcScript(JSContext *cx, MutableHandleScript scriptRes, jsbytecode **pcRes);
+GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes);
 
 // Given a slot index, returns the offset, in bytes, of that slot from an
 // IonJSFrameLayout. Slot distances are uniform across architectures, however,
 // the distance does depend on the size of the frame header.
 static inline int32_t
 OffsetOfFrameSlot(int32_t slot)
 {
     if (slot <= 0)
--- a/js/src/ion/PcScriptCache-inl.h
+++ b/js/src/ion/PcScriptCache-inl.h
@@ -11,28 +11,28 @@
 #include "PcScriptCache.h"
 
 namespace js {
 namespace ion {
 
 // Get a value from the cache. May perform lazy allocation.
 bool
 PcScriptCache::get(JSRuntime *rt, uint32_t hash, uint8_t *addr,
-                   MutableHandleScript scriptRes, jsbytecode **pcRes)
+                   JSScript **scriptRes, jsbytecode **pcRes)
 {
     // If a GC occurred, lazily clear the cache now.
     if (gcNumber != rt->gcNumber) {
         clear(rt->gcNumber);
         return false;
     }
 
     if (entries[hash].returnAddress != addr)
         return false;
 
-    scriptRes.set(entries[hash].script);
+    *scriptRes = entries[hash].script;
     if (pcRes)
         *pcRes = entries[hash].pc;
 
     return true;
 }
 
 } // namespace ion
 } // namespace js
--- a/js/src/ion/PcScriptCache.h
+++ b/js/src/ion/PcScriptCache.h
@@ -39,17 +39,17 @@ struct PcScriptCache
         for (uint32_t i = 0; i < Length; i++)
             entries[i].returnAddress = NULL;
         this->gcNumber = gcNumber;
     }
 
     // Get a value from the cache. May perform lazy allocation.
     // Defined in PcScriptCache-inl.h.
     bool get(JSRuntime *rt, uint32_t hash, uint8_t *addr,
-             MutableHandleScript scriptRes, jsbytecode **pcRes);
+             JSScript **scriptRes, jsbytecode **pcRes);
 
     void add(uint32_t hash, uint8_t *addr, jsbytecode *pc, UnrootedScript script) {
         entries[hash].returnAddress = addr;
         entries[hash].pc = pc;
         entries[hash].script = script;
     }
 
     static uint32_t Hash(uint8_t *addr) {
--- a/js/src/ion/VMFunctions.cpp
+++ b/js/src/ion/VMFunctions.cpp
@@ -57,17 +57,17 @@ InvokeFunction(JSContext *cx, HandleFunc
     // hitting functions that are uncompilable.
     if (fun->isInterpreted()) {
         if (fun->isInterpretedLazy() && !JSFunction::getOrCreateScript(cx, fun))
             return false;
 
         if (fun->isCloneAtCallsite()) {
             RootedScript script(cx);
             jsbytecode *pc;
-            types::TypeScript::GetPcScript(cx, &script, &pc);
+            types::TypeScript::GetPcScript(cx, script.address(), &pc);
             fun = CloneFunctionAtCallsite(cx, fun0, script, pc);
             if (!fun)
                 return false;
         }
 
         if (!fun->nonLazyScript()->canIonCompile()) {
             UnrootedScript script = GetTopIonJSScript(cx);
             if (script->hasIonScript() &&
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -581,19 +581,18 @@ JS_ValueToInt32(JSContext *cx, jsval vAr
 JS_PUBLIC_API(JSBool)
 JS_ValueToUint16(JSContext *cx, jsval valueArg, uint16_t *ip)
 {
     RootedValue value(cx, valueArg);
     return ToUint16(cx, value, ip);
 }
 
 JS_PUBLIC_API(JSBool)
-JS_ValueToBoolean(JSContext *cx, jsval valueArg, JSBool *bp)
-{
-    RootedValue value(cx, valueArg);
+JS_ValueToBoolean(JSContext *cx, jsval value, JSBool *bp)
+{
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, value);
     *bp = ToBoolean(value);
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSType)
@@ -610,20 +609,18 @@ JS_PUBLIC_API(const char *)
 JS_GetTypeName(JSContext *cx, JSType type)
 {
     if ((unsigned)type >= (unsigned)JSTYPE_LIMIT)
         return NULL;
     return TypeStrings[type];
 }
 
 JS_PUBLIC_API(JSBool)
-JS_StrictlyEqual(JSContext *cx, jsval value1Arg, jsval value2Arg, JSBool *equal)
-{
-    RootedValue value1(cx, value1Arg);
-    RootedValue value2(cx, value2Arg);
+JS_StrictlyEqual(JSContext *cx, jsval value1, jsval value2, JSBool *equal)
+{
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, value1, value2);
     bool eq;
     if (!StrictlyEqual(cx, value1, value2, &eq))
         return false;
     *equal = eq;
     return true;
@@ -640,20 +637,18 @@ JS_LooselyEqual(JSContext *cx, jsval val
     bool eq;
     if (!LooselyEqual(cx, value1, value2, &eq))
         return false;
     *equal = eq;
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
-JS_SameValue(JSContext *cx, jsval value1Arg, jsval value2Arg, JSBool *same)
-{
-    RootedValue value1(cx, value1Arg);
-    RootedValue value2(cx, value2Arg);
+JS_SameValue(JSContext *cx, jsval value1, jsval value2, JSBool *same)
+{
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, value1, value2);
     bool s;
     if (!SameValue(cx, value1, value2, &s))
         return false;
     *same = s;
     return true;
@@ -1584,18 +1579,18 @@ JS_TransplantObject(JSContext *cx, JSObj
     AssertHeapIsIdle(cx);
     JS_ASSERT(origobj != target);
     JS_ASSERT(!IsCrossCompartmentWrapper(origobj));
     JS_ASSERT(!IsCrossCompartmentWrapper(target));
 
     AutoMaybeTouchDeadCompartments agc(cx);
 
     JSCompartment *destination = target->compartment();
-    Value origv = ObjectValue(*origobj);
-    JSObject *newIdentity;
+    RootedValue origv(cx, ObjectValue(*origobj));
+    RootedObject newIdentity(cx);
 
     if (origobj->compartment() == destination) {
         // If the original object is in the same compartment as the
         // destination, then we know that we won't find a wrapper in the
         // destination's cross compartment map and that the same
         // object will continue to work.
         if (!origobj->swap(cx, target))
             MOZ_CRASH();
@@ -1662,17 +1657,17 @@ js_TransplantObjectWithWrapper(JSContext
     AutoMaybeTouchDeadCompartments agc(cx);
 
     AssertHeapIsIdle(cx);
     JS_ASSERT(!IsCrossCompartmentWrapper(origobj));
     JS_ASSERT(!IsCrossCompartmentWrapper(origwrapper));
     JS_ASSERT(!IsCrossCompartmentWrapper(targetobj));
     JS_ASSERT(!IsCrossCompartmentWrapper(targetwrapper));
 
-    JSObject *newWrapper;
+    RootedObject newWrapper(cx);
     JSCompartment *destination = targetobj->compartment();
 
     // |origv| is the map entry we're looking up. The map entries are going to
     // be for |origobj|, not |origwrapper|.
     Value origv = ObjectValue(*origobj);
 
     // There might already be a wrapper for the original object in the new
     // compartment.
@@ -1912,32 +1907,31 @@ static JSStdName object_prototype_names[
 
     {NULL,                      0, NULL}
 };
 
 JS_PUBLIC_API(JSBool)
 JS_ResolveStandardClass(JSContext *cx, JSObject *objArg, jsid id, JSBool *resolved)
 {
     RootedObject obj(cx, objArg);
-    JSString *idstr;
     JSRuntime *rt;
     JSAtom *atom;
     JSStdName *stdnm;
     unsigned i;
 
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
     *resolved = false;
 
     rt = cx->runtime;
     if (!rt->hasContexts() || !JSID_IS_ATOM(id))
         return true;
 
-    idstr = JSID_TO_STRING(id);
+    RootedString idstr(cx, JSID_TO_STRING(id));
 
     /* Check whether we're resolving 'undefined', and define it if so. */
     atom = rt->atomState.undefined;
     if (idstr == atom) {
         *resolved = true;
         RootedValue undefinedValue(cx, UndefinedValue());
         return JSObject::defineProperty(cx, obj, atom->asPropertyName(), undefinedValue,
                                         JS_PropertyStub, JS_StrictPropertyStub,
@@ -4314,19 +4308,20 @@ JS_PUBLIC_API(JSBool)
 JS_GetProperty(JSContext *cx, JSObject *objArg, const char *name, jsval *vp)
 {
     RootedObject obj(cx, objArg);
     JSAtom *atom = Atomize(cx, name, strlen(name));
     return atom && JS_GetPropertyById(cx, obj, AtomToId(atom), vp);
 }
 
 JS_PUBLIC_API(JSBool)
-JS_GetPropertyDefault(JSContext *cx, JSObject *objArg, const char *name, jsval def, jsval *vp)
+JS_GetPropertyDefault(JSContext *cx, JSObject *objArg, const char *name, jsval defArg, jsval *vp)
 {
     RootedObject obj(cx, objArg);
+    RootedValue def(cx, defArg);
     JSAtom *atom = Atomize(cx, name, strlen(name));
     return atom && JS_GetPropertyByIdDefault(cx, obj, AtomToId(atom), def, vp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetUCProperty(JSContext *cx, JSObject *objArg, const jschar *name, size_t namelen, jsval *vp)
 {
     RootedObject obj(cx, objArg);
@@ -4352,18 +4347,19 @@ JS_GetMethodById(JSContext *cx, JSObject
     if (objp)
         *objp = obj;
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetMethod(JSContext *cx, JSObject *objArg, const char *name, JSObject **objp, jsval *vp)
 {
+    RootedObject obj(cx, objArg);
     JSAtom *atom = Atomize(cx, name, strlen(name));
-    return atom && JS_GetMethodById(cx, objArg, AtomToId(atom), objp, vp);
+    return atom && JS_GetMethodById(cx, obj, AtomToId(atom), objp, vp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetPropertyById(JSContext *cx, JSObject *objArg, jsid idArg, jsval *vp)
 {
     RootedObject obj(cx, objArg);
     RootedId id(cx, idArg);
     AssertHeapIsIdle(cx);
@@ -6362,17 +6358,17 @@ JS_WriteStructuredClone(JSContext *cx, j
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, value);
 
     const JSStructuredCloneCallbacks *callbacks =
         optionalCallbacks ?
         optionalCallbacks :
         cx->runtime->structuredCloneCallbacks;
-    return WriteStructuredClone(cx, valueArg, (uint64_t **) bufp, nbytesp,
+    return WriteStructuredClone(cx, value, (uint64_t **) bufp, nbytesp,
                                 callbacks, closure, transferable);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ClearStructuredClone(const uint64_t *data, size_t nbytes)
 {
     return ClearStructuredClone(data, nbytes);
 }
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -945,24 +945,24 @@ InitArrayElements(JSContext *cx, HandleO
     }
 
     if (vector == end)
         return true;
 
     JS_ASSERT(start == MAX_ARRAY_INDEX + 1);
     RootedValue value(cx);
     RootedId id(cx);
-    Value idval = DoubleValue(MAX_ARRAY_INDEX + 1);
+    double index = MAX_ARRAY_INDEX + 1;
     do {
         value = *vector++;
-        if (!ValueToId(cx, idval, &id) ||
+        if (!ValueToId(cx, DoubleValue(index), &id) ||
             !JSObject::setGeneric(cx, obj, obj, id, &value, true)) {
             return false;
         }
-        idval.getDoubleRef() += 1;
+        index += 1;
     } while (vector != end);
 
     return true;
 }
 
 static JSBool
 array_reverse(JSContext *cx, unsigned argc, Value *vp)
 {
@@ -1002,20 +1002,22 @@ array_reverse(JSContext *cx, unsigned ar
                 return false;
             JS_ASSERT(result == JSObject::ED_SPARSE);
             break;
         }
 
         /* Fill out the array's initialized length to its proper length. */
         obj->ensureDenseInitializedLength(cx, len, 0);
 
+        RootedValue origlo(cx), orighi(cx);
+
         uint32_t lo = 0, hi = len - 1;
         for (; lo < hi; lo++, hi--) {
-            Value origlo = obj->getDenseElement(lo);
-            Value orighi = obj->getDenseElement(hi);
+            origlo = obj->getDenseElement(lo);
+            orighi = obj->getDenseElement(hi);
             obj->setDenseElement(lo, orighi);
             if (orighi.isMagic(JS_ELEMENTS_HOLE) &&
                 !js_SuppressDeletedProperty(cx, obj, INT_TO_JSID(lo))) {
                 return false;
             }
             obj->setDenseElement(hi, origlo);
             if (origlo.isMagic(JS_ELEMENTS_HOLE) &&
                 !js_SuppressDeletedProperty(cx, obj, INT_TO_JSID(hi))) {
@@ -1745,17 +1747,17 @@ TryReuseArrayType(JSObject *obj, JSObjec
 /*
  * Returns true if this is a dense array whose |count| properties starting from
  * |startingIndex| may be accessed (get, set, delete) directly through its
  * contiguous vector of elements without fear of getters, setters, etc. along
  * the prototype chain, or of enumerators requiring notification of
  * modifications.
  */
 static inline bool
-CanOptimizeForDenseStorage(JSObject *arr, uint32_t startingIndex, uint32_t count, JSContext *cx)
+CanOptimizeForDenseStorage(HandleObject arr, uint32_t startingIndex, uint32_t count, JSContext *cx)
 {
     /* If the desired properties overflow dense storage, we can't optimize. */
     if (UINT32_MAX - startingIndex < count)
         return false;
 
     /* There's no optimizing possible if it's not an array. */
     if (!arr->isArray())
         return false;
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -199,20 +199,20 @@ js::ToBooleanSlow(const Value &v)
     if (v.isString())
         return v.toString()->length() != 0;
 
     JS_ASSERT(v.isObject());
     return !EmulatesUndefined(&v.toObject());
 }
 
 bool
-js::BooleanGetPrimitiveValueSlow(JSContext *cx, JSObject &obj, Value *vp)
+js::BooleanGetPrimitiveValueSlow(JSContext *cx, HandleObject obj, Value *vp)
 {
     InvokeArgsGuard ag;
     if (!cx->stack.pushInvokeArgs(cx, 0, &ag))
         return false;
     ag.setCallee(cx->compartment->maybeGlobal()->booleanValueOf());
-    ag.setThis(ObjectValue(obj));
+    ag.setThis(ObjectValue(*obj));
     if (!Invoke(cx, ag))
         return false;
     *vp = ag.rval();
     return true;
 }
--- a/js/src/jsbool.h
+++ b/js/src/jsbool.h
@@ -17,13 +17,13 @@ extern JSObject *
 js_InitBooleanClass(JSContext *cx, js::HandleObject obj);
 
 extern JSString *
 js_BooleanToString(JSContext *cx, JSBool b);
 
 namespace js {
 
 inline bool
-BooleanGetPrimitiveValue(JSContext *cx, JSObject &obj, Value *vp);
+BooleanGetPrimitiveValue(JSContext *cx, HandleObject obj, Value *vp);
 
 } /* namespace js */
 
 #endif /* jsbool_h___ */
--- a/js/src/jsboolinlines.h
+++ b/js/src/jsboolinlines.h
@@ -13,23 +13,23 @@
 #include "gc/Root.h"
 
 #include "jsobjinlines.h"
 
 #include "vm/BooleanObject-inl.h"
 
 namespace js {
 
-bool BooleanGetPrimitiveValueSlow(JSContext *, JSObject &, Value *);
+bool BooleanGetPrimitiveValueSlow(JSContext *, HandleObject, Value *);
 
 inline bool
-BooleanGetPrimitiveValue(JSContext *cx, JSObject &obj, Value *vp)
+BooleanGetPrimitiveValue(JSContext *cx, HandleObject obj, Value *vp)
 {
-    if (obj.isBoolean()) {
-        *vp = BooleanValue(obj.asBoolean().unbox());
+    if (obj->isBoolean()) {
+        *vp = BooleanValue(obj->asBoolean().unbox());
         return true;
     }
 
     return BooleanGetPrimitiveValueSlow(cx, obj, vp);
 }
 
 inline bool
 EmulatesUndefined(RawObject obj)
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -116,17 +116,17 @@ SwapBytes(uint64_t u)
            ((u & 0x00ff000000000000LLU) >> 40) |
            ((u & 0xff00000000000000LLU) >> 56);
 #else
     return u;
 #endif
 }
 
 bool
-js::WriteStructuredClone(JSContext *cx, const Value &v, uint64_t **bufp, size_t *nbytesp,
+js::WriteStructuredClone(JSContext *cx, HandleValue v, uint64_t **bufp, size_t *nbytesp,
                          const JSStructuredCloneCallbacks *cb, void *cbClosure,
                          jsval transferable)
 {
     SCOutput out(cx);
     JSStructuredCloneWriter w(out, cb, cbClosure, transferable);
     return w.init() && w.write(v) && out.extractBuffer(bufp, nbytesp);
 }
 
@@ -461,30 +461,31 @@ JSStructuredCloneWriter::parseTransferab
     if (JSVAL_IS_NULL(transferable) || JSVAL_IS_VOID(transferable))
         return true;
 
     if (!transferable.isObject()) {
         reportErrorTransferable();
         return false;
     }
 
-    JSObject* array = &transferable.toObject();
+    RootedObject array(context(), &transferable.toObject());
     if (!JS_IsArrayObject(context(), array)) {
         reportErrorTransferable();
         return false;
     }
 
     uint32_t length;
     if (!JS_GetArrayLength(context(), array, &length)) {
         return false;
     }
 
+    RootedValue v(context());
+
     for (uint32_t i = 0; i < length; ++i) {
-        Value v;
-        if (!JS_GetElement(context(), array, i, &v)) {
+        if (!JS_GetElement(context(), array, i, v.address())) {
             return false;
         }
 
         if (!v.isObject()) {
             reportErrorTransferable();
             return false;
         }
 
--- a/js/src/jsclone.h
+++ b/js/src/jsclone.h
@@ -10,17 +10,17 @@
 #include "jscntxt.h"
 
 #include "js/HashTable.h"
 #include "js/Vector.h"
 
 namespace js {
 
 bool
-WriteStructuredClone(JSContext *cx, const Value &v, uint64_t **bufp, size_t *nbytesp,
+WriteStructuredClone(JSContext *cx, HandleValue v, uint64_t **bufp, size_t *nbytesp,
                      const JSStructuredCloneCallbacks *cb, void *cbClosure,
                      jsval transferable);
 
 bool
 ReadStructuredClone(JSContext *cx, uint64_t *data, size_t nbytes, Value *vp,
                     const JSStructuredCloneCallbacks *cb, void *cbClosure);
 
 bool
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -637,18 +637,18 @@ js::ReportUsageError(JSContext *cx, Hand
 {
     const char *usageStr = "usage";
     PropertyName *usageAtom = Atomize(cx, usageStr, strlen(usageStr))->asPropertyName();
     DebugOnly<RawShape> shape = static_cast<RawShape>(callee->nativeLookup(cx, NameToId(usageAtom)));
     JS_ASSERT(!shape->configurable());
     JS_ASSERT(!shape->writable());
     JS_ASSERT(shape->hasDefaultGetter());
 
-    jsval usage;
-    if (!JS_LookupProperty(cx, callee, "usage", &usage))
+    RootedValue usage(cx);
+    if (!JS_LookupProperty(cx, callee, "usage", usage.address()))
         return;
 
     if (JSVAL_IS_VOID(usage)) {
         JS_ReportError(cx, "%s", msg);
     } else {
         JSString *str = JSVAL_TO_STRING(usage);
         JS::Anchor<JSString *> a_str(str);
         const jschar *chars = JS_GetStringCharsZ(cx, str);
--- a/js/src/jsfuninlines.h
+++ b/js/src/jsfuninlines.h
@@ -152,20 +152,20 @@ IsNativeFunction(const js::Value &v, JSN
  * TODO: a per-thread shape-based cache would be faster and simpler.
  */
 static JS_ALWAYS_INLINE bool
 ClassMethodIsNative(JSContext *cx, HandleObject obj, Class *clasp, HandleId methodid, JSNative native)
 {
     JS_ASSERT(!obj->isProxy());
     JS_ASSERT(obj->getClass() == clasp);
 
-    Value v;
-    if (!HasDataProperty(cx, obj, methodid, &v)) {
+    RootedValue v(cx);
+    if (!HasDataProperty(cx, obj, methodid, v.address())) {
         RootedObject proto(cx, obj->getProto());
-        if (!proto || proto->getClass() != clasp || !HasDataProperty(cx, proto, methodid, &v))
+        if (!proto || proto->getClass() != clasp || !HasDataProperty(cx, proto, methodid, v.address()))
             return false;
     }
 
     return js::IsNativeFunction(v, native);
 }
 
 extern JS_ALWAYS_INLINE bool
 SameTraceType(const Value &lhs, const Value &rhs)
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -2413,24 +2413,24 @@ TypeCompartment::addAllocationSiteTypeOb
         cx->compartment->types.setPendingNukeTypes(cx);
         return NULL;
     }
 
     return res;
 }
 
 static inline jsid
-GetAtomId(JSContext *cx, HandleScript script, const jsbytecode *pc, unsigned offset)
+GetAtomId(JSContext *cx, UnrootedScript script, const jsbytecode *pc, unsigned offset)
 {
     PropertyName *name = script->getName(GET_UINT32_INDEX(pc + offset));
     return MakeTypeId(cx, NameToId(name));
 }
 
 bool
-types::UseNewType(JSContext *cx, HandleScript script, jsbytecode *pc)
+types::UseNewType(JSContext *cx, UnrootedScript script, jsbytecode *pc)
 {
     JS_ASSERT(cx->typeInferenceEnabled());
 
     /*
      * Make a heuristic guess at a use of JSOP_NEW that the constructed object
      * should have a fresh type object. We do this when the NEW is immediately
      * followed by a simple assignment to an object's .prototype field.
      * This is designed to catch common patterns for subclassing in JS:
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -1082,17 +1082,17 @@ struct TypeObjectEntry
 
     static inline HashNumber hash(TaggedProto base);
     static inline bool match(TypeObject *key, TaggedProto lookup);
 };
 typedef HashSet<ReadBarriered<TypeObject>, TypeObjectEntry, SystemAllocPolicy> TypeObjectSet;
 
 /* Whether to use a new type object when calling 'new' at script/pc. */
 bool
-UseNewType(JSContext *cx, HandleScript script, jsbytecode *pc);
+UseNewType(JSContext *cx, UnrootedScript script, jsbytecode *pc);
 
 /* Whether to use a new type object for an initializer opcode at script/pc. */
 bool
 UseNewTypeForInitializer(JSContext *cx, HandleScript script, jsbytecode *pc, JSProtoKey key);
 
 /*
  * Whether Array.prototype, or an object on its proto chain, has an
  * indexed property.
@@ -1175,17 +1175,17 @@ class TypeScript
     /*
      * Monitor a bytecode pushing a value which is not accounted for by the
      * inference type constraints, such as integer overflow.
      */
     static inline void MonitorOverflow(JSContext *cx, HandleScript script, jsbytecode *pc);
     static inline void MonitorString(JSContext *cx, HandleScript script, jsbytecode *pc);
     static inline void MonitorUnknown(JSContext *cx, HandleScript script, jsbytecode *pc);
 
-    static inline void GetPcScript(JSContext *cx, MutableHandleScript script, jsbytecode **pc);
+    static inline void GetPcScript(JSContext *cx, JSScript **script, jsbytecode **pc);
     static inline void MonitorOverflow(JSContext *cx);
     static inline void MonitorString(JSContext *cx);
     static inline void MonitorUnknown(JSContext *cx);
 
     /*
      * Monitor a bytecode pushing any value. This must be called for any opcode
      * which is JOF_TYPESET, and where either the script has not been analyzed
      * by type inference or where the pc has type barriers. For simplicity, we
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -673,21 +673,20 @@ FixObjectType(JSContext *cx, HandleObjec
 extern void TypeMonitorResult(JSContext *cx, HandleScript script, jsbytecode *pc,
                               const js::Value &rval);
 extern void TypeDynamicResult(JSContext *cx, HandleScript script, jsbytecode *pc,
                               js::types::Type type);
 
 inline bool
 UseNewTypeAtEntry(JSContext *cx, StackFrame *fp)
 {
-
     if (!fp->isConstructing() || !cx->typeInferenceEnabled() || !fp->prev())
         return false;
 
-    RootedScript prevScript(cx, fp->prev()->script());
+    JSScript *prevScript = fp->prev()->script();
     return UseNewType(cx, prevScript, fp->prevpc());
 }
 
 inline bool
 UseNewTypeForClone(JSFunction *fun)
 {
     AutoAssertNoGC nogc;
 
@@ -912,62 +911,62 @@ TypeScript::MonitorString(JSContext *cx,
 /* static */ inline void
 TypeScript::MonitorUnknown(JSContext *cx, HandleScript script, jsbytecode *pc)
 {
     if (cx->typeInferenceEnabled())
         TypeDynamicResult(cx, script, pc, Type::UnknownType());
 }
 
 /* static */ inline void
-TypeScript::GetPcScript(JSContext *cx, MutableHandleScript script, jsbytecode **pc)
+TypeScript::GetPcScript(JSContext *cx, JSScript **script, jsbytecode **pc)
 {
     AutoAssertNoGC nogc;
 #ifdef JS_ION
     if (cx->fp()->beginsIonActivation()) {
         ion::GetPcScript(cx, script, pc);
         return;
     }
 #endif
-    script.set(cx->fp()->script());
+    *script = cx->fp()->script();
     *pc = cx->regs().pc;
 }
 
 /* static */ inline void
 TypeScript::MonitorOverflow(JSContext *cx)
 {
     RootedScript script(cx);
     jsbytecode *pc;
-    GetPcScript(cx, &script, &pc);
+    GetPcScript(cx, script.address(), &pc);
     MonitorOverflow(cx, script, pc);
 }
 
 /* static */ inline void
 TypeScript::MonitorString(JSContext *cx)
 {
     RootedScript script(cx);
     jsbytecode *pc;
-    GetPcScript(cx, &script, &pc);
+    GetPcScript(cx, script.address(), &pc);
     MonitorString(cx, script, pc);
 }
 
 /* static */ inline void
 TypeScript::MonitorUnknown(JSContext *cx)
 {
     RootedScript script(cx);
     jsbytecode *pc;
-    GetPcScript(cx, &script, &pc);
+    GetPcScript(cx, script.address(), &pc);
     MonitorUnknown(cx, script, pc);
 }
 
 /* static */ inline void
 TypeScript::Monitor(JSContext *cx, const js::Value &rval)
 {
     RootedScript script(cx);
     jsbytecode *pc;
-    GetPcScript(cx, &script, &pc);
+    GetPcScript(cx, script.address(), &pc);
     Monitor(cx, script, pc, rval);
 }
 
 /* static */ inline void
 TypeScript::MonitorAssign(JSContext *cx, HandleObject obj, jsid id)
 {
     if (cx->typeInferenceEnabled() && !obj->hasSingletonType()) {
         /*
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -2393,17 +2393,17 @@ BEGIN_CASE(JSOP_FUNCALL)
     }
 
     if (!TypeMonitorCall(cx, args, construct))
         goto error;
 
     InitialFrameFlags initial = construct ? INITIAL_CONSTRUCT : INITIAL_NONE;
     bool newType = cx->typeInferenceEnabled() && UseNewType(cx, script, regs.pc);
     RootedScript funScript(cx, fun->nonLazyScript());
-    if (!cx->stack.pushInlineFrame(cx, regs, args, *fun, funScript, initial))
+    if (!cx->stack.pushInlineFrame(cx, regs, args, fun, funScript, initial))
         goto error;
 
     SET_SCRIPT(regs.fp()->script());
 #ifdef JS_METHODJIT
     script->resetLoopCount();
 #endif
 
 #ifdef JS_ION
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -728,29 +728,29 @@ GetObjectElementOperation(JSContext *cx,
     }
 #endif
     // Don't call GetPcScript (needed for analysis) from inside Ion since it's expensive.
     bool analyze = !cx->fp()->beginsIonActivation();
 
     uint32_t index;
     if (IsDefinitelyIndex(rref, &index)) {
         if (analyze && !obj->isNative()) {
-            RootedScript script(cx, NULL);
+            JSScript *script = NULL;
             jsbytecode *pc = NULL;
             types::TypeScript::GetPcScript(cx, &script, &pc);
 
             if (script->hasAnalysis())
                 script->analysis()->getCode(pc).nonNativeGetElement = true;
         }
 
         if (!JSObject::getElement(cx, obj, obj, index, res))
             return false;
     } else {
         if (analyze) {
-            RootedScript script(cx, NULL);
+            JSScript *script = NULL;
             jsbytecode *pc = NULL;
             types::TypeScript::GetPcScript(cx, &script, &pc);
 
             if (script->hasAnalysis()) {
                 script->analysis()->getCode(pc).getStringElement = true;
 
                 if (!obj->isArray() && !obj->isNative())
                     script->analysis()->getCode(pc).nonNativeGetElement = true;
@@ -838,17 +838,17 @@ static JS_ALWAYS_INLINE bool
 SetObjectElementOperation(JSContext *cx, Handle<JSObject*> obj, HandleId id, const Value &value, bool strict)
 {
     types::TypeScript::MonitorAssign(cx, obj, id);
 
     if (obj->isArray() && JSID_IS_INT(id)) {
         uint32_t length = obj->getDenseInitializedLength();
         int32_t i = JSID_TO_INT(id);
         if ((uint32_t)i >= length && !cx->fp()->beginsIonActivation()) {
-            RootedScript script(cx);
+            JSScript *script = NULL;
             jsbytecode *pc;
             types::TypeScript::GetPcScript(cx, &script, &pc);
 
             if (script->hasAnalysis())
                 script->analysis()->getCode(pc).arrayWriteHole = true;
         }
     }
 
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -335,17 +335,18 @@ PreprocessValue(JSContext *cx, HandleObj
                 return false;
             vp.set(NumberValue(d));
         } else if (ObjectClassIs(obj, ESClass_String, cx)) {
             JSString *str = ToStringSlow(cx, vp);
             if (!str)
                 return false;
             vp.set(StringValue(str));
         } else if (ObjectClassIs(obj, ESClass_Boolean, cx)) {
-            if (!BooleanGetPrimitiveValue(cx, obj, vp.address()))
+            RootedObject nobj(cx, &obj);
+            if (!BooleanGetPrimitiveValue(cx, nobj, vp.address()))
                 return false;
             JS_ASSERT(vp.get().isBoolean());
         }
     }
 
     return true;
 }
 
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -353,17 +353,17 @@ UncachedInlineCall(VMFrame &f, InitialFr
      * f.regs reflects the state when we entered the stub call. This handoff is
      * tricky: we need to make sure that f.regs is not updated to the new
      * frame, and we also need to ensure that cx->regs still points to f.regs
      * when space is reserved, in case doing so throws an exception.
      */
     FrameRegs regs = f.regs;
 
     /* Get pointer to new frame/slots, prepare arguments. */
-    if (!cx->stack.pushInlineFrame(cx, regs, args, *newfun, newscript, initial, &f.stackLimit))
+    if (!cx->stack.pushInlineFrame(cx, regs, args, newfun, newscript, initial, &f.stackLimit))
         return false;
 
     /* Finish the handoff to the new frame regs. */
     PreserveRegsGuard regsGuard(cx, regs);
 
     /*
      * If newscript was successfully compiled, run it. Skip for calls which
      * will be constructing a new type object for 'this'.
--- a/js/src/vm/RegExpObject-inl.h
+++ b/js/src/vm/RegExpObject-inl.h
@@ -119,17 +119,16 @@ RegExpShared::isJITRuntimeEnabled(JSCont
 #else
     return false;
 #endif
 }
 
 inline bool
 RegExpToShared(JSContext *cx, JSObject &obj, RegExpGuard *g)
 {
-    JS_ASSERT(ObjectClassIs(obj, ESClass_RegExp, cx));
     if (obj.isRegExp())
         return obj.asRegExp().getShared(cx, g);
     return Proxy::regexp_toShared(cx, &obj, g);
 }
 
 inline void
 RegExpShared::prepareForUse(JSContext *cx)
 {
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -452,49 +452,49 @@ ContextStack::getCallFrame(JSContext *cx
     Value *dst = firstUnused;
     Value *src = args.base();
     PodCopy(dst, src, ncopy);
     return reinterpret_cast<StackFrame *>(firstUnused + ncopy);
 }
 
 JS_ALWAYS_INLINE bool
 ContextStack::pushInlineFrame(JSContext *cx, FrameRegs &regs, const CallArgs &args,
-                              JSFunction &callee, HandleScript script,
+                              HandleFunction callee, HandleScript script,
                               InitialFrameFlags initial, MaybeReportError report)
 {
     mozilla::Maybe<AutoAssertNoGC> maybeNoGC;
     if (report)
         AssertCanGC();
     else
         maybeNoGC.construct();
 
     JS_ASSERT(onTop());
     JS_ASSERT(regs.sp == args.end());
     /* Cannot assert callee == args.callee() since this is called from LeaveTree. */
-    JS_ASSERT(callee.nonLazyScript() == script);
+    JS_ASSERT(callee->nonLazyScript() == script);
 
     StackFrame::Flags flags = ToFrameFlags(initial);
-    StackFrame *fp = getCallFrame(cx, report, args, &callee, script, &flags);
+    StackFrame *fp = getCallFrame(cx, report, args, callee, script, &flags);
     if (!fp)
         return false;
 
     /* Initialize frame, locals, regs. */
-    fp->initCallFrame(cx, callee, script, args.length(), flags);
+    fp->initCallFrame(cx, *callee, script, args.length(), flags);
 
     /*
      * N.B. regs may differ from the active registers, if the parent is about
      * to repoint the active registers to regs. See UncachedInlineCall.
      */
     regs.prepareToRun(*fp, script);
     return true;
 }
 
 JS_ALWAYS_INLINE bool
 ContextStack::pushInlineFrame(JSContext *cx, FrameRegs &regs, const CallArgs &args,
-                              JSFunction &callee, HandleScript script,
+                              HandleFunction callee, HandleScript script,
                               InitialFrameFlags initial, Value **stackLimit)
 {
     AssertCanGC();
     if (!pushInlineFrame(cx, regs, args, callee, script, initial))
         return false;
     *stackLimit = space().conservativeEnd_;
     return true;
 }
@@ -556,17 +556,17 @@ ContextStack::currentScript(jsbytecode *
     if (!hasfp())
         return NULL;
 
     FrameRegs &regs = this->regs();
     StackFrame *fp = regs.fp();
 
 #ifdef JS_ION
     if (fp->beginsIonActivation()) {
-        RootedScript script(cx_);
+        JSScript *script = NULL;
         ion::GetPcScript(cx_, &script, ppc);
         if (!allowCrossCompartment && script->compartment() != cx_->compartment)
             return UnrootedScript(NULL);
         return script;
     }
 #endif
 
 #ifdef JS_METHODJIT
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1611,21 +1611,21 @@ class ContextStack
     bool pushGeneratorFrame(JSContext *cx, JSGenerator *gen, GeneratorFrameGuard *gfg);
 
     /*
      * An "inline frame" may only be pushed from within the top, active
      * segment. This is the case for calls made inside mjit code and Interpret.
      * The 'stackLimit' overload updates 'stackLimit' if it changes.
      */
     bool pushInlineFrame(JSContext *cx, FrameRegs &regs, const CallArgs &args,
-                         JSFunction &callee, HandleScript script,
+                         HandleFunction callee, HandleScript script,
                          InitialFrameFlags initial,
                          MaybeReportError report = REPORT_ERROR);
     bool pushInlineFrame(JSContext *cx, FrameRegs &regs, const CallArgs &args,
-                         JSFunction &callee, HandleScript script,
+                         HandleFunction callee, HandleScript script,
                          InitialFrameFlags initial, Value **stackLimit);
     void popInlineFrame(FrameRegs &regs);
 
     /* Pop a partially-pushed frame after hitting the limit before throwing. */
     void popFrameAfterOverflow();
 
     /*
      * Get the topmost script and optional pc on the stack. By default, this