Bug 912581 - Make JS_Add*Root APIs take Heap<T> r=terrence r=bz r=bholley
authorJon Coppeard <jcoppeard@mozilla.com>
Wed, 16 Apr 2014 09:47:57 +0100
changeset 198367 ce496597e5eb7a546ec60a0d43611c100ad3f25f
parent 198366 df934e78525e1b7640189e6fb8b99b5c1a36bb4f
child 198368 a668d68c3592a14581b69bea1433b1680da38c7f
push id486
push userasasaki@mozilla.com
push dateMon, 14 Jul 2014 18:39:42 +0000
treeherdermozilla-release@d33428174ff1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence, bz, bholley
bugs912581
milestone31.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 912581 - Make JS_Add*Root APIs take Heap<T> r=terrence r=bz r=bholley
dom/bindings/BindingUtils.cpp
ipc/testshell/TestShellParent.cpp
js/jsd/jsd.h
js/jsd/jsd_high.cpp
js/jsd/jsd_val.cpp
js/src/jsapi-tests/testChromeBuffer.cpp
js/src/jsapi-tests/testNullRoot.cpp
js/src/jsapi-tests/testResolveRecursion.cpp
js/src/jsapi-tests/tests.cpp
js/src/jsapi-tests/tests.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsfriendapi.h
js/src/jsgc.cpp
js/xpconnect/public/nsAutoJSValHolder.h
js/xpconnect/src/XPCWrappedNative.cpp
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -182,17 +182,17 @@ ErrorResult::ThrowJSException(JSContext*
   if (IsTypeError()) {
     delete mMessage;
   }
 
   // Make sure mJSException is initialized _before_ we try to root it.  But
   // don't set it to exn yet, because we don't want to do that until after we
   // root.
   mJSException = JS::UndefinedValue();
-  if (!JS_AddNamedValueRoot(cx, &mJSException, "ErrorResult::mJSException")) {
+  if (!js::AddRawValueRoot(cx, &mJSException, "ErrorResult::mJSException")) {
     // Don't use NS_ERROR_DOM_JS_EXCEPTION, because that indicates we have
     // in fact rooted mJSException.
     mResult = NS_ERROR_OUT_OF_MEMORY;
   } else {
     mJSException = exn;
     mResult = NS_ERROR_DOM_JS_EXCEPTION;
   }
 }
@@ -205,17 +205,17 @@ ErrorResult::ReportJSException(JSContext
 
   JS::Rooted<JS::Value> exception(cx, mJSException);
   if (JS_WrapValue(cx, &exception)) {
     JS_SetPendingException(cx, exception);
   }
   mJSException = exception;
   // If JS_WrapValue failed, not much we can do about it...  No matter
   // what, go ahead and unroot mJSException.
-  JS_RemoveValueRoot(cx, &mJSException);
+  js::RemoveRawValueRoot(cx, &mJSException);
 }
 
 void
 ErrorResult::ReportJSExceptionFromJSImplementation(JSContext* aCx)
 {
   MOZ_ASSERT(!mMightHaveUnreportedJSException,
              "Why didn't you tell us you planned to handle JS exceptions?");
 
@@ -230,33 +230,33 @@ ErrorResult::ReportJSExceptionFromJSImpl
     // went really wrong.
     NS_RUNTIMEABORT("We stored a non-DOMError exception!");
   }
 
   nsString message;
   domError->GetMessage(message);
 
   JS_ReportError(aCx, "%hs", message.get());
-  JS_RemoveValueRoot(aCx, &mJSException);
+  js::RemoveRawValueRoot(aCx, &mJSException);
 
   // We no longer have a useful exception but we do want to signal that an error
   // occured.
   mResult = NS_ERROR_FAILURE;
 }
 
 void
 ErrorResult::StealJSException(JSContext* cx,
                               JS::MutableHandle<JS::Value> value)
 {
   MOZ_ASSERT(!mMightHaveUnreportedJSException,
              "Must call WouldReportJSException unconditionally in all codepaths that might call StealJSException");
   MOZ_ASSERT(IsJSException(), "No exception to steal");
 
   value.set(mJSException);
-  JS_RemoveValueRoot(cx, &mJSException);
+  js::RemoveRawValueRoot(cx, &mJSException);
   mResult = NS_OK;
 }
 
 void
 ErrorResult::ReportNotEnoughArgsError(JSContext* cx,
                                       const char* ifaceName,
                                       const char* memberName)
 {
--- a/ipc/testshell/TestShellParent.cpp
+++ b/ipc/testshell/TestShellParent.cpp
@@ -54,17 +54,17 @@ TestShellCommandParent::SetCallback(JSCo
   mCx = aCx;
 
   return true;
 }
 
 bool
 TestShellCommandParent::RunCallback(const nsString& aResponse)
 {
-  NS_ENSURE_TRUE(*mCallback.ToJSValPtr() != JSVAL_NULL && mCx, false);
+  NS_ENSURE_TRUE(!mCallback.get().isNull() && mCx, false);
 
   // We're pulling a cx off the heap, so make sure it's stack-top.
   AutoCxPusher pusher(mCx);
   NS_ENSURE_TRUE(mCallback.ToJSObject(), false);
   JSAutoCompartment ac(mCx, mCallback.ToJSObject());
   JS::Rooted<JSObject*> global(mCx, JS::CurrentGlobalOrNull(mCx));
 
   JSString* str = JS_NewUCStringCopyN(mCx, aResponse.get(), aResponse.Length());
--- a/js/jsd/jsd.h
+++ b/js/jsd/jsd.h
@@ -93,17 +93,17 @@ struct JSDContext
     JSD_ExecutionHookProc   debuggerHook;
     void*                   debuggerHookData;
     JSD_ExecutionHookProc   throwHook;
     void*                   throwHookData;
     JSD_CallHookProc        functionHook;
     void*                   functionHookData;
     JSD_CallHookProc        toplevelHook;
     void*                   toplevelHookData;
-    JSObject*               glob;
+    JS::Heap<JSObject*>     glob;
     JSD_UserCallbacks       userCallbacks;
     void*                   user;
     JSCList                 scripts;
     JSHashTable*            scriptsTable;
     JSCList                 sources;
     JSCList                 removedSources;
     unsigned                   sourceAlterCount;
     JSHashTable*            atoms;
@@ -201,26 +201,26 @@ struct JSDStackFrameInfo
 
 #define GOT_PROTO   ((short) (1 << 0))
 #define GOT_PROPS   ((short) (1 << 1))
 #define GOT_PARENT  ((short) (1 << 2))
 #define GOT_CTOR    ((short) (1 << 3))
 
 struct JSDValue
 {
-    jsval       val;
-    int        nref;
-    JSCList     props;
-    JSString*   string;
-    JSString*   funName;
-    const char* className;
-    JSDValue*   proto;
-    JSDValue*   parent;
-    JSDValue*   ctor;
-    unsigned       flags;
+    JS::Heap<JS::Value> val;
+    int                 nref;
+    JSCList             props;
+    JS::Heap<JSString*> string;
+    JS::Heap<JSString*> funName;
+    const char*         className;
+    JSDValue*           proto;
+    JSDValue*           parent;
+    JSDValue*           ctor;
+    unsigned            flags;
 };
 
 struct JSDProperty
 {
     JSCList     links;      /* we are part of a JSCList */
     int        nref;
     JSDValue*   val;
     JSDValue*   name;
--- a/js/jsd/jsd_high.cpp
+++ b/js/jsd/jsd_high.cpp
@@ -114,43 +114,43 @@ static JSDContext*
         goto label_newJSDContext_failure;
 
     if( ! jsd_InitObjectManager(jsdc) )
         goto label_newJSDContext_failure;
 
     if( ! jsd_InitScriptManager(jsdc) )
         goto label_newJSDContext_failure;
 
-
-    jsdc->glob = CreateJSDGlobal(cx, &global_class);
+    {
+        JS::RootedObject global(cx, CreateJSDGlobal(cx, &global_class));
+        if( ! global )
+            goto label_newJSDContext_failure;
 
-    if( ! jsdc->glob )
-        goto label_newJSDContext_failure;
+        jsdc->glob = global;
 
-    {
         JSAutoCompartment ac(cx, jsdc->glob);
-        ok = JS_AddNamedObjectRoot(cx, &jsdc->glob, "JSD context global") &&
-             JS_InitStandardClasses(cx, JS::HandleObject::fromMarkedLocation(&jsdc->glob));
+        ok = JS::AddNamedObjectRoot(cx, &jsdc->glob, "JSD context global") &&
+             JS_InitStandardClasses(cx, global);
     }
     if( ! ok )
         goto label_newJSDContext_failure;
 
     jsdc->data = nullptr;
     jsdc->inited = true;
 
     JSD_LOCK();
     JS_INSERT_LINK(&jsdc->links, &_jsd_context_list);
     JSD_UNLOCK();
 
     return jsdc;
 
 label_newJSDContext_failure:
     if( jsdc ) {
         if ( jsdc->glob )
-            JS_RemoveObjectRootRT(JS_GetRuntime(cx), &jsdc->glob);
+            JS::RemoveObjectRootRT(JS_GetRuntime(cx), &jsdc->glob);
         jsd_DestroyObjectManager(jsdc);
         jsd_DestroyAtomTable(jsdc);
         free(jsdc);
     }
     return nullptr;
 }
 
 static void
@@ -158,17 +158,17 @@ static void
 {
     JSD_ASSERT_VALID_CONTEXT(jsdc);
 
     JSD_LOCK();
     JS_REMOVE_LINK(&jsdc->links);
     JSD_UNLOCK();
 
     if ( jsdc->glob ) {
-        JS_RemoveObjectRootRT(jsdc->jsrt, &jsdc->glob);
+        JS::RemoveObjectRootRT(jsdc->jsrt, &jsdc->glob);
     }
     jsd_DestroyObjectManager(jsdc);
     jsd_DestroyAtomTable(jsdc);
 
     jsdc->inited = false;
 
     /*
     * We should free jsdc here, but we let it leak in case there are any 
--- a/js/jsd/jsd_val.cpp
+++ b/js/jsd/jsd_val.cpp
@@ -197,17 +197,17 @@ jsd_GetValueString(JSDContext* jsdc, JSD
     if(string) {
         stringval = STRING_TO_JSVAL(string);
     }
     if(!string || !JS_WrapValue(cx, &stringval)) {
         return nullptr;
     }
 
     jsdval->string = JSVAL_TO_STRING(stringval);
-    if(!JS_AddNamedStringRoot(cx, &jsdval->string, "ValueString"))
+    if(!JS::AddNamedStringRoot(cx, &jsdval->string, "ValueString"))
         jsdval->string = nullptr;
 
     return jsdval->string;
 }
 
 JSString*
 jsd_GetValueFunctionId(JSDContext* jsdc, JSDValue* jsdval)
 {
@@ -247,17 +247,17 @@ jsd_NewValue(JSDContext* jsdc, jsval val
     if(!(jsdval = (JSDValue*) calloc(1, sizeof(JSDValue))))
         return nullptr;
 
     if(JSVAL_IS_GCTHING(val))
     {
         bool ok;
         JSAutoCompartment ac(cx, jsdc->glob);
 
-        ok = JS_AddNamedValueRoot(cx, &jsdval->val, "JSDValue");
+        ok = JS::AddNamedValueRoot(cx, &jsdval->val, "JSDValue");
         if(ok && JSVAL_IS_STRING(val)) {
             if(!JS_WrapValue(cx, &val)) {
                 ok = false;
             }
         }
 
         if(!ok)
         {
@@ -278,17 +278,17 @@ jsd_DropValue(JSDContext* jsdc, JSDValue
     MOZ_ASSERT(jsdval->nref > 0);
     if(0 == --jsdval->nref)
     {
         jsd_RefreshValue(jsdc, jsdval);
         if(JSVAL_IS_GCTHING(jsdval->val))
         {
             AutoSafeJSContext cx;
             JSAutoCompartment ac(cx, jsdc->glob);
-            JS_RemoveValueRoot(cx, &jsdval->val);
+            JS::RemoveValueRoot(cx, &jsdval->val);
         }
         free(jsdval);
     }
 }
 
 jsval
 jsd_GetValueWrappedJSVal(JSDContext* jsdc, JSDValue* jsdval)
 {
@@ -407,17 +407,17 @@ jsd_RefreshValue(JSDContext* jsdc, JSDVa
 {
     AutoSafeJSContext cx;
     if(jsdval->string)
     {
         /* if the jsval is a string, then we didn't need to root the string */
         if(!JSVAL_IS_STRING(jsdval->val))
         {
             JSAutoCompartment ac(cx, jsdc->glob);
-            JS_RemoveStringRoot(cx, &jsdval->string);
+            JS::RemoveStringRoot(cx, &jsdval->string);
         }
         jsdval->string = nullptr;
     }
 
     jsdval->funName = nullptr;
     jsdval->className = nullptr;
     DROP_CLEAR_VALUE(jsdc, jsdval->proto);
     DROP_CLEAR_VALUE(jsdc, jsdval->parent);
--- a/js/src/jsapi-tests/testChromeBuffer.cpp
+++ b/js/src/jsapi-tests/testChromeBuffer.cpp
@@ -20,18 +20,18 @@ static const JSClass global_class = {
     JS_ConvertStub,
     nullptr,
     nullptr,
     nullptr,
     nullptr,
     JS_GlobalObjectTraceHook
 };
 
-static JSObject *trusted_glob = nullptr;
-static JSObject *trusted_fun = nullptr;
+static JS::Heap<JSObject *> trusted_glob;
+static JS::Heap<JSObject *> trusted_fun;
 
 static bool
 CallTrusted(JSContext *cx, unsigned argc, jsval *vp)
 {
     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
 
     if (!JS_SaveFrameChain(cx))
         return false;
@@ -48,38 +48,38 @@ CallTrusted(JSContext *cx, unsigned argc
 
 BEGIN_TEST(testChromeBuffer)
 {
     JS_SetTrustedPrincipals(rt, &system_principals);
 
     trusted_glob = JS_NewGlobalObject(cx, &global_class, &system_principals, JS::FireOnNewGlobalHook);
     CHECK(trusted_glob);
 
-    if (!JS_AddNamedObjectRoot(cx, &trusted_glob, "trusted-global"))
+    if (!JS::AddNamedObjectRoot(cx, &trusted_glob, "trusted-global"))
         return false;
 
     JS::RootedFunction fun(cx);
 
     /*
      * Check that, even after untrusted content has exhausted the stack, code
      * compiled with "trusted principals" can run using reserved trusted-only
      * buffer space.
      */
     {
         {
             JSAutoCompartment ac(cx, trusted_glob);
             const char *paramName = "x";
             const char *bytes = "return x ? 1 + trusted(x-1) : 0";
-            JS::HandleObject global = JS::HandleObject::fromMarkedLocation(&trusted_glob);
+            JS::HandleObject global = JS::HandleObject::fromMarkedLocation(trusted_glob.unsafeGet());
             JS::CompileOptions options(cx);
             options.setFileAndLine("", 0);
             CHECK(fun = JS_CompileFunction(cx, global, "trusted", 1, &paramName,
                                            bytes, strlen(bytes), options));
             trusted_fun = JS_GetFunctionObject(fun);
-            if (!JS_AddNamedObjectRoot(cx, &trusted_fun, "trusted-function"))
+            if (!JS::AddNamedObjectRoot(cx, &trusted_fun, "trusted-function"))
                 return false;
         }
 
         JS::RootedValue v(cx, JS::ObjectValue(*trusted_fun));
         CHECK(JS_WrapValue(cx, &v));
 
         const char *paramName = "trusted";
         const char *bytes = "try {                                      "
@@ -109,17 +109,17 @@ BEGIN_TEST(testChromeBuffer)
         {
             JSAutoCompartment ac(cx, trusted_glob);
             const char *paramName = "untrusted";
             const char *bytes = "try {                                  "
                                 "  untrusted();                         "
                                 "} catch (e) {                          "
                                 "  return 'From trusted: ' + e;         "
                                 "}                                      ";
-            JS::HandleObject global = JS::HandleObject::fromMarkedLocation(&trusted_glob);
+            JS::HandleObject global = JS::HandleObject::fromMarkedLocation(trusted_glob.unsafeGet());
             JS::CompileOptions options(cx);
             options.setFileAndLine("", 0);
             CHECK(fun = JS_CompileFunction(cx, global, "trusted", 1, &paramName,
                                            bytes, strlen(bytes), options));
             trusted_fun = JS_GetFunctionObject(fun);
         }
 
         JS::RootedValue v(cx, JS::ObjectValue(*trusted_fun));
@@ -146,17 +146,17 @@ BEGIN_TEST(testChromeBuffer)
     /*
      * Check that JS_SaveFrameChain called on the way from content to chrome
      * (say, as done by XPCJSContextSTack::Push) works.
      */
     {
         {
             JSAutoCompartment ac(cx, trusted_glob);
             const char *bytes = "return 42";
-            JS::HandleObject global = JS::HandleObject::fromMarkedLocation(&trusted_glob);
+            JS::HandleObject global = JS::HandleObject::fromMarkedLocation(trusted_glob.unsafeGet());
             JS::CompileOptions options(cx);
             options.setFileAndLine("", 0);
             CHECK(fun = JS_CompileFunction(cx, global, "trusted", 0, nullptr,
                                            bytes, strlen(bytes), options));
             trusted_fun = JS_GetFunctionObject(fun);
         }
 
         JS::RootedFunction fun(cx, JS_NewFunction(cx, CallTrusted, 0, 0, global, "callTrusted"));
@@ -177,13 +177,15 @@ BEGIN_TEST(testChromeBuffer)
         JS::RootedValue rval(cx);
         CHECK(JS_CallFunction(cx, JS::NullPtr(), fun, arg, &rval));
         CHECK(JSVAL_TO_INT(rval) == 42);
     }
 
     return true;
 }
 virtual void uninit() {
-    JS_RemoveObjectRoot(cx, &trusted_glob);
-    JS_RemoveObjectRoot(cx, &trusted_fun);
+    trusted_glob = nullptr;
+    trusted_fun = nullptr;
+    JS::RemoveObjectRoot(cx, &trusted_glob);
+    JS::RemoveObjectRoot(cx, &trusted_fun);
     JSAPITest::uninit();
 }
 END_TEST(testChromeBuffer)
--- a/js/src/jsapi-tests/testNullRoot.cpp
+++ b/js/src/jsapi-tests/testNullRoot.cpp
@@ -4,26 +4,30 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jsapi-tests/tests.h"
 
 BEGIN_TEST(testNullRoot)
 {
-    JS::RootedObject obj(cx);
-    CHECK(JS_AddObjectRoot(cx, obj.address()));
+    obj = nullptr;
+    CHECK(JS::AddObjectRoot(cx, &obj));
 
-    JS::RootedString str(cx);
-    CHECK(JS_AddStringRoot(cx, str.address()));
+    str = nullptr;
+    CHECK(JS::AddStringRoot(cx, &str));
 
-    JS::RootedScript script(cx);
-    CHECK(JS_AddNamedScriptRoot(cx, script.address(), "testNullRoot's script"));
+    script = nullptr;
+    CHECK(JS::AddNamedScriptRoot(cx, &script, "testNullRoot's script"));
 
     // This used to crash because obj was nullptr.
     JS_GC(cx->runtime());
 
-    JS_RemoveObjectRoot(cx, obj.address());
-    JS_RemoveStringRoot(cx, str.address());
-    JS_RemoveScriptRoot(cx, script.address());
+    JS::RemoveObjectRoot(cx, &obj);
+    JS::RemoveStringRoot(cx, &str);
+    JS::RemoveScriptRoot(cx, &script);
     return true;
 }
+
+JS::Heap<JSObject *> obj;
+JS::Heap<JSString *> str;
+JS::Heap<JSScript *> script;
 END_TEST(testNullRoot)
--- a/js/src/jsapi-tests/testResolveRecursion.cpp
+++ b/js/src/jsapi-tests/testResolveRecursion.cpp
@@ -23,18 +23,18 @@ BEGIN_TEST(testResolveRecursion)
         JS_PropertyStub,       // get
         JS_StrictPropertyStub, // set
         JS_EnumerateStub,
         (JSResolveOp) my_resolve,
         JS_ConvertStub
     };
 
     obj1 = obj2 = nullptr;
-    JS_AddObjectRoot(cx, &obj1);
-    JS_AddObjectRoot(cx, &obj2);
+    JS::AddObjectRoot(cx, &obj1);
+    JS::AddObjectRoot(cx, &obj2);
 
     obj1 = JS_NewObject(cx, &my_resolve_class, JS::NullPtr(), JS::NullPtr());
     CHECK(obj1);
     obj2 = JS_NewObject(cx, &my_resolve_class, JS::NullPtr(), JS::NullPtr());
     CHECK(obj2);
     JS_SetPrivate(obj1, this);
     JS_SetPrivate(obj2, this);
 
@@ -46,23 +46,25 @@ BEGIN_TEST(testResolveRecursion)
 
     /* Start the essence of the test via invoking the first resolve hook. */
     JS::RootedValue v(cx);
     EVAL("obj1.x", &v);
     CHECK_SAME(v, JSVAL_FALSE);
     CHECK_EQUAL(resolveEntryCount, 4);
     CHECK_EQUAL(resolveExitCount, 4);
 
-    JS_RemoveObjectRoot(cx, &obj1);
-    JS_RemoveObjectRoot(cx, &obj2);
+    obj1 = nullptr;
+    obj2 = nullptr;
+    JS::RemoveObjectRoot(cx, &obj1);
+    JS::RemoveObjectRoot(cx, &obj2);
     return true;
 }
 
-JSObject *obj1;
-JSObject *obj2;
+JS::Heap<JSObject *> obj1;
+JS::Heap<JSObject *> obj2;
 unsigned resolveEntryCount;
 unsigned resolveExitCount;
 
 struct AutoIncrCounters {
 
     AutoIncrCounters(cls_testResolveRecursion *t) : t(t) {
         t->resolveEntryCount++;
     }
--- a/js/src/jsapi-tests/tests.cpp
+++ b/js/src/jsapi-tests/tests.cpp
@@ -26,46 +26,45 @@ bool JSAPITest::init()
         return false;
     JS_EnterCompartment(cx, global);
     return true;
 }
 
 bool JSAPITest::exec(const char *bytes, const char *filename, int lineno)
 {
     JS::RootedValue v(cx);
-    JS::HandleObject global = JS::HandleObject::fromMarkedLocation(&this->global);
+    JS::HandleObject global = JS::HandleObject::fromMarkedLocation(this->global.unsafeGet());
     return JS_EvaluateScript(cx, global, bytes, strlen(bytes), filename, lineno, &v) ||
         fail(bytes, filename, lineno);
 }
 
 bool JSAPITest::evaluate(const char *bytes, const char *filename, int lineno,
                          JS::MutableHandleValue vp)
 {
-    JS::HandleObject global = JS::HandleObject::fromMarkedLocation(&this->global);
+    JS::HandleObject global = JS::HandleObject::fromMarkedLocation(this->global.unsafeGet());
     return JS_EvaluateScript(cx, global, bytes, strlen(bytes), filename, lineno, vp) ||
         fail(bytes, filename, lineno);
 }
 
 bool JSAPITest::definePrint()
 {
-    JS::HandleObject global = JS::HandleObject::fromMarkedLocation(&this->global);
+    JS::HandleObject global = JS::HandleObject::fromMarkedLocation(this->global.unsafeGet());
     return JS_DefineFunction(cx, global, "print", (JSNative) print, 0, 0);
 }
 
 JSObject * JSAPITest::createGlobal(JSPrincipals *principals)
 {
     /* Create the global object. */
     JS::CompartmentOptions options;
     options.setVersion(JSVERSION_LATEST);
     global = JS_NewGlobalObject(cx, getGlobalClass(), principals, JS::FireOnNewGlobalHook, options);
     if (!global)
         return nullptr;
-    JS_AddNamedObjectRoot(cx, &global, "test-global");
-    JS::HandleObject globalHandle = JS::HandleObject::fromMarkedLocation(&global);
-
+    JS::AddNamedObjectRoot(cx, &global, "test-global");
+    JS::HandleObject globalHandle = JS::HandleObject::fromMarkedLocation(global.unsafeGet());
     JSAutoCompartment ac(cx, globalHandle);
 
     /* Populate the global object with the standard globals, like Object and
        Array. */
     if (!JS_InitStandardClasses(cx, globalHandle))
         return nullptr;
     return global;
 }
@@ -90,17 +89,17 @@ int main(int argc, char *argv[])
 
         printf("%s\n", name);
         if (!test->init()) {
             printf("TEST-UNEXPECTED-FAIL | %s | Failed to initialize.\n", name);
             failures++;
             continue;
         }
 
-        JS::HandleObject global = JS::HandleObject::fromMarkedLocation(&test->global);
+        JS::HandleObject global = JS::HandleObject::fromMarkedLocation(test->global.unsafeGet());
         if (test->run(global)) {
             printf("TEST-PASS | %s | ok\n", name);
         } else {
             JSAPITestString messages = test->messages();
             printf("%s | %s | %.*s\n",
                    (test->knownFail ? "TEST-KNOWN-FAIL" : "TEST-UNEXPECTED-FAIL"),
                    name, (int) messages.length(), messages.begin());
             if (!test->knownFail)
--- a/js/src/jsapi-tests/tests.h
+++ b/js/src/jsapi-tests/tests.h
@@ -49,17 +49,17 @@ inline JSAPITestString operator+(JSAPITe
 class JSAPITest
 {
   public:
     static JSAPITest *list;
     JSAPITest *next;
 
     JSRuntime *rt;
     JSContext *cx;
-    JSObject *global;
+    JS::Heap<JSObject *> global;
     bool knownFail;
     JSAPITestString msgs;
     JSCompartment *oldCompartment;
 
     JSAPITest() : rt(nullptr), cx(nullptr), global(nullptr),
                   knownFail(false), oldCompartment(nullptr) {
         next = list;
         list = this;
@@ -69,18 +69,19 @@ class JSAPITest
 
     virtual bool init();
 
     virtual void uninit() {
         if (oldCompartment) {
             JS_LeaveCompartment(cx, oldCompartment);
             oldCompartment = nullptr;
         }
+        global = nullptr;
         if (cx) {
-            JS_RemoveObjectRoot(cx, &global);
+            JS::RemoveObjectRoot(cx, &global);
             JS_LeaveCompartment(cx, nullptr);
             JS_EndRequest(cx);
             JS_DestroyContext(cx);
             cx = nullptr;
         }
         if (rt) {
             destroyRuntime();
             rt = nullptr;
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1481,129 +1481,137 @@ JS_strdup(JSRuntime *rt, const char *s)
     if (!p)
         return nullptr;
     return static_cast<char*>(js_memcpy(p, s, n));
 }
 
 #undef JS_AddRoot
 
 JS_PUBLIC_API(bool)
-JS_AddValueRoot(JSContext *cx, jsval *vp)
+JS::AddValueRoot(JSContext *cx, JS::Heap<JS::Value> *vp)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    return AddValueRoot(cx, vp, nullptr);
+    return AddValueRoot(cx, vp->unsafeGet(), nullptr);
 }
 
 JS_PUBLIC_API(bool)
-JS_AddStringRoot(JSContext *cx, JSString **rp)
+JS::AddStringRoot(JSContext *cx, JS::Heap<JSString *> *rp)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    return AddStringRoot(cx, rp, nullptr);
+    return AddStringRoot(cx, rp->unsafeGet(), nullptr);
 }
 
 JS_PUBLIC_API(bool)
-JS_AddObjectRoot(JSContext *cx, JSObject **rp)
+JS::AddObjectRoot(JSContext *cx, JS::Heap<JSObject *> *rp)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    return AddObjectRoot(cx, rp, nullptr);
+    return AddObjectRoot(cx, rp->unsafeGet(), nullptr);
 }
 
 JS_PUBLIC_API(bool)
-JS_AddNamedValueRoot(JSContext *cx, jsval *vp, const char *name)
+JS::AddNamedValueRoot(JSContext *cx, JS::Heap<JS::Value> *vp, const char *name)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    return AddValueRoot(cx, vp, name);
+    return AddValueRoot(cx, vp->unsafeGet(), name);
 }
 
 JS_PUBLIC_API(bool)
-JS_AddNamedValueRootRT(JSRuntime *rt, jsval *vp, const char *name)
-{
-    return AddValueRootRT(rt, vp, name);
+JS::AddNamedValueRootRT(JSRuntime *rt, JS::Heap<JS::Value> *vp, const char *name)
+{
+    return AddValueRootRT(rt, vp->unsafeGet(), name);
 }
 
 JS_PUBLIC_API(bool)
-JS_AddNamedStringRoot(JSContext *cx, JSString **rp, const char *name)
+JS::AddNamedStringRoot(JSContext *cx, JS::Heap<JSString *> *rp, const char *name)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    return AddStringRoot(cx, rp, name);
+    return AddStringRoot(cx, rp->unsafeGet(), name);
 }
 
 JS_PUBLIC_API(bool)
-JS_AddNamedObjectRoot(JSContext *cx, JSObject **rp, const char *name)
+JS::AddNamedObjectRoot(JSContext *cx, JS::Heap<JSObject *> *rp, const char *name)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    return AddObjectRoot(cx, rp, name);
+    return AddObjectRoot(cx, rp->unsafeGet(), name);
 }
 
 JS_PUBLIC_API(bool)
-JS_AddNamedScriptRoot(JSContext *cx, JSScript **rp, const char *name)
+JS::AddNamedScriptRoot(JSContext *cx, JS::Heap<JSScript *> *rp, const char *name)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    return AddScriptRoot(cx, rp, name);
+    return AddScriptRoot(cx, rp->unsafeGet(), name);
 }
 
 /* We allow unrooting from finalizers within the GC */
 
 JS_PUBLIC_API(void)
-JS_RemoveValueRoot(JSContext *cx, jsval *vp)
+JS::RemoveValueRoot(JSContext *cx, JS::Heap<JS::Value> *vp)
 {
     CHECK_REQUEST(cx);
     RemoveRoot(cx->runtime(), (void *)vp);
+    *vp = UndefinedValue();
 }
 
 JS_PUBLIC_API(void)
-JS_RemoveStringRoot(JSContext *cx, JSString **rp)
+JS::RemoveStringRoot(JSContext *cx, JS::Heap<JSString *> *rp)
 {
     CHECK_REQUEST(cx);
     RemoveRoot(cx->runtime(), (void *)rp);
+    *rp = nullptr;
 }
 
 JS_PUBLIC_API(void)
-JS_RemoveObjectRoot(JSContext *cx, JSObject **rp)
+JS::RemoveObjectRoot(JSContext *cx, JS::Heap<JSObject *> *rp)
 {
     CHECK_REQUEST(cx);
     RemoveRoot(cx->runtime(), (void *)rp);
+    *rp = nullptr;
 }
 
 JS_PUBLIC_API(void)
-JS_RemoveScriptRoot(JSContext *cx, JSScript **rp)
+JS::RemoveScriptRoot(JSContext *cx, JS::Heap<JSScript *> *rp)
 {
     CHECK_REQUEST(cx);
     RemoveRoot(cx->runtime(), (void *)rp);
+    *rp = nullptr;
 }
 
 JS_PUBLIC_API(void)
-JS_RemoveValueRootRT(JSRuntime *rt, jsval *vp)
+JS::RemoveValueRootRT(JSRuntime *rt, JS::Heap<JS::Value> *vp)
 {
     RemoveRoot(rt, (void *)vp);
+    *vp = UndefinedValue();
 }
 
 JS_PUBLIC_API(void)
-JS_RemoveStringRootRT(JSRuntime *rt, JSString **rp)
+JS::RemoveStringRootRT(JSRuntime *rt, JS::Heap<JSString *> *rp)
 {
     RemoveRoot(rt, (void *)rp);
+    *rp = nullptr;
 }
 
 JS_PUBLIC_API(void)
-JS_RemoveObjectRootRT(JSRuntime *rt, JSObject **rp)
+JS::RemoveObjectRootRT(JSRuntime *rt, JS::Heap<JSObject *> *rp)
 {
     RemoveRoot(rt, (void *)rp);
+    *rp = nullptr;
 }
 
 JS_PUBLIC_API(void)
-JS_RemoveScriptRootRT(JSRuntime *rt, JSScript **rp)
+JS::RemoveScriptRootRT(JSRuntime *rt, JS::Heap<JSScript *> *rp)
 {
     RemoveRoot(rt, (void *)rp);
+    *rp = nullptr;
 }
 
 JS_PUBLIC_API(bool)
 JS_AddExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
 {
     AssertHeapIsIdle(rt);
     return !!rt->gcBlackRootTracers.append(JSRuntime::ExtraTracer(traceOp, data));
 }
@@ -5919,17 +5927,17 @@ JS_RestoreExceptionState(JSContext *cx, 
 JS_PUBLIC_API(void)
 JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     if (state) {
         if (state->throwing && JSVAL_IS_GCTHING(state->exception)) {
             assertSameCompartment(cx, state->exception);
-            JS_RemoveValueRoot(cx, &state->exception);
+            RemoveRoot(cx->runtime(), &state->exception);
         }
         js_free(state);
     }
 }
 
 JS_PUBLIC_API(JSErrorReport *)
 JS_ErrorFromException(JSContext *cx, HandleObject obj)
 {
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1884,16 +1884,17 @@ JS_updateMallocCounter(JSContext *cx, si
 
 extern JS_PUBLIC_API(char *)
 JS_strdup(JSContext *cx, const char *s);
 
 /* Duplicate a string.  Does not report an error on failure. */
 extern JS_PUBLIC_API(char *)
 JS_strdup(JSRuntime *rt, const char *s);
 
+namespace JS {
 
 /*
  * A GC root is a pointer to a jsval, JSObject * or JSString * that itself
  * points into the GC heap. JS_AddValueRoot takes a pointer to a jsval and
  * JS_AddGCThingRoot takes a pointer to a JSObject * or JString *.
  *
  * Note that, since JS_Add*Root stores the address of a variable (of type
  * jsval, JSString *, or JSObject *), that variable must live until
@@ -1911,62 +1912,64 @@ JS_strdup(JSRuntime *rt, const char *s);
  *
  * Also, use JS_AddNamed*Root(cx, &structPtr->memberObj, "structPtr->memberObj")
  * in preference to JS_Add*Root(cx, &structPtr->memberObj), in order to identify
  * roots by their source callsites.  This way, you can find the callsite while
  * debugging if you should fail to do JS_Remove*Root(cx, &structPtr->memberObj)
  * before freeing structPtr's memory.
  */
 extern JS_PUBLIC_API(bool)
-JS_AddValueRoot(JSContext *cx, jsval *vp);
+AddValueRoot(JSContext *cx, JS::Heap<JS::Value> *vp);
 
 extern JS_PUBLIC_API(bool)
-JS_AddStringRoot(JSContext *cx, JSString **rp);
+AddStringRoot(JSContext *cx, JS::Heap<JSString *> *rp);
 
 extern JS_PUBLIC_API(bool)
-JS_AddObjectRoot(JSContext *cx, JSObject **rp);
+AddObjectRoot(JSContext *cx, JS::Heap<JSObject *> *rp);
 
 extern JS_PUBLIC_API(bool)
-JS_AddNamedValueRoot(JSContext *cx, jsval *vp, const char *name);
+AddNamedValueRoot(JSContext *cx, JS::Heap<JS::Value> *vp, const char *name);
 
 extern JS_PUBLIC_API(bool)
-JS_AddNamedValueRootRT(JSRuntime *rt, jsval *vp, const char *name);
+AddNamedValueRootRT(JSRuntime *rt, JS::Heap<JS::Value> *vp, const char *name);
 
 extern JS_PUBLIC_API(bool)
-JS_AddNamedStringRoot(JSContext *cx, JSString **rp, const char *name);
+AddNamedStringRoot(JSContext *cx, JS::Heap<JSString *> *rp, const char *name);
 
 extern JS_PUBLIC_API(bool)
-JS_AddNamedObjectRoot(JSContext *cx, JSObject **rp, const char *name);
+AddNamedObjectRoot(JSContext *cx, JS::Heap<JSObject *> *rp, const char *name);
 
 extern JS_PUBLIC_API(bool)
-JS_AddNamedScriptRoot(JSContext *cx, JSScript **rp, const char *name);
+AddNamedScriptRoot(JSContext *cx, JS::Heap<JSScript *> *rp, const char *name);
 
 extern JS_PUBLIC_API(void)
-JS_RemoveValueRoot(JSContext *cx, jsval *vp);
+RemoveValueRoot(JSContext *cx, JS::Heap<JS::Value> *vp);
 
 extern JS_PUBLIC_API(void)
-JS_RemoveStringRoot(JSContext *cx, JSString **rp);
+RemoveStringRoot(JSContext *cx, JS::Heap<JSString *> *rp);
 
 extern JS_PUBLIC_API(void)
-JS_RemoveObjectRoot(JSContext *cx, JSObject **rp);
+RemoveObjectRoot(JSContext *cx, JS::Heap<JSObject *> *rp);
 
 extern JS_PUBLIC_API(void)
-JS_RemoveScriptRoot(JSContext *cx, JSScript **rp);
+RemoveScriptRoot(JSContext *cx, JS::Heap<JSScript *> *rp);
 
 extern JS_PUBLIC_API(void)
-JS_RemoveValueRootRT(JSRuntime *rt, jsval *vp);
+RemoveValueRootRT(JSRuntime *rt, JS::Heap<JS::Value> *vp);
 
 extern JS_PUBLIC_API(void)
-JS_RemoveStringRootRT(JSRuntime *rt, JSString **rp);
+RemoveStringRootRT(JSRuntime *rt, JS::Heap<JSString *> *rp);
 
 extern JS_PUBLIC_API(void)
-JS_RemoveObjectRootRT(JSRuntime *rt, JSObject **rp);
+RemoveObjectRootRT(JSRuntime *rt, JS::Heap<JSObject *> *rp);
 
 extern JS_PUBLIC_API(void)
-JS_RemoveScriptRootRT(JSRuntime *rt, JSScript **rp);
+RemoveScriptRootRT(JSRuntime *rt, JS::Heap<JSScript *> *rp);
+
+} /* namespace JS */
 
 /*
  * Register externally maintained GC roots.
  *
  * traceOp: the trace operation. For each root the implementation should call
  *          JS_CallTracer whenever the root contains a traceable thing.
  * data:    the data argument to pass to each invocation of traceOp.
  */
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -147,21 +147,25 @@ JS_FRIEND_API(void)
 js_ReportOverRecursed(JSContext *maybecx);
 
 JS_FRIEND_API(bool)
 js_ObjectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue);
 
 JS_FRIEND_API(const char *)
 js_ObjectClassName(JSContext *cx, JS::HandleObject obj);
 
+namespace js {
+
 JS_FRIEND_API(bool)
-js_AddObjectRoot(JSRuntime *rt, JSObject **objp);
+AddRawValueRoot(JSContext *cx, JS::Value *vp, const char *name);
 
 JS_FRIEND_API(void)
-js_RemoveObjectRoot(JSRuntime *rt, JSObject **objp);
+RemoveRawValueRoot(JSContext *cx, JS::Value *vp);
+
+} /* namespace js */
 
 #ifdef JS_DEBUG
 
 /*
  * Routines to print out values during debugging.  These are FRIEND_API to help
  * the debugger find them and to support temporarily hacking js_Dump* calls
  * into other code.
  */
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1247,25 +1247,25 @@ js::AddObjectRoot(JSRuntime *rt, JSObjec
 
 extern bool
 js::AddScriptRoot(JSContext *cx, JSScript **rp, const char *name)
 {
     return AddRoot(cx, rp, name, JS_GC_ROOT_SCRIPT_PTR);
 }
 
 extern JS_FRIEND_API(bool)
-js_AddObjectRoot(JSRuntime *rt, JSObject **objp)
-{
-    return AddRoot(rt, objp, nullptr, JS_GC_ROOT_OBJECT_PTR);
+js::AddRawValueRoot(JSContext *cx, Value *vp, const char *name)
+{
+    return AddRoot(cx, vp, name, JS_GC_ROOT_VALUE_PTR);
 }
 
 extern JS_FRIEND_API(void)
-js_RemoveObjectRoot(JSRuntime *rt, JSObject **objp)
-{
-    RemoveRoot(rt, objp);
+js::RemoveRawValueRoot(JSContext *cx, Value *vp)
+{
+    RemoveRoot(cx->runtime(), vp);
 }
 
 void
 js::RemoveRoot(JSRuntime *rt, void *rp)
 {
     rt->gcRootsHash.remove(rp);
     rt->gcPoke = true;
 }
--- a/js/xpconnect/public/nsAutoJSValHolder.h
+++ b/js/xpconnect/public/nsAutoJSValHolder.h
@@ -57,38 +57,34 @@ public:
     return Hold(JS_GetRuntime(aCx));
   }
 
   /**
    * Hold by rooting on the runtime.
    * Note that mVal may be JSVAL_NULL, which is not a problem.
    */
   bool Hold(JSRuntime* aRt) {
-    // Do we really care about different runtimes?
-    if (mRt && aRt != mRt) {
-      JS_RemoveValueRootRT(mRt, &mVal);
-      mRt = nullptr;
-    }
+    MOZ_ASSERT_IF(mRt, mRt == aRt);
 
-    if (!mRt && JS_AddNamedValueRootRT(aRt, &mVal, "nsAutoJSValHolder")) {
+    if (!mRt && JS::AddNamedValueRootRT(aRt, &mVal, "nsAutoJSValHolder")) {
       mRt = aRt;
     }
 
     return !!mRt;
   }
 
   /**
    * Manually release, nullifying mVal, and mRt, but returning
    * the original JS::Value.
    */
   JS::Value Release() {
     JS::Value oldval = mVal;
 
     if (mRt) {
-      JS_RemoveValueRootRT(mRt, &mVal); // infallible
+      JS::RemoveValueRootRT(mRt, &mVal); // infallible
       mRt = nullptr;
     }
 
     mVal = JSVAL_NULL;
 
     return oldval;
   }
 
@@ -103,37 +99,34 @@ public:
    * Explicit JSObject* conversion.
    */
   JSObject* ToJSObject() const {
     return mVal.isObject()
          ? &mVal.toObject()
          : nullptr;
   }
 
-  JS::Value* ToJSValPtr() {
-    return &mVal;
-  }
-
   /**
    * Pretend to be a JS::Value.
    */
   operator JS::Value() const { return mVal; }
+  JS::Value get() const { return mVal; }
 
   nsAutoJSValHolder &operator=(JSObject* aOther) {
     return *this = OBJECT_TO_JSVAL(aOther);
   }
 
   nsAutoJSValHolder &operator=(JS::Value aOther) {
 #ifdef DEBUG
     if (JSVAL_IS_GCTHING(aOther) && !JSVAL_IS_NULL(aOther)) {
       MOZ_ASSERT(IsHeld(), "Not rooted!");
     }
 #endif
     mVal = aOther;
     return *this;
   }
 
 private:
-  JS::Value mVal;
+  JS::Heap<JS::Value> mVal;
   JSRuntime* mRt;
 };
 
 #endif /* __NSAUTOJSVALHOLDER_H__ */
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -2114,17 +2114,17 @@ CallMethodHelper::ConvertIndependentPara
     if (paramInfo.IsIndirect())
         dp->SetIndirect();
 
     // The JSVal proper is always stored within the 'val' union and passed
     // indirectly, regardless of in/out-ness.
     if (type_tag == nsXPTType::T_JSVAL) {
         // Root the value.
         dp->val.j = JSVAL_VOID;
-        if (!JS_AddValueRoot(mCallContext, &dp->val.j))
+        if (!js::AddRawValueRoot(mCallContext, &dp->val.j, "XPCWrappedNative::CallMethod param"))
             return false;
     }
 
     // Flag cleanup for anything that isn't self-contained.
     if (!type.IsArithmetic())
         dp->SetValNeedsCleanup();
 
     // Even if there's nothing to convert, we still need to examine the
@@ -2308,17 +2308,17 @@ CallMethodHelper::CleanupParam(nsXPTCMin
 
     // Pointers may sometimes be null even if cleanup was requested. Combine
     // the null checking for all the different types into one check here.
     if (type.TagPart() != nsXPTType::T_JSVAL && param.val.p == nullptr)
         return;
 
     switch (type.TagPart()) {
         case nsXPTType::T_JSVAL:
-            JS_RemoveValueRoot(mCallContext, (jsval*)&param.val);
+            js::RemoveRawValueRoot(mCallContext, (jsval*)&param.val);
             break;
         case nsXPTType::T_INTERFACE:
         case nsXPTType::T_INTERFACE_IS:
             ((nsISupports*)param.val.p)->Release();
             break;
         case nsXPTType::T_ASTRING:
         case nsXPTType::T_DOMSTRING:
             nsXPConnect::GetRuntimeInstance()->DeleteShortLivedString((nsString*)param.val.p);