Bug 817818 - Miscellaneous rooting fixes. r=terrence
authorSteve Fink <sfink@mozilla.com>
Mon, 17 Dec 2012 11:55:15 -0800
changeset 125416 1d71ba26519f3613f6505c4c87dce187ffbd7638
parent 125415 20646e439eb79836090bd8b4fc43e3574fcae26c
child 125417 e3559bd8606f9d8322d76a2343f6574c9797b5d9
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs817818
milestone20.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 817818 - Miscellaneous rooting fixes. r=terrence
js/src/gc/Root.h
js/src/jsprobes.cpp
js/src/jsprobes.h
js/src/jsscope.cpp
js/src/shell/js.cpp
js/src/vm/SPSProfiler.cpp
js/src/vm/SPSProfiler.h
js/src/vm/ScopeObject.cpp
--- a/js/src/gc/Root.h
+++ b/js/src/gc/Root.h
@@ -332,18 +332,16 @@ typedef MutableHandle<Value>       Mutab
 
 namespace js {
 
 /*
  * Raw pointer used as documentation that a parameter does not need to be
  * rooted.
  */
 typedef JSObject *                  RawObject;
-typedef JSFunction *                RawFunction;
-typedef JSScript *                  RawScript;
 typedef JSString *                  RawString;
 typedef jsid                        RawId;
 typedef JS::Value                   RawValue;
 
 /*
  * InternalHandle is a handle to an internal pointer into a gcthing. Use
  * InternalHandle when you have a pointer to a direct field of a gcthing, or
  * when you need a parameter type for something that *may* be a pointer to a
@@ -513,28 +511,28 @@ class Unrooted
 
     T ptr_;
 };
 
 /*
  * This macro simplifies declaration of the required matching raw-pointer for
  * optimized builds and Unrooted<T> template for debug builds.
  */
-# define ForwardDeclare(type)                                                 \
-    class type;                                                               \
-    typedef Unrooted<type*> Unrooted##type;                                   \
+# define ForwardDeclare(type)                        \
+    class type;                                      \
+    typedef Unrooted<type*> Unrooted##type;          \
     typedef type * Raw##type
 
-# define ForwardDeclareJS(type)                                               \
-    struct JS##type;                                                          \
-    namespace js {                                                            \
-        typedef Unrooted<JS##type*> Unrooted##type;                           \
-        typedef JS##type * Raw##type;                                         \
-    }                                                                         \
-    struct JS##type
+# define ForwardDeclareJS(type)                      \
+    class JS##type;                                  \
+    namespace js {                                   \
+        typedef js::Unrooted<JS##type*> Unrooted##type; \
+        typedef JS##type * Raw##type;                \
+    }                                                \
+    class JS##type
 
 template <typename T>
 T DropUnrooted(Unrooted<T> &unrooted)
 {
     T rv = unrooted;
     unrooted.drop();
     return rv;
 }
@@ -548,28 +546,28 @@ T DropUnrooted(T &unrooted)
 }
 
 template <>
 inline RawId DropUnrooted(RawId &id) { return id; }
 
 #else /* NDEBUG */
 
 /* In opt builds |UnrootedFoo| is a real |Foo*|. */
-# define ForwardDeclare(type)                                                 \
-    class type;                                                               \
-    typedef type * Unrooted##type;                                            \
+# define ForwardDeclare(type)        \
+    class type;                      \
+    typedef type * Unrooted##type;   \
     typedef type * Raw##type
 
 # define ForwardDeclareJS(type)                                               \
-    struct JS##type;                                                          \
+    class JS##type;                                                           \
     namespace js {                                                            \
         typedef JS##type * Unrooted##type;                                    \
         typedef JS##type * Raw##type;                                         \
     }                                                                         \
-    struct JS##type
+    class JS##type
 
 template <typename T>
 class Unrooted
 {
   private:
     Unrooted() MOZ_DELETE;
     Unrooted(const Unrooted &) MOZ_DELETE;
     ~Unrooted() MOZ_DELETE;
@@ -953,11 +951,14 @@ class CompilerRootNode
     CompilerRootNode *next;
 
   protected:
     js::gc::Cell *ptr;
 };
 
 }  /* namespace js */
 
+ForwardDeclareJS(Script);
+ForwardDeclareJS(Function);
+
 #endif  /* __cplusplus */
 
 #endif  /* jsgc_root_h___ */
--- a/js/src/jsprobes.cpp
+++ b/js/src/jsprobes.cpp
@@ -154,42 +154,42 @@ ScriptFilename(const UnrootedScript scri
     if (!script)
         return Probes::nullName;
     if (!script->filename)
         return Probes::anonymousName;
     return script->filename;
 }
 
 static const char *
-FunctionName(JSContext *cx, const JSFunction *fun, JSAutoByteString* bytes)
+FunctionName(JSContext *cx, UnrootedFunction fun, JSAutoByteString* bytes)
 {
     if (!fun)
         return Probes::nullName;
     if (!fun->displayAtom())
         return Probes::anonymousName;
     return bytes->encode(cx, fun->displayAtom()) ? bytes->ptr() : Probes::nullName;
 }
 
 /*
  * These functions call the DTrace macros for the JavaScript USDT probes.
  * Originally this code was inlined in the JavaScript code; however since
  * a number of operations are called, these have been placed into functions
  * to reduce any negative compiler optimization effect that the addition of
  * a number of usually unused lines of code would cause.
  */
 void
-Probes::DTraceEnterJSFun(JSContext *cx, JSFunction *fun, UnrootedScript script)
+Probes::DTraceEnterJSFun(JSContext *cx, UnrootedFunction fun, UnrootedScript script)
 {
     JSAutoByteString funNameBytes;
     JAVASCRIPT_FUNCTION_ENTRY(ScriptFilename(script), Probes::nullName,
                               FunctionName(cx, fun, &funNameBytes));
 }
 
 void
-Probes::DTraceExitJSFun(JSContext *cx, JSFunction *fun, UnrootedScript script)
+Probes::DTraceExitJSFun(JSContext *cx, UnrootedFunction fun, UnrootedScript script)
 {
     JSAutoByteString funNameBytes;
     JAVASCRIPT_FUNCTION_RETURN(ScriptFilename(script), Probes::nullName,
                                FunctionName(cx, fun, &funNameBytes));
 }
 #endif
 
 #ifdef MOZ_ETW
@@ -238,80 +238,80 @@ Probes::ETWDestroyRuntime(JSRuntime *rt)
 bool
 Probes::ETWShutdown()
 {
     EventUnregisterMozillaSpiderMonkey();
     return true;
 }
 
 bool
-Probes::ETWEnterJSFun(JSContext *cx, JSFunction *fun, UnrootedScript script, int counter)
+Probes::ETWEnterJSFun(JSContext *cx, UnrootedFunction fun, UnrootedScript script, int counter)
 {
     int lineno = script ? script->lineno : -1;
     JSAutoByteString bytes;
     return (EventWriteEvtFunctionEntry(ScriptFilename(script), lineno,
                                        ObjectClassname((JSObject *)fun),
                                        FunctionName(cx, fun, &bytes)) == ERROR_SUCCESS);
 }
 
 bool
-Probes::ETWExitJSFun(JSContext *cx, JSFunction *fun, UnrootedScript script, int counter)
+Probes::ETWExitJSFun(JSContext *cx, UnrootedFunction fun, UnrootedScript script, int counter)
 {
     int lineno = script ? script->lineno : -1;
     JSAutoByteString bytes;
     return (EventWriteEvtFunctionExit(ScriptFilename(script), lineno,
                                       ObjectClassname((JSObject *)fun),
                                       FunctionName(cx, fun, &bytes)) == ERROR_SUCCESS);
 }
 
 bool
-Probes::ETWCreateObject(JSContext *cx, JSObject *obj)
+Probes::ETWCreateObject(JSContext *cx, UnrootedObject obj)
 {
     int lineno;
     const char * script_filename;
     current_location(cx, &lineno, &script_filename);
 
     return EventWriteEvtObjectCreate(script_filename, lineno,
                                      ObjectClassname(obj), reinterpret_cast<uint64_t_t>(obj),
                                      obj ? obj->computedSizeOfIncludingThis() : 0) == ERROR_SUCCESS;
 }
 
 bool
-Probes::ETWFinalizeObject(JSObject *obj)
+Probes::ETWFinalizeObject(UnrootedObject obj)
 {
     return EventWriteEvtObjectFinalize(ObjectClassname(obj),
                                        reinterpret_cast<uint64_t_t>(obj)) == ERROR_SUCCESS;
 }
 
 bool
-Probes::ETWResizeObject(JSContext *cx, JSObject *obj, size_t oldSize, size_t newSize)
+Probes::ETWResizeObject(JSContext *cx, UnrootedObject obj, size_t oldSize, size_t newSize)
 {
     int lineno;
     const char *script_filename;
     current_location(cx, &lineno, &script_filename);
 
     return EventWriteEvtObjectResize(script_filename, lineno,
                                      ObjectClassname(obj), reinterpret_cast<uint64_t_t>(obj),
                                      oldSize, newSize) == ERROR_SUCCESS;
 }
 
 bool
-Probes::ETWCreateString(JSContext *cx, JSString *string, size_t length)
+Probes::ETWCreateString(JSContext *cx, UnrootedString string, size_t length)
 {
     int lineno;
     const char *script_filename;
     current_location(cx, &lineno, &script_filename);
 
     return EventWriteEvtStringCreate(script_filename, lineno,
                                      reinterpret_cast<uint64_t_t>(string), length) ==
            ERROR_SUCCESS;
 }
 
 bool
-Probes::ETWFinalizeString(JSString *string)
+Probes::ETWFinalizeString(UnrootedString string)
 {
     return EventWriteEvtStringFinalize(reinterpret_cast<uint64_t>(string),
                                        string->length()) == ERROR_SUCCESS;
 }
 
 bool
 Probes::ETWCompileScriptBegin(const char *filename, int lineno)
 {
@@ -320,31 +320,31 @@ Probes::ETWCompileScriptBegin(const char
 
 bool
 Probes::ETWCompileScriptEnd(const char *filename, int lineno)
 {
     return EventWriteEvtScriptCompileEnd(filename, lineno) == ERROR_SUCCESS;
 }
 
 bool
-Probes::ETWCalloutBegin(JSContext *cx, JSFunction *fun)
+Probes::ETWCalloutBegin(JSContext *cx, UnrootedFunction fun)
 {
     const char *script_filename;
     int lineno;
     JSAutoByteString bytes;
     current_location(cx, &lineno, &script_filename);
 
     return EventWriteEvtCalloutBegin(script_filename,
                                      lineno,
                                      ObjectClassname((JSObject *)fun),
                                      FunctionName(cx, fun, &bytes)) == ERROR_SUCCESS;
 }
 
 bool
-Probes::ETWCalloutEnd(JSContext *cx, JSFunction *fun)
+Probes::ETWCalloutEnd(JSContext *cx, UnrootedFunction fun)
 {
         const char *script_filename;
         int lineno;
         JSAutoByteString bytes;
         current_location(cx, &lineno, &script_filename);
 
         return EventWriteEvtCalloutEnd(script_filename,
                                        lineno,
@@ -401,17 +401,17 @@ Probes::ETWGCStartSweepPhase(JSCompartme
 
 bool
 Probes::ETWGCEndSweepPhase(JSCompartment *compartment)
 {
     return EventWriteEvtGCEndSweepPhase(reinterpret_cast<uint64_t>(compartment)) == ERROR_SUCCESS;
 }
 
 bool
-Probes::ETWCustomMark(JSString *string)
+Probes::ETWCustomMark(UnrootedString string)
 {
     const jschar *chars = string->getCharsZ(NULL);
     return !chars || EventWriteEvtCustomString(chars) == ERROR_SUCCESS;
 }
 
 bool
 Probes::ETWCustomMark(const char *string)
 {
--- a/js/src/jsprobes.h
+++ b/js/src/jsprobes.h
@@ -87,20 +87,20 @@ bool callTrackingActive(JSContext *);
 
 /*
  * Test whether anything is looking for JIT native code registration events.
  * This information will not be collected otherwise.
  */
 bool wantNativeAddressInfo(JSContext *);
 
 /* Entering a JS function */
-bool enterScript(JSContext *, UnrootedScript , JSFunction *, StackFrame *);
+bool enterScript(JSContext *, UnrootedScript, UnrootedFunction , StackFrame *);
 
 /* About to leave a JS function */
-bool exitScript(JSContext *, UnrootedScript , JSFunction *, StackFrame *);
+bool exitScript(JSContext *, UnrootedScript, UnrootedFunction , StackFrame *);
 
 /* Executing a script */
 bool startExecution(UnrootedScript script);
 
 /* Script has completed execution */
 bool stopExecution(UnrootedScript script);
 
 /* Heap has been resized */
@@ -142,20 +142,20 @@ bool finalizeString(JSString *string);
 
 /* Script is about to be compiled */
 bool compileScriptBegin(const char *filename, int lineno);
 
 /* Script has just finished compilation */
 bool compileScriptEnd(const char *filename, int lineno);
 
 /* About to make a call from JS into native code */
-bool calloutBegin(JSContext *cx, JSFunction *fun);
+bool calloutBegin(JSContext *cx, UnrootedFunction fun);
 
 /* Native code called by JS has terminated */
-bool calloutEnd(JSContext *cx, JSFunction *fun);
+bool calloutEnd(JSContext *cx, UnrootedFunction fun);
 
 /* Unimplemented */
 bool acquireMemory(JSContext *cx, void *address, size_t nbytes);
 bool releaseMemory(JSContext *cx, void *address, size_t nbytes);
 
 /*
  * Garbage collection probes
  *
@@ -235,39 +235,39 @@ void
 discardExecutableRegion(void *start, size_t size);
 
 /*
  * Internal: DTrace-specific functions to be called during Probes::enterScript
  * and Probes::exitScript. These will not be inlined, but the argument
  * marshalling required for these probe points is expensive enough that it
  * shouldn't really matter.
  */
-void DTraceEnterJSFun(JSContext *cx, JSFunction *fun, UnrootedScript script);
-void DTraceExitJSFun(JSContext *cx, JSFunction *fun, UnrootedScript script);
+void DTraceEnterJSFun(JSContext *cx, UnrootedFunction fun, UnrootedScript script);
+void DTraceExitJSFun(JSContext *cx, UnrootedFunction fun, UnrootedScript script);
 
 /*
  * Internal: ETW-specific probe functions
  */
 #ifdef MOZ_ETW
 // ETW Handlers
 bool ETWCreateRuntime(JSRuntime *rt);
 bool ETWDestroyRuntime(JSRuntime *rt);
 bool ETWShutdown();
 bool ETWCallTrackingActive();
-bool ETWEnterJSFun(JSContext *cx, JSFunction *fun, UnrootedScript script, int counter);
-bool ETWExitJSFun(JSContext *cx, JSFunction *fun, UnrootedScript script, int counter);
+bool ETWEnterJSFun(JSContext *cx, UnrootedFunction fun, UnrootedScript script, int counter);
+bool ETWExitJSFun(JSContext *cx, UnrootedFunction fun, UnrootedScript script, int counter);
 bool ETWCreateObject(JSContext *cx, JSObject *obj);
 bool ETWFinalizeObject(JSObject *obj);
 bool ETWResizeObject(JSContext *cx, JSObject *obj, size_t oldSize, size_t newSize);
 bool ETWCreateString(JSContext *cx, JSString *string, size_t length);
 bool ETWFinalizeString(JSString *string);
 bool ETWCompileScriptBegin(const char *filename, int lineno);
 bool ETWCompileScriptEnd(const char *filename, int lineno);
-bool ETWCalloutBegin(JSContext *cx, JSFunction *fun);
-bool ETWCalloutEnd(JSContext *cx, JSFunction *fun);
+bool ETWCalloutBegin(JSContext *cx, UnrootedFunction fun);
+bool ETWCalloutEnd(JSContext *cx, UnrootedFunction fun);
 bool ETWAcquireMemory(JSContext *cx, void *address, size_t nbytes);
 bool ETWReleaseMemory(JSContext *cx, void *address, size_t nbytes);
 bool ETWGCStart();
 bool ETWGCEnd();
 bool ETWGCStartMarkPhase();
 bool ETWGCEndMarkPhase();
 bool ETWGCStartSweepPhase();
 bool ETWGCEndSweepPhase();
@@ -307,17 +307,17 @@ Probes::callTrackingActive(JSContext *cx
 inline bool
 Probes::wantNativeAddressInfo(JSContext *cx)
 {
     return (cx->reportGranularity >= JITREPORT_GRANULARITY_FUNCTION &&
             JITGranularityRequested(cx) >= JITREPORT_GRANULARITY_FUNCTION);
 }
 
 inline bool
-Probes::enterScript(JSContext *cx, UnrootedScript script, JSFunction *maybeFun,
+Probes::enterScript(JSContext *cx, UnrootedScript script, UnrootedFunction maybeFun,
                     StackFrame *fp)
 {
     bool ok = true;
 #ifdef INCLUDE_MOZILLA_DTRACE
     if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED())
         DTraceEnterJSFun(cx, maybeFun, script);
 #endif
 #ifdef MOZ_TRACE_JSCALLS
@@ -334,17 +334,17 @@ Probes::enterScript(JSContext *cx, Unroo
         JS_ASSERT_IF(!fp->isGeneratorFrame(), !fp->hasPushedSPSFrame());
         fp->setPushedSPSFrame();
     }
 
     return ok;
 }
 
 inline bool
-Probes::exitScript(JSContext *cx, UnrootedScript script, JSFunction *maybeFun,
+Probes::exitScript(JSContext *cx, UnrootedScript script, UnrootedFunction maybeFun,
                    StackFrame *fp)
 {
     bool ok = true;
 
 #ifdef INCLUDE_MOZILLA_DTRACE
     if (JAVASCRIPT_FUNCTION_RETURN_ENABLED())
         DTraceExitJSFun(cx, maybeFun, script);
 #endif
@@ -507,30 +507,30 @@ Probes::compileScriptEnd(const char *fil
     if (ProfilingActive && !ETWCompileScriptEnd(filename, lineno))
         ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
-Probes::calloutBegin(JSContext *cx, JSFunction *fun)
+Probes::calloutBegin(JSContext *cx, UnrootedFunction fun)
 {
     bool ok = true;
 
 #ifdef MOZ_ETW
     if (ProfilingActive && !ETWCalloutBegin(cx, fun))
         ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
-Probes::calloutEnd(JSContext *cx, JSFunction *fun)
+Probes::calloutEnd(JSContext *cx, UnrootedFunction fun)
 {
     bool ok = true;
 
 #ifdef MOZ_ETW
     if (ProfilingActive && !ETWCalloutEnd(cx, fun))
         ok = false;
 #endif
 
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -299,16 +299,17 @@ Shape::replaceLastProperty(JSContext *cx
         /* Treat as resetting the initial property of the shape hierarchy. */
         AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
         return EmptyShape::getInitialShape(cx, base.clasp, proto,
                                            base.parent, kind,
                                            base.flags & BaseShape::OBJECT_FLAG_MASK);
     }
 
     StackShape child(shape);
+    StackShape::AutoRooter childRoot(cx, &child);
     {
         UnrootedUnownedBaseShape nbase = BaseShape::getUnowned(cx, base);
         if (!nbase)
             return UnrootedShape(NULL);
 
         child.base = nbase;
     }
 
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -3980,20 +3980,21 @@ PrintHelpString(JSContext *cx, jsval v)
     fprintf(gOutFile, "\n");
 
     return true;
 }
 
 static bool
 PrintHelp(JSContext *cx, HandleObject obj)
 {
-    jsval usage, help;
-    if (!JS_LookupProperty(cx, obj, "usage", &usage))
+    RootedValue usage(cx);
+    if (!JS_LookupProperty(cx, obj, "usage", usage.address()))
         return false;
-    if (!JS_LookupProperty(cx, obj, "help", &help))
+    RootedValue help(cx);
+    if (!JS_LookupProperty(cx, obj, "help", help.address()))
         return false;
 
     if (JSVAL_IS_VOID(usage) || JSVAL_IS_VOID(help))
         return true;
 
     return PrintHelpString(cx, usage) && PrintHelpString(cx, help);
 }
 
--- a/js/src/vm/SPSProfiler.cpp
+++ b/js/src/vm/SPSProfiler.cpp
@@ -65,34 +65,34 @@ SPSProfiler::enable(bool enabled)
      * Ensure all future generated code will be instrumented, or that all
      * currently instrumented code is discarded
      */
     ReleaseAllJITCode(rt->defaultFreeOp());
 }
 
 /* Lookup the string for the function/script, creating one if necessary */
 const char*
-SPSProfiler::profileString(JSContext *cx, JSScript *script, JSFunction *maybeFun)
+SPSProfiler::profileString(JSContext *cx, UnrootedScript script, UnrootedFunction maybeFun)
 {
     JS_ASSERT(strings.initialized());
     ProfileStringMap::AddPtr s = strings.lookupForAdd(script);
     if (s)
         return s->value;
     const char *str = allocProfileString(cx, script, maybeFun);
     if (str == NULL)
         return NULL;
     if (!strings.add(s, script, str)) {
         js_free(const_cast<char *>(str));
         return NULL;
     }
     return str;
 }
 
 void
-SPSProfiler::onScriptFinalized(JSScript *script)
+SPSProfiler::onScriptFinalized(UnrootedScript script)
 {
     /*
      * This function is called whenever a script is destroyed, regardless of
      * whether profiling has been turned on, so don't invoke a function on an
      * invalid hash set. Also, even if profiling was enabled but then turned
      * off, we still want to remove the string, so no check of enabled() is
      * done.
      */
@@ -101,30 +101,30 @@ SPSProfiler::onScriptFinalized(JSScript 
     if (ProfileStringMap::Ptr entry = strings.lookup(script)) {
         const char *tofree = entry->value;
         strings.remove(entry);
         js_free(const_cast<char *>(tofree));
     }
 }
 
 bool
-SPSProfiler::enter(JSContext *cx, JSScript *script, JSFunction *maybeFun)
+SPSProfiler::enter(JSContext *cx, UnrootedScript script, UnrootedFunction maybeFun)
 {
     const char *str = profileString(cx, script, maybeFun);
     if (str == NULL)
         return false;
 
     JS_ASSERT_IF(*size_ > 0 && *size_ - 1 < max_ && stack_[*size_ - 1].js(),
                  stack_[*size_ - 1].pc() != NULL);
     push(str, NULL, script, script->code);
     return true;
 }
 
 void
-SPSProfiler::exit(JSContext *cx, JSScript *script, JSFunction *maybeFun)
+SPSProfiler::exit(JSContext *cx, UnrootedScript script, UnrootedFunction maybeFun)
 {
     pop();
 
 #ifdef DEBUG
     /* Sanity check to make sure push/pop balanced */
     if (*size_ < max_) {
         const char *str = profileString(cx, script, maybeFun);
         /* Can't fail lookup because we should already be in the set */
@@ -134,17 +134,17 @@ SPSProfiler::exit(JSContext *cx, JSScrip
         JS_ASSERT(strcmp((const char*) stack_[*size_].label(), str) == 0);
         stack_[*size_].setLabel(NULL);
         stack_[*size_].setPC(NULL);
     }
 #endif
 }
 
 void
-SPSProfiler::push(const char *string, void *sp, JSScript *script, jsbytecode *pc)
+SPSProfiler::push(const char *string, void *sp, UnrootedScript script, jsbytecode *pc)
 {
     /* these operations cannot be re-ordered, so volatile-ize operations */
     volatile ProfileEntry *stack = stack_;
     volatile uint32_t *size = size_;
     uint32_t current = *size;
 
     JS_ASSERT(enabled());
     if (current < max_) {
@@ -166,17 +166,17 @@ SPSProfiler::pop()
 
 /*
  * Serializes the script/function pair into a "descriptive string" which is
  * allowed to fail. This function cannot trigger a GC because it could finalize
  * some scripts, resize the hash table of profile strings, and invalidate the
  * AddPtr held while invoking allocProfileString.
  */
 const char*
-SPSProfiler::allocProfileString(JSContext *cx, JSScript *script, JSFunction *maybeFun)
+SPSProfiler::allocProfileString(JSContext *cx, UnrootedScript script, UnrootedFunction maybeFun)
 {
     DebugOnly<uint64_t> gcBefore = cx->runtime->gcNumber;
     StringBuffer buf(cx);
     bool hasAtom = maybeFun != NULL && maybeFun->displayAtom() != NULL;
     if (hasAtom) {
         if (!buf.append(maybeFun->displayAtom()))
             return NULL;
         if (!buf.append(" ("))
@@ -219,17 +219,17 @@ JMChunkInfo::JMChunkInfo(mjit::JSActiveF
     mainEnd(frame->mainCodeEnd),
     stubStart(frame->stubCodeStart),
     stubEnd(frame->stubCodeEnd),
     pcLengths(pcLengths),
     chunk(chunk)
 {}
 
 jsbytecode*
-SPSProfiler::ipToPC(JSScript *script, size_t ip)
+SPSProfiler::ipToPC(UnrootedScript script, size_t ip)
 {
     if (!jminfo.initialized())
         return NULL;
 
     JITInfoMap::Ptr ptr = jminfo.lookup(script);
     if (!ptr)
         return NULL;
     JMScriptInfo *info = ptr->value;
@@ -247,17 +247,17 @@ SPSProfiler::ipToPC(JSScript *script, si
         if (pc != NULL)
             return pc;
     }
 
     return NULL;
 }
 
 jsbytecode*
-JMChunkInfo::convert(JSScript *script, size_t ip)
+JMChunkInfo::convert(UnrootedScript script, size_t ip)
 {
     if (mainStart <= ip && ip < mainEnd) {
         size_t offset = 0;
         uint32_t i;
         for (i = 0; i < script->length - 1; i++) {
             offset += (uint32_t) pcLengths[i].inlineLength;
             if (mainStart + offset > ip)
                 break;
@@ -345,17 +345,17 @@ SPSProfiler::registerScript(mjit::JSActi
     }
     if (!info->chunks.append(JMChunkInfo(frame, entries, chunk)))
         return NULL;
     return info->chunks.end() - 1;
 }
 
 bool
 SPSProfiler::registerICCode(mjit::JITChunk *chunk,
-                            JSScript *script, jsbytecode *pc,
+                            UnrootedScript script, jsbytecode *pc,
                             void *base, size_t size)
 {
     JS_ASSERT(jminfo.initialized());
     JITInfoMap::Ptr ptr = jminfo.lookup(script);
     JS_ASSERT(ptr);
     return ptr->value->ics.append(ICInfo(base, size, pc));
 }
 
--- a/js/src/vm/SPSProfiler.h
+++ b/js/src/vm/SPSProfiler.h
@@ -130,19 +130,19 @@ class SPSProfiler
     JSRuntime            *rt;
     ProfileStringMap     strings;
     ProfileEntry         *stack_;
     uint32_t             *size_;
     uint32_t             max_;
     bool                 slowAssertions;
     bool                 enabled_;
 
-    const char *allocProfileString(JSContext *cx, JSScript *script,
-                                   JSFunction *function);
-    void push(const char *string, void *sp, JSScript *script, jsbytecode *pc);
+    const char *allocProfileString(JSContext *cx, UnrootedScript script,
+                                   UnrootedFunction function);
+    void push(const char *string, void *sp, UnrootedScript script, jsbytecode *pc);
     void pop();
 
   public:
     SPSProfiler(JSRuntime *rt);
     ~SPSProfiler();
 
     uint32_t *sizePointer() { return size_; }
     uint32_t maxSize() { return max_; }
@@ -159,19 +159,19 @@ class SPSProfiler
      * Functions which are the actual instrumentation to track run information
      *
      *   - enter: a function has started to execute
      *   - updatePC: updates the pc information about where a function
      *               is currently executing
      *   - exit: this function has ceased execution, and no further
      *           entries/exits will be made
      */
-    bool enter(JSContext *cx, JSScript *script, JSFunction *maybeFun);
-    void exit(JSContext *cx, JSScript *script, JSFunction *maybeFun);
-    void updatePC(JSScript *script, jsbytecode *pc) {
+    bool enter(JSContext *cx, UnrootedScript script, UnrootedFunction maybeFun);
+    void exit(JSContext *cx, UnrootedScript script, UnrootedFunction maybeFun);
+    void updatePC(UnrootedScript script, jsbytecode *pc) {
         if (enabled() && *size_ - 1 < max_) {
             JS_ASSERT(*size_ > 0);
             JS_ASSERT(stack_[*size_ - 1].script() == script);
             stack_[*size_ - 1].setPC(pc);
         }
     }
 
 #ifdef JS_METHODJIT
@@ -194,17 +194,17 @@ class SPSProfiler
         size_t stubEnd;
         mjit::PCLengthEntry *pcLengths; // pcLengths for this chunk
         mjit::JITChunk *chunk;          // stored to test when removing
 
         JMChunkInfo(mjit::JSActiveFrame *frame,
                     mjit::PCLengthEntry *pcLengths,
                     mjit::JITChunk *chunk);
 
-        jsbytecode *convert(JSScript *script, size_t ip);
+        jsbytecode *convert(UnrootedScript script, size_t ip);
     };
 
     struct JMScriptInfo
     {
         Vector<ICInfo, 0, SystemAllocPolicy> ics;
         Vector<JMChunkInfo, 1, SystemAllocPolicy> chunks;
     };
 
@@ -227,33 +227,33 @@ class SPSProfiler
      */
     JITInfoMap jminfo;
 
     bool registerMJITCode(mjit::JITChunk *chunk,
                           mjit::JSActiveFrame *outerFrame,
                           mjit::JSActiveFrame **inlineFrames);
     void discardMJITCode(mjit::JITScript *jscr,
                          mjit::JITChunk *chunk, void* address);
-    bool registerICCode(mjit::JITChunk *chunk, JSScript *script, jsbytecode* pc,
+    bool registerICCode(mjit::JITChunk *chunk, UnrootedScript script, jsbytecode* pc,
                         void *start, size_t size);
-    jsbytecode *ipToPC(JSScript *script, size_t ip);
+    jsbytecode *ipToPC(UnrootedScript script, size_t ip);
 
   private:
     JMChunkInfo *registerScript(mjit::JSActiveFrame *frame,
                                 mjit::PCLengthEntry *lenths,
                                 mjit::JITChunk *chunk);
     void unregisterScript(UnrootedScript script, mjit::JITChunk *chunk);
   public:
 #else
-    jsbytecode *ipToPC(JSScript *script, size_t ip) { return NULL; }
+    jsbytecode *ipToPC(UnrootedScript script, size_t ip) { return NULL; }
 #endif
 
     void setProfilingStack(ProfileEntry *stack, uint32_t *size, uint32_t max);
-    const char *profileString(JSContext *cx, JSScript *script, JSFunction *maybeFun);
-    void onScriptFinalized(JSScript *script);
+    const char *profileString(JSContext *cx, UnrootedScript script, UnrootedFunction maybeFun);
+    void onScriptFinalized(UnrootedScript script);
 
     /* meant to be used for testing, not recommended to call in normal code */
     size_t stringsCount() { return strings.count(); }
     void stringsReset() { strings.clear(); }
 };
 
 /*
  * This class is used in RunScript() to push the marker onto the sampling stack
@@ -362,45 +362,45 @@ class SPSInstrumentation
         frame->skipNext = true;
     }
 
     /*
      * In some cases, a frame needs to be flagged as having been pushed, but no
      * instrumentation should be emitted. This updates internal state to flag
      * that further instrumentation should actually be emitted.
      */
-    void setPushed(JSScript *script) {
+    void setPushed(UnrootedScript script) {
         if (!enabled())
             return;
         JS_ASSERT(frame->left == 0);
         frame->script = script;
     }
 
     /*
      * Flags entry into a JS function for the first time. Before this is called,
      * no instrumentation is emitted, but after this instrumentation is emitted.
      */
-    bool push(JSContext *cx, JSScript *script, Assembler &masm, Register scratch) {
+    bool push(JSContext *cx, UnrootedScript script, Assembler &masm, Register scratch) {
         if (!enabled())
             return true;
         const char *string = profiler_->profileString(cx, script,
                                                       script->function());
         if (string == NULL)
             return false;
         masm.spsPushFrame(profiler_, string, script, scratch);
         setPushed(script);
         return true;
     }
 
     /*
      * Signifies that C++ performed the push() for this function. C++ always
      * sets the current PC to something non-null, however, so as soon as JIT
      * code is reentered this updates the current pc to NULL.
      */
-    void pushManual(JSScript *script, Assembler &masm, Register scratch) {
+    void pushManual(UnrootedScript script, Assembler &masm, Register scratch) {
         if (!enabled())
             return;
         masm.spsUpdatePCIdx(profiler_, ProfileEntry::NullPCIndex, scratch);
         setPushed(script);
     }
 
     /*
      * Signals that the current function is leaving for a function call. This
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -1738,17 +1738,17 @@ DebugScopes::onPopCall(StackFrame *fp, J
 {
     JS_ASSERT(!fp->isYielding());
     assertSameCompartment(cx, fp);
 
     DebugScopes *scopes = cx->compartment->debugScopes;
     if (!scopes)
         return;
 
-    DebugScopeObject *debugScope = NULL;
+    Rooted<DebugScopeObject*> debugScope(cx, NULL);
 
     if (fp->fun()->isHeavyweight()) {
         /*
          * The StackFrame may be observed before the prologue has created the
          * CallObject. See ScopeIter::settle.
          */
         if (!fp->hasCallObj())
             return;