Bug 959787 - Handlify several JSAPI interfaces that can GC, Part 5; r=jonco
authorTerrence Cole <terrence@mozilla.com>
Fri, 17 Jan 2014 10:09:38 -0800
changeset 164104 e40cf0c641b5543556240c97a08213e3b4c7a615
parent 164103 21cef8b355cea6e7785ef61567e1ea4f752f305b
child 164105 811f4c3267b6c0026067160f0aaaafc42cd87fc7
push id26026
push userphilringnalda@gmail.com
push dateSat, 18 Jan 2014 23:17:27 +0000
treeherdermozilla-central@61fd0f987cf2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco
bugs959787
milestone29.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 959787 - Handlify several JSAPI interfaces that can GC, Part 5; r=jonco
content/base/src/nsDocument.cpp
dom/bindings/BindingUtils.cpp
dom/xbl/nsXBLProtoImplMethod.cpp
dom/xbl/nsXBLPrototypeHandler.cpp
js/public/OldDebugAPI.h
js/src/gdb/tests/test-JSObject.cpp
js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsopcode.cpp
js/src/shell/js.cpp
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -5381,17 +5381,17 @@ nsDocument::Register(JSContext* aCx, con
 
   nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
                                        NS_LITERAL_STRING("elementupgrade"),
                                        true, true);
 
   // Create constructor to return. Store the name of the custom element as the
   // name of the function.
   JSFunction* constructor = JS_NewFunction(aCx, CustomElementConstructor, 0,
-                                           JSFUN_CONSTRUCTOR, nullptr,
+                                           JSFUN_CONSTRUCTOR, JS::NullPtr(),
                                            NS_ConvertUTF16toUTF8(lcName).get());
   JSObject* constructorObject = JS_GetFunctionObject(constructor);
   return constructorObject;
 }
 
 NS_IMETHODIMP
 nsDocument::GetElementsByTagName(const nsAString& aTagname,
                                  nsIDOMNodeList** aReturn)
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1604,17 +1604,18 @@ NativeToString(JSContext* cx, JS::Handle
           str = JS_NewStringCopyZ(cx, clasp->name);
           str = ConcatJSString(cx, "[object ", str, "]");
         } else if (IsDOMIfaceAndProtoClass(clasp)) {
           const DOMIfaceAndProtoJSClass* ifaceAndProtoJSClass =
             DOMIfaceAndProtoJSClass::FromJSClass(clasp);
           str = JS_NewStringCopyZ(cx, ifaceAndProtoJSClass->mToString);
         } else {
           MOZ_ASSERT(JS_IsNativeFunction(obj, Constructor));
-          str = JS_DecompileFunction(cx, JS_GetObjectFunction(obj), 0);
+          JS::Rooted<JSFunction*> fun(cx, JS_GetObjectFunction(obj));
+          str = JS_DecompileFunction(cx, fun, 0);
         }
       }
       str = ConcatJSString(cx, pre, str, post);
     }
   }
 
   if (!str) {
     return false;
--- a/dom/xbl/nsXBLProtoImplMethod.cpp
+++ b/dom/xbl/nsXBLProtoImplMethod.cpp
@@ -315,17 +315,18 @@ nsXBLProtoImplAnonymousMethod::Execute(n
 
   JSAutoCompartment ac(cx, scopeObject);
   if (!JS_WrapObject(cx, &thisObject))
       return NS_ERROR_OUT_OF_MEMORY;
 
   // Clone the function object, using thisObject as the parent so "this" is in
   // the scope chain of the resulting function (for backwards compat to the
   // days when this was an event handler).
-  JS::Rooted<JSObject*> method(cx, ::JS_CloneFunctionObject(cx, GetCompiledMethod(), thisObject));
+  JS::Rooted<JSObject*> jsMethodObject(cx, GetCompiledMethod());
+  JS::Rooted<JSObject*> method(cx, ::JS_CloneFunctionObject(cx, jsMethodObject, thisObject));
   if (!method)
     return NS_ERROR_OUT_OF_MEMORY;
 
   // Now call the method
 
   // Check whether script is enabled.
   bool scriptAllowed = nsContentUtils::GetSecurityManager()->
                          ScriptAllowed(js::GetGlobalForObjectCrossCompartment(method));
--- a/dom/xbl/nsXBLPrototypeHandler.cpp
+++ b/dom/xbl/nsXBLPrototypeHandler.cpp
@@ -307,17 +307,18 @@ nsXBLPrototypeHandler::ExecuteHandler(Ev
   // scope if one doesn't already exist, and potentially wraps it cross-
   // compartment into our scope (via aAllowWrapping=true).
   JS::Rooted<JS::Value> targetV(cx, JS::UndefinedValue());
   rv = nsContentUtils::WrapNative(cx, scopeObject, scriptTarget, &targetV,
                                   /* aAllowWrapping = */ true);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Next, clone the generic handler to be parented to the target.
-  JS::Rooted<JSObject*> bound(cx, JS_CloneFunctionObject(cx, genericHandler, &targetV.toObject()));
+  JS::Rooted<JSObject*> target(cx, &targetV.toObject());
+  JS::Rooted<JSObject*> bound(cx, JS_CloneFunctionObject(cx, genericHandler, target));
   NS_ENSURE_TRUE(bound, NS_ERROR_FAILURE);
 
   // Now, wrap the bound handler into the content compartment and use it.
   JSAutoCompartment ac2(cx, globalObject);
   if (!JS_WrapObject(cx, &bound)) {
     return NS_ERROR_FAILURE;
   }
 
--- a/js/public/OldDebugAPI.h
+++ b/js/public/OldDebugAPI.h
@@ -7,17 +7,17 @@
 #ifndef js_OldDebugAPI_h
 #define js_OldDebugAPI_h
 
 /*
  * JS debugger API.
  */
 
 #include "mozilla/NullPtr.h"
- 
+
 #include "jsbytecode.h"
 
 #include "js/CallArgs.h"
 #include "js/TypeDecls.h"
 
 class JSAtom;
 class JSFreeOp;
 
@@ -138,17 +138,17 @@ typedef void
                     size_t length, void **listenerTSData, void *closure);
 
 
 
 extern JS_PUBLIC_API(JSCompartment *)
 JS_EnterCompartmentOfScript(JSContext *cx, JSScript *target);
 
 extern JS_PUBLIC_API(JSString *)
-JS_DecompileScript(JSContext *cx, JSScript *script, const char *name, unsigned indent);
+JS_DecompileScript(JSContext *cx, JS::HandleScript script, const char *name, unsigned indent);
 
 /*
  * Currently, we only support runtime-wide debugging. In the future, we should
  * be able to support compartment-wide debugging.
  */
 extern JS_PUBLIC_API(void)
 JS_SetRuntimeDebugMode(JSRuntime *rt, bool debug);
 
--- a/js/src/gdb/tests/test-JSObject.cpp
+++ b/js/src/gdb/tests/test-JSObject.cpp
@@ -1,20 +1,20 @@
 #include "gdb-tests.h"
 #include "jsapi.h"
 
 FRAGMENT(JSObject, simple) {
   JS::Rooted<JSObject *> glob(cx, JS::CurrentGlobalOrNull(cx));
   JS::Rooted<JSObject *> plain(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
+  JS::Rooted<JSObject *> global(cx, JS::CurrentGlobalOrNull(cx));
   JS::Rooted<JSObject *> func(cx, (JSObject *) JS_NewFunction(cx, (JSNative) 1, 0, 0,
-                                                              JS::CurrentGlobalOrNull(cx), "dys"));
-  JS::Rooted<JSObject *> anon(cx, (JSObject *) JS_NewFunction(cx, (JSNative) 1, 0, 0,
-                                                              JS::CurrentGlobalOrNull(cx), 0));
+                                                              global, "dys"));
+  JS::Rooted<JSObject *> anon(cx, (JSObject *) JS_NewFunction(cx, (JSNative) 1, 0, 0, global, 0));
   JS::Rooted<JSFunction *> funcPtr(cx, JS_NewFunction(cx, (JSNative) 1, 0, 0,
-                                                      JS::CurrentGlobalOrNull(cx), "formFollows"));
+                                                      global, "formFollows"));
 
   JSObject &plainRef = *plain;
   JSFunction &funcRef = *funcPtr;
   JSObject *plainRaw = plain;
   JSObject *funcRaw = func;
 
   breakpoint();
 
--- a/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp
+++ b/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp
@@ -17,22 +17,22 @@ BEGIN_TEST(testDefineGetterSetterNonEnum
 {
     static const char PROPERTY_NAME[] = "foo";
 
     JS::RootedValue vobj(cx);
     JS::RootedObject obj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
     CHECK(obj);
     vobj = OBJECT_TO_JSVAL(obj);
 
-    JSFunction *funGet = JS_NewFunction(cx, NativeGetterSetter, 0, 0, nullptr, "get");
+    JSFunction *funGet = JS_NewFunction(cx, NativeGetterSetter, 0, 0, JS::NullPtr(), "get");
     CHECK(funGet);
     JS::RootedObject funGetObj(cx, JS_GetFunctionObject(funGet));
     JS::RootedValue vget(cx, OBJECT_TO_JSVAL(funGetObj));
 
-    JSFunction *funSet = JS_NewFunction(cx, NativeGetterSetter, 1, 0, nullptr, "set");
+    JSFunction *funSet = JS_NewFunction(cx, NativeGetterSetter, 1, 0, JS::NullPtr(), "set");
     CHECK(funSet);
     JS::RootedObject funSetObj(cx, JS_GetFunctionObject(funSet));
     JS::RootedValue vset(cx, OBJECT_TO_JSVAL(funSetObj));
 
     JS::RootedObject vObject(cx, JSVAL_TO_OBJECT(vobj));
     CHECK(JS_DefineProperty(cx, vObject, PROPERTY_NAME,
                             JSVAL_VOID,
                             JS_DATA_TO_FUNC_PTR(JSPropertyOp, (JSObject*) funGetObj),
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3841,19 +3841,18 @@ JS_InitDestroyPrincipalsCallback(JSRunti
 {
     JS_ASSERT(destroyPrincipals);
     JS_ASSERT(!rt->destroyPrincipals);
     rt->destroyPrincipals = destroyPrincipals;
 }
 
 JS_PUBLIC_API(JSFunction *)
 JS_NewFunction(JSContext *cx, JSNative native, unsigned nargs, unsigned flags,
-               JSObject *parentArg, const char *name)
-{
-    RootedObject parent(cx, parentArg);
+               HandleObject parent, const char *name)
+{
     JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
 
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, parent);
 
     RootedAtom atom(cx);
     if (name) {
@@ -3862,34 +3861,33 @@ JS_NewFunction(JSContext *cx, JSNative n
             return nullptr;
     }
 
     JSFunction::Flags funFlags = JSAPIToJSFunctionFlags(flags);
     return NewFunction(cx, NullPtr(), native, nargs, funFlags, parent, atom);
 }
 
 JS_PUBLIC_API(JSFunction *)
-JS_NewFunctionById(JSContext *cx, JSNative native, unsigned nargs, unsigned flags, JSObject *parentArg,
-                   jsid id)
-{
-    RootedObject parent(cx, parentArg);
+JS_NewFunctionById(JSContext *cx, JSNative native, unsigned nargs, unsigned flags,
+                   HandleObject parent, HandleId id)
+{
     JS_ASSERT(JSID_IS_STRING(id));
     JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
     JS_ASSERT(native);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, parent);
 
     RootedAtom name(cx, JSID_TO_ATOM(id));
     JSFunction::Flags funFlags = JSAPIToJSFunctionFlags(flags);
     return NewFunction(cx, NullPtr(), native, nargs, funFlags, parent, name);
 }
 
 JS_PUBLIC_API(JSFunction *)
-JS::GetSelfHostedFunction(JSContext *cx, const char *selfHostedName, jsid id, unsigned nargs)
+JS::GetSelfHostedFunction(JSContext *cx, const char *selfHostedName, HandleId id, unsigned nargs)
 {
     JS_ASSERT(JSID_IS_STRING(id));
     JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     RootedAtom name(cx, JSID_TO_ATOM(id));
     RootedAtom shName(cx, Atomize(cx, selfHostedName, strlen(selfHostedName)));
@@ -3897,20 +3895,20 @@ JS::GetSelfHostedFunction(JSContext *cx,
         return nullptr;
     RootedValue funVal(cx);
     if (!cx->global()->getSelfHostedFunction(cx, shName, name, nargs, &funVal))
         return nullptr;
     return &funVal.toObject().as<JSFunction>();
 }
 
 JS_PUBLIC_API(JSObject *)
-JS_CloneFunctionObject(JSContext *cx, JSObject *funobjArg, JSObject *parentArg)
-{
-    RootedObject funobj(cx, funobjArg);
+JS_CloneFunctionObject(JSContext *cx, HandleObject funobj, HandleObject parentArg)
+{
     RootedObject parent(cx, parentArg);
+
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, parent);
     // Note that funobj can be in a different compartment.
 
     if (!parent)
         parent = cx->global();
 
@@ -3998,19 +3996,18 @@ JS_IsNativeFunction(JSObject *funobj, JS
 
 extern JS_PUBLIC_API(bool)
 JS_IsConstructor(JSFunction *fun)
 {
     return fun->isNativeConstructor() || fun->isInterpretedConstructor();
 }
 
 JS_PUBLIC_API(JSObject*)
-JS_BindCallable(JSContext *cx, JSObject *targetArg, JSObject *newThis)
-{
-    RootedObject target(cx, targetArg);
+JS_BindCallable(JSContext *cx, HandleObject target, HandleObject newThis)
+{
     RootedValue thisArg(cx, ObjectValue(*newThis));
     return js_fun_bind(cx, target, thisArg, nullptr, 0);
 }
 
 static bool
 js_generic_native_method_dispatcher(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -4034,24 +4031,23 @@ js_generic_native_method_dispatcher(JSCo
 
     /* Clear the last parameter in case too few arguments were passed. */
     vp[2 + --argc].setUndefined();
 
     return fs->call.op(cx, argc, vp);
 }
 
 JS_PUBLIC_API(bool)
-JS_DefineFunctions(JSContext *cx, JSObject *objArg, const JSFunctionSpec *fs)
+JS_DefineFunctions(JSContext *cx, HandleObject obj, const JSFunctionSpec *fs)
 {
     JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    assertSameCompartment(cx, objArg);
-
-    RootedObject obj(cx, objArg);
+    assertSameCompartment(cx, obj);
+
     RootedObject ctor(cx);
 
     for (; fs->name; fs++) {
         RootedAtom atom(cx);
         // If the name starts with "@@", it must be a well-known symbol.
         if (fs->name[0] != '@' || fs->name[1] != '@')
             atom = Atomize(cx, fs->name, strlen(fs->name));
         else if (strcmp(fs->name, "@@iterator") == 0)
@@ -4486,19 +4482,18 @@ JS_CompileScript(JSContext *cx, JS::Hand
 JS_PUBLIC_API(JSScript *)
 JS_CompileUCScript(JSContext *cx, JS::HandleObject obj, const jschar *chars,
                    size_t length, const JS::CompileOptions &options)
 {
     return Compile(cx, obj, options, chars, length);
 }
 
 JS_PUBLIC_API(bool)
-JS_BufferIsCompilableUnit(JSContext *cx, JSObject *objArg, const char *utf8, size_t length)
-{
-    RootedObject obj(cx, objArg);
+JS_BufferIsCompilableUnit(JSContext *cx, HandleObject obj, const char *utf8, size_t length)
+{
     bool result;
     JSExceptionState *exnState;
     JSErrorReporter older;
 
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     jschar *chars = JS::UTF8CharsToNewTwoByteCharsZ(cx, JS::UTF8Chars(utf8, length), &length).get();
@@ -4616,52 +4611,49 @@ JS_CompileFunction(JSContext *cx, JS::Ha
                    unsigned nargs, const char *const *argnames,
                    const char *ascii, size_t length,
                    const JS::CompileOptions &options)
 {
     return CompileFunction(cx, obj, options, name, nargs, argnames, ascii, length);
 }
 
 JS_PUBLIC_API(JSString *)
-JS_DecompileScript(JSContext *cx, JSScript *scriptArg, const char *name, unsigned indent)
+JS_DecompileScript(JSContext *cx, HandleScript script, const char *name, unsigned indent)
 {
     JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
 
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    RootedScript script(cx, scriptArg);
     script->ensureNonLazyCanonicalFunction(cx);
     RootedFunction fun(cx, script->functionNonDelazifying());
     if (fun)
         return JS_DecompileFunction(cx, fun, indent);
     bool haveSource = script->scriptSource()->hasSourceData();
     if (!haveSource && !JSScript::loadSource(cx, script->scriptSource(), &haveSource))
         return nullptr;
     return haveSource ? script->sourceData(cx) : js_NewStringCopyZ<CanGC>(cx, "[no source]");
 }
 
 JS_PUBLIC_API(JSString *)
-JS_DecompileFunction(JSContext *cx, JSFunction *funArg, unsigned indent)
+JS_DecompileFunction(JSContext *cx, HandleFunction fun, unsigned indent)
 {
     JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    assertSameCompartment(cx, funArg);
-    RootedFunction fun(cx, funArg);
+    assertSameCompartment(cx, fun);
     return FunctionToString(cx, fun, false, !(indent & JS_DONT_PRETTY_PRINT));
 }
 
 JS_PUBLIC_API(JSString *)
-JS_DecompileFunctionBody(JSContext *cx, JSFunction *funArg, unsigned indent)
+JS_DecompileFunctionBody(JSContext *cx, HandleFunction fun, unsigned indent)
 {
     JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    assertSameCompartment(cx, funArg);
-    RootedFunction fun(cx, funArg);
+    assertSameCompartment(cx, fun);
     return FunctionToString(cx, fun, true, !(indent & JS_DONT_PRETTY_PRINT));
 }
 
 JS_NEVER_INLINE JS_PUBLIC_API(bool)
 JS_ExecuteScript(JSContext *cx, JSObject *objArg, JSScript *scriptArg, jsval *rval)
 {
     RootedObject obj(cx, objArg);
     RootedScript script(cx, scriptArg);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -3252,30 +3252,31 @@ JS_InitDestroyPrincipalsCallback(JSRunti
 
 /************************************************************************/
 
 /*
  * Functions and scripts.
  */
 extern JS_PUBLIC_API(JSFunction *)
 JS_NewFunction(JSContext *cx, JSNative call, unsigned nargs, unsigned flags,
-               JSObject *parent, const char *name);
+               JS::Handle<JSObject*> parent, const char *name);
 
 /*
  * Create the function with the name given by the id. JSID_IS_STRING(id) must
  * be true.
  */
 extern JS_PUBLIC_API(JSFunction *)
 JS_NewFunctionById(JSContext *cx, JSNative call, unsigned nargs, unsigned flags,
-                   JSObject *parent, jsid id);
+                   JS::Handle<JSObject*> parent, JS::Handle<jsid> id);
 
 namespace JS {
 
 extern JS_PUBLIC_API(JSFunction *)
-GetSelfHostedFunction(JSContext *cx, const char *selfHostedName, jsid id, unsigned nargs);
+GetSelfHostedFunction(JSContext *cx, const char *selfHostedName, JS::Handle<jsid> id,
+                      unsigned nargs);
 
 } /* namespace JS */
 
 extern JS_PUBLIC_API(JSObject *)
 JS_GetFunctionObject(JSFunction *fun);
 
 /*
  * Return the function's identifier as a JSString, or null if fun is unnamed.
@@ -3322,20 +3323,20 @@ extern JS_PUBLIC_API(bool)
 JS_IsConstructor(JSFunction *fun);
 
 /*
  * Bind the given callable to use the given object as "this".
  *
  * If |callable| is not callable, will throw and return nullptr.
  */
 extern JS_PUBLIC_API(JSObject*)
-JS_BindCallable(JSContext *cx, JSObject *callable, JSObject *newThis);
+JS_BindCallable(JSContext *cx, JS::Handle<JSObject*> callable, JS::Handle<JSObject*> newThis);
 
 extern JS_PUBLIC_API(bool)
-JS_DefineFunctions(JSContext *cx, JSObject *obj, const JSFunctionSpec *fs);
+JS_DefineFunctions(JSContext *cx, JS::Handle<JSObject*> obj, const JSFunctionSpec *fs);
 
 extern JS_PUBLIC_API(JSFunction *)
 JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call,
                   unsigned nargs, unsigned attrs);
 
 extern JS_PUBLIC_API(JSFunction *)
 JS_DefineUCFunction(JSContext *cx, JSObject *obj,
                     const jschar *name, size_t namelen, JSNative call,
@@ -3345,27 +3346,28 @@ extern JS_PUBLIC_API(JSFunction *)
 JS_DefineFunctionById(JSContext *cx, JSObject *obj, jsid id, JSNative call,
                       unsigned nargs, unsigned attrs);
 
 /*
  * Clone a top-level function into a new scope. This function will dynamically
  * fail if funobj was lexically nested inside some other function.
  */
 extern JS_PUBLIC_API(JSObject *)
-JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent);
+JS_CloneFunctionObject(JSContext *cx, JS::Handle<JSObject*> funobj, JS::Handle<JSObject*> parent);
 
 /*
  * Given a buffer, return false if the buffer might become a valid
  * javascript statement with the addition of more lines.  Otherwise return
  * true.  The intent is to support interactive compilation - accumulate
  * lines in a buffer until JS_BufferIsCompilableUnit is true, then pass it to
  * the compiler.
  */
 extern JS_PUBLIC_API(bool)
-JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj, const char *utf8, size_t length);
+JS_BufferIsCompilableUnit(JSContext *cx, JS::Handle<JSObject*> obj, const char *utf8,
+                          size_t length);
 
 extern JS_PUBLIC_API(JSScript *)
 JS_CompileScript(JSContext *cx, JS::HandleObject obj,
                  const char *ascii, size_t length,
                  const JS::CompileOptions &options);
 
 extern JS_PUBLIC_API(JSScript *)
 JS_CompileUCScript(JSContext *cx, JS::HandleObject obj,
@@ -3679,29 +3681,29 @@ CompileFunction(JSContext *cx, JS::Handl
 extern JS_PUBLIC_API(JSFunction *)
 CompileFunction(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options,
                 const char *name, unsigned nargs, const char *const *argnames,
                 const jschar *chars, size_t length);
 
 } /* namespace JS */
 
 extern JS_PUBLIC_API(JSString *)
-JS_DecompileScript(JSContext *cx, JSScript *script, const char *name, unsigned indent);
+JS_DecompileScript(JSContext *cx, JS::Handle<JSScript*> script, const char *name, unsigned indent);
 
 /*
  * API extension: OR this into indent to avoid pretty-printing the decompiled
  * source resulting from JS_DecompileFunction{,Body}.
  */
 #define JS_DONT_PRETTY_PRINT    ((unsigned)0x8000)
 
 extern JS_PUBLIC_API(JSString *)
-JS_DecompileFunction(JSContext *cx, JSFunction *fun, unsigned indent);
+JS_DecompileFunction(JSContext *cx, JS::Handle<JSFunction*> fun, unsigned indent);
 
 extern JS_PUBLIC_API(JSString *)
-JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, unsigned indent);
+JS_DecompileFunctionBody(JSContext *cx, JS::Handle<JSFunction*> fun, unsigned indent);
 
 /*
  * NB: JS_ExecuteScript and the JS_Evaluate*Script* quadruplets use the obj
  * parameter as the initial scope chain header, the 'this' keyword value, and
  * the variables object (ECMA parlance for where 'var' and 'function' bind
  * names) of the execution context for script.
  *
  * Using obj as the variables object is problematic if obj's parent (which is
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -870,17 +870,18 @@ ToDisassemblySource(JSContext *cx, Handl
             source = JS_sprintf_append(source, "}");
             if (!source)
                 return false;
             bytes->initBytes(source);
             return true;
         }
 
         if (obj->is<JSFunction>()) {
-            JSString *str = JS_DecompileFunction(cx, &obj->as<JSFunction>(), JS_DONT_PRETTY_PRINT);
+            RootedFunction fun(cx, &obj->as<JSFunction>());
+            JSString *str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT);
             if (!str)
                 return false;
             return bytes->encodeLatin1(cx, str);
         }
 
         if (obj->is<RegExpObject>()) {
             JSString *source = obj->as<RegExpObject>().toString(cx);
             if (!source)
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -3670,24 +3670,25 @@ NestedShell(JSContext *cx, unsigned argc
     }
 
     args.rval().setUndefined();
     return true;
 }
 
 static bool
 DecompileFunctionSomehow(JSContext *cx, unsigned argc, Value *vp,
-                         JSString *(*decompiler)(JSContext *, JSFunction *, unsigned))
+                         JSString *(*decompiler)(JSContext *, HandleFunction, unsigned))
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() < 1 || !args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
         args.rval().setUndefined();
         return true;
     }
-    JSString *result = decompiler(cx, &args[0].toObject().as<JSFunction>(), 0);
+    RootedFunction fun(cx, &args[0].toObject().as<JSFunction>());
+    JSString *result = decompiler(cx, fun, 0);
     if (!result)
         return false;
     args.rval().setString(result);
     return true;
 }
 
 static bool
 DecompileBody(JSContext *cx, unsigned argc, Value *vp)