Bug 1257335. Replace some AutoSafeJSContext uses with AutoJSAPI or AutoJSContext uses. r=bholley
authorBoris Zbarsky <bzbarsky@mit.edu>
Fri, 18 Mar 2016 10:48:38 -0400
changeset 289359 476c67fdc36c72c4d7efac7bb4506625093f29b1
parent 289358 d2b13daf01edb6ab59d5f7ed657da40d7a71aace
child 289360 5096e12520cd2ac31f554d7b2d7df40671f992ec
push id30102
push userryanvm@gmail.com
push dateSat, 19 Mar 2016 15:23:17 +0000
treeherdermozilla-central@720fb3d55e28 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs1257335
milestone48.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 1257335. Replace some AutoSafeJSContext uses with AutoJSAPI or AutoJSContext uses. r=bholley In general, using an AutoJSAPI inited with an object is NOT the same as using AutoSafeJSContext (or AutoJSAPI inited without an object) and then entering the compartment of the object: the former will report exceptions to the global of the object as it comes off the stack, while the latter will not. This only really matters if we have an object from a window or worker global and hence might fire error events, or report internal stuff to the web console. The changes to initing with an object made in this bug are OK for the following reasons: 1) dom/base/Console.cpp: Always clears its exception before coming off the stack. 2) dom/base/nsDOMClassInfo.cpp: Inits with a non-web global. 3) dom/base/nsFrameMessageManager.cpp: Inits with a non-web global. 4) dom/media/MediaPermissionGonk.cpp: We probably want the caller to notice if anything here throws. 5) dom/xbl/nsXBLPrototypeBinding.cpp: Inits with a non-web global. 6) dom/xul/nsXULElement.cpp: Inits with a non-web global. 7) extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp: Inits with a non-web global. 8) ipc/testshell/XPCShellEnvironment.cpp: Inits with a non-web global.
dom/base/Console.cpp
dom/base/ScriptSettings.h
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
dom/base/nsFrameMessageManager.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsObjectLoadingContent.cpp
dom/base/nsXMLHttpRequest.cpp
dom/bindings/CallbackObject.cpp
dom/bluetooth/common/BluetoothReplyRunnable.cpp
dom/datastore/DataStoreDB.cpp
dom/media/MediaPermissionGonk.cpp
dom/system/gonk/AudioManager.cpp
dom/system/gonk/AutoMounterSetting.cpp
dom/system/gonk/SystemWorkerManager.cpp
dom/system/gonk/SystemWorkerManager.h
dom/time/DateCacheCleaner.cpp
dom/xbl/nsXBLPrototypeBinding.cpp
dom/xul/nsXULElement.cpp
extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp
ipc/testshell/XPCShellEnvironment.cpp
--- a/dom/base/Console.cpp
+++ b/dom/base/Console.cpp
@@ -1328,22 +1328,24 @@ Console::ProcessCallData(ConsoleCallData
   AssertIsOnMainThread();
   MOZ_ASSERT(aData);
 
   ConsoleStackEntry frame;
   if (aData->mTopStackFrame) {
     frame = *aData->mTopStackFrame;
   }
 
-  AutoSafeJSContext cx;
+  AutoJSAPI jsapi;
+  if (!jsapi.Init(aGlobal)) {
+    return;
+  }
+  JSContext* cx = jsapi.cx();
   ClearException ce(cx);
   RootedDictionary<ConsoleEvent> event(cx);
 
-  JSAutoCompartment ac(cx, aGlobal);
-
   event.mID.Construct();
   event.mInnerID.Construct();
 
   MOZ_ASSERT(aData->mIDType != ConsoleCallData::eUnknown);
   if (aData->mIDType == ConsoleCallData::eString) {
     event.mID.Value().SetAsString() = aData->mOuterIDString;
     event.mInnerID.Value().SetAsString() = aData->mInnerIDString;
   } else {
--- a/dom/base/ScriptSettings.h
+++ b/dom/base/ScriptSettings.h
@@ -216,32 +216,44 @@ public:
   // accessing the JSContext through cx().
   AutoJSAPI();
 
   ~AutoJSAPI();
 
   // This uses the SafeJSContext (or worker equivalent), and enters a null
   // compartment, so that the consumer is forced to select a compartment to
   // enter before manipulating objects.
+  //
+  // This variant will ensure that any errors reported by this AutoJSAPI as it
+  // comes off the stack will not fire error events or be associated with any
+  // particular web-visible global.
   void Init();
 
   // This uses the SafeJSContext (or worker equivalent), and enters the
   // compartment of aGlobalObject.
   // If aGlobalObject or its associated JS global are null then it returns
   // false and use of cx() will cause an assertion.
+  //
+  // If aGlobalObject represents a web-visible global, errors reported by this
+  // AutoJSAPI as it comes off the stack will fire the relevant error events and
+  // show up in the corresponding web console.
   bool Init(nsIGlobalObject* aGlobalObject);
 
   // This is a helper that grabs the native global associated with aObject and
   // invokes the above Init() with that.
   bool Init(JSObject* aObject);
 
   // Unsurprisingly, this uses aCx and enters the compartment of aGlobalObject.
   // If aGlobalObject or its associated JS global are null then it returns
   // false and use of cx() will cause an assertion.
   // If aCx is null it will cause an assertion.
+  //
+  // If aGlobalObject represents a web-visible global, errors reported by this
+  // AutoJSAPI as it comes off the stack will fire the relevant error events and
+  // show up in the corresponding web console.
   bool Init(nsIGlobalObject* aGlobalObject, JSContext* aCx);
 
   // Convenience functions to take an nsPIDOMWindow* or nsGlobalWindow*,
   // when it is more easily available than an nsIGlobalObject.
   bool Init(nsPIDOMWindowInner* aWindow);
   bool Init(nsPIDOMWindowInner* aWindow, JSContext* aCx);
 
   bool Init(nsGlobalWindow* aWindow);
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -320,19 +320,23 @@ SetParentToWindow(nsGlobalWindow *win, J
 
 nsISupports *
 nsDOMClassInfo::GetNative(nsIXPConnectWrappedNative *wrapper, JSObject *obj)
 {
   return wrapper ? wrapper->Native() : static_cast<nsISupports*>(js::GetObjectPrivate(obj));
 }
 
 nsresult
-nsDOMClassInfo::DefineStaticJSVals(JSContext *cx)
+nsDOMClassInfo::DefineStaticJSVals()
 {
-#define SET_JSID_TO_STRING(_id, _cx, _str)                                    \
+  AutoJSAPI jsapi;
+  jsapi.Init(xpc::UnprivilegedJunkScope());
+  JSContext* cx = jsapi.cx();
+
+#define SET_JSID_TO_STRING(_id, _cx, _str)                              \
   if (JSString *str = ::JS_AtomizeAndPinString(_cx, _str))                             \
       _id = INTERNED_STRING_TO_JSID(_cx, str);                                \
   else                                                                        \
       return NS_ERROR_OUT_OF_MEMORY;
 
   SET_JSID_TO_STRING(sConstructor_id,     cx, "constructor");
   SET_JSID_TO_STRING(sWrappedJSObject_id, cx, "wrappedJSObject");
 
@@ -495,18 +499,16 @@ nsDOMClassInfo::Init()
   nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
   NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
 
   NS_ADDREF(sXPConnect = nsContentUtils::XPConnect());
 
   nsCOMPtr<nsIXPCFunctionThisTranslator> elt = new nsEventListenerThisTranslator();
   sXPConnect->SetFunctionThisTranslator(NS_GET_IID(nsIDOMEventListener), elt);
 
-  AutoSafeJSContext cx;
-
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(DOMPrototype, nsIDOMDOMConstructor)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMConstructor)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(DOMConstructor, nsIDOMDOMConstructor)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMConstructor)
   DOM_CLASSINFO_MAP_END
 
@@ -660,17 +662,17 @@ nsDOMClassInfo::Init()
     if (!sClassInfoData[i].mInterfaces) {
       MOZ_CRASH("Class info data without an interface list! Fix this, "
                 "mozilla will not work without this fixed!");
      }
    }
 #endif
 
   // Initialize static JSString's
-  DefineStaticJSVals(cx);
+  DefineStaticJSVals();
 
   int32_t i;
 
   for (i = 0; i < eDOMClassInfoIDCount; ++i) {
     if (i == eDOMClassInfo_DOMPrototype_id) {
       continue;
     }
 
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -105,17 +105,17 @@ protected:
   {
   }
 
   static nsresult RegisterClassProtos(int32_t aDOMClassInfoID);
 
   static nsIXPConnect *sXPConnect;
 
   // nsIXPCScriptable code
-  static nsresult DefineStaticJSVals(JSContext *cx);
+  static nsresult DefineStaticJSVals();
 
   static bool sIsInitialized;
 
 public:
   static jsid sConstructor_id;
   static jsid sWrappedJSObject_id;
 };
 
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -1641,17 +1641,16 @@ nsMessageManagerScriptExecutor::DidCreat
   }
 }
 
 // static
 void
 nsMessageManagerScriptExecutor::Shutdown()
 {
   if (sCachedScripts) {
-    AutoSafeJSContext cx;
     NS_ASSERTION(sCachedScripts != nullptr, "Need cached scripts");
     for (auto iter = sCachedScripts->Iter(); !iter.Done(); iter.Next()) {
       delete iter.Data();
       iter.Remove();
     }
 
     delete sCachedScripts;
     sCachedScripts = nullptr;
@@ -1756,22 +1755,23 @@ nsMessageManagerScriptExecutor::TryCache
                                    EmptyString(), nullptr,
                                    dataStringBuf, dataStringLength);
   }
 
   JS::SourceBufferHolder srcBuf(dataStringBuf, dataStringLength,
                                 JS::SourceBufferHolder::GiveOwnership);
 
   if (dataStringBuf && dataStringLength > 0) {
-    AutoSafeJSContext cx;
     // Compile the script in the compilation scope instead of the current global
     // to avoid keeping the current compartment alive.
-    JS::Rooted<JSObject*> global(cx, xpc::CompilationScope());
-
-    JSAutoCompartment ac(cx, global);
+    AutoJSAPI jsapi;
+    if (!jsapi.Init(xpc::CompilationScope())) {
+      return;
+    }
+    JSContext* cx = jsapi.cx();
     JS::CompileOptions options(cx, JSVERSION_LATEST);
     options.setFileAndLine(url.get(), 1);
     options.setNoScriptRval(true);
     JS::Rooted<JSScript*> script(cx);
 
     if (aRunInGlobalScope) {
       if (!JS::Compile(cx, options, srcBuf, &script)) {
         return;
@@ -1796,18 +1796,17 @@ nsMessageManagerScriptExecutor::TryCache
   }
 }
 
 void
 nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript(
   const nsAString& aURL,
   bool aRunInGlobalScope)
 {
-  AutoSafeJSContext cx;
-  JS::Rooted<JSScript*> script(cx);
+  JS::Rooted<JSScript*> script(nsContentUtils::RootingCx());
   TryCacheLoadAndCompileScript(aURL, aRunInGlobalScope, true, &script);
 }
 
 void
 nsMessageManagerScriptExecutor::Trace(const TraceCallbacks& aCallbacks, void* aClosure)
 {
   for (size_t i = 0, length = mAnonymousGlobalScopes.Length(); i < length; ++i) {
     aCallbacks.Trace(&mAnonymousGlobalScopes[i], "mAnonymousGlobalScopes[i]", aClosure);
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -4007,17 +4007,19 @@ MozSelfSupport*
 nsGlobalWindow::GetMozSelfSupport(ErrorResult& aError)
 {
   MOZ_ASSERT(IsInnerWindow());
 
   if (mMozSelfSupport) {
     return mMozSelfSupport;
   }
 
-  AutoSafeJSContext cx;
+  // We're called from JS and want to use out existing JSContext (and,
+  // importantly, its compartment!) here.
+  AutoJSContext cx;
   GlobalObject global(cx, FastGetGlobalJSObject());
   mMozSelfSupport = MozSelfSupport::Constructor(global, cx, aError);
   return mMozSelfSupport;
 }
 
 nsresult
 nsGlobalWindow::GetScriptableContent(JSContext* aCx, JS::MutableHandle<JS::Value> aVal)
 {
@@ -5695,18 +5697,23 @@ nsGlobalWindow::DispatchResizeEvent(cons
 
   ErrorResult res;
   RefPtr<Event> domEvent =
     mDoc->CreateEvent(NS_LITERAL_STRING("CustomEvent"), res);
   if (res.Failed()) {
     return false;
   }
 
-  AutoSafeJSContext cx;
+  // We don't init the AutoJSAPI with ourselves because we don't want it
+  // reporting errors to our onerror handlers.
+  AutoJSAPI jsapi;
+  jsapi.Init();
+  JSContext* cx = jsapi.cx();
   JSAutoCompartment ac(cx, GetWrapperPreserveColor());
+
   DOMWindowResizeEventDetail detail;
   detail.mWidth = aSize.width;
   detail.mHeight = aSize.height;
   JS::Rooted<JS::Value> detailValue(cx);
   if (!ToJSValue(cx, detail, &detailValue)) {
     return false;
   }
 
@@ -8667,18 +8674,17 @@ nsGlobalWindow::NotifyDOMWindowThawed(ns
                         DOM_WINDOW_THAWED_TOPIC, nullptr);
     }
   }
 }
 
 JSObject*
 nsGlobalWindow::GetCachedXBLPrototypeHandler(nsXBLPrototypeHandler* aKey)
 {
-  AutoSafeJSContext cx;
-  JS::Rooted<JSObject*> handler(cx);
+  JS::Rooted<JSObject*> handler(nsContentUtils::RootingCx());
   if (mCachedXBLPrototypeHandlers) {
     mCachedXBLPrototypeHandlers->Get(aKey, handler.address());
   }
   return handler;
 }
 
 void
 nsGlobalWindow::CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey,
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -3715,21 +3715,25 @@ nsObjectLoadingContent::GetPluginJSObjec
 }
 
 void
 nsObjectLoadingContent::TeardownProtoChain()
 {
   nsCOMPtr<nsIContent> thisContent =
     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
 
-  // Use the safe JSContext here as we're not always able to find the
-  // JSContext associated with the NPP any more.
-  AutoSafeJSContext cx;
+  NS_ENSURE_TRUE_VOID(thisContent->GetWrapper());
+
+  // We don't init the AutoJSAPI with our wrapper because we don't want it
+  // reporting errors to our window's onerror listeners.
+  AutoJSAPI jsapi;
+  jsapi.Init();
+  JSContext* cx = jsapi.cx();
   JS::Rooted<JSObject*> obj(cx, thisContent->GetWrapper());
-  NS_ENSURE_TRUE(obj, /* void */);
+  MOZ_ASSERT(obj);
 
   JS::Rooted<JSObject*> proto(cx);
   JSAutoCompartment ac(cx, obj);
 
   // Loop over the DOM element's JS object prototype chain and remove
   // all JS objects of the class sNPObjectJSWrapperClass
   DebugOnly<bool> removed = false;
   while (obj) {
--- a/dom/base/nsXMLHttpRequest.cpp
+++ b/dom/base/nsXMLHttpRequest.cpp
@@ -2407,23 +2407,23 @@ GetRequestBody(nsIVariant* aBody, nsIInp
 
     // nsIXHRSendable?
     nsCOMPtr<nsIXHRSendable> sendable = do_QueryInterface(supports);
     if (sendable) {
       return GetRequestBody(sendable, aResult, aContentLength, aContentType, aCharset);
     }
 
     // ArrayBuffer?
-    AutoSafeJSContext cx;
-    JS::Rooted<JS::Value> realVal(cx);
+    JSContext* rootingCx = nsContentUtils::RootingCx();
+    JS::Rooted<JS::Value> realVal(rootingCx);
 
     nsresult rv = aBody->GetAsJSVal(&realVal);
     if (NS_SUCCEEDED(rv) && !realVal.isPrimitive()) {
-      JS::Rooted<JSObject*> obj(cx, realVal.toObjectOrNull());
-      ArrayBuffer buf;
+      JS::Rooted<JSObject*> obj(rootingCx, realVal.toObjectOrNull());
+      RootedTypedArray<ArrayBuffer> buf(rootingCx);
       if (buf.Init(obj)) {
           buf.ComputeLengthAndData();
           return GetRequestBody(buf.Data(), buf.Length(), aResult,
                                 aContentLength, aContentType, aCharset);
       }
     }
   }
   else if (dataType == nsIDataType::VTYPE_VOID ||
--- a/dom/bindings/CallbackObject.cpp
+++ b/dom/bindings/CallbackObject.cpp
@@ -320,17 +320,21 @@ already_AddRefed<nsISupports>
 CallbackObjectHolderBase::ToXPCOMCallback(CallbackObject* aCallback,
                                           const nsIID& aIID) const
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!aCallback) {
     return nullptr;
   }
 
-  AutoSafeJSContext cx;
+  // We don't init the AutoJSAPI with our callback because we don't want it
+  // reporting errors to its global's onerror handlers.
+  AutoJSAPI jsapi;
+  jsapi.Init();
+  JSContext* cx = jsapi.cx();
 
   JS::Rooted<JSObject*> callback(cx, aCallback->Callback());
 
   JSAutoCompartment ac(cx, callback);
   RefPtr<nsXPCWrappedJS> wrappedJS;
   nsresult rv =
     nsXPCWrappedJS::GetNewOrUsed(callback, aIID, getter_AddRefs(wrappedJS));
   if (NS_FAILED(rv) || !wrappedJS) {
--- a/dom/bluetooth/common/BluetoothReplyRunnable.cpp
+++ b/dom/bluetooth/common/BluetoothReplyRunnable.cpp
@@ -3,16 +3,17 @@
 /* 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 "base/basictypes.h"
 #include "BluetoothReplyRunnable.h"
 #include "BluetoothUtils.h"
 #include "DOMRequest.h"
+#include "nsContentUtils.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/dom/Promise.h"
 #include "nsServiceManagerUtils.h"
 
 using namespace mozilla::dom;
 
 USING_BLUETOOTH_NAMESPACE
@@ -87,18 +88,17 @@ BluetoothReplyRunnable::FireErrorString(
 }
 
 NS_IMETHODIMP
 BluetoothReplyRunnable::Run()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mReply);
 
-  AutoSafeJSContext cx;
-  JS::Rooted<JS::Value> v(cx, JS::UndefinedValue());
+  JS::Rooted<JS::Value> v(nsContentUtils::RootingCx(), JS::UndefinedValue());
 
   nsresult rv;
   if (mReply->type() != BluetoothReply::TBluetoothReplySuccess) {
     ParseErrorStatus();
     rv = FireErrorString();
   } else if (!ParseSuccessfulReply(&v)) {
     rv = FireErrorString();
   } else {
--- a/dom/datastore/DataStoreDB.cpp
+++ b/dom/datastore/DataStoreDB.cpp
@@ -107,17 +107,19 @@ DataStoreDB::CreateFactoryIfNeeded()
     nsCOMPtr<nsIPrincipal> principal = nsNullPrincipal::Create();
     if (!principal) {
       return NS_ERROR_FAILURE;
     }
 
     nsIXPConnect* xpc = nsContentUtils::XPConnect();
     MOZ_ASSERT(xpc);
 
-    AutoSafeJSContext cx;
+    AutoJSAPI jsapi;
+    jsapi.Init();
+    JSContext* cx = jsapi.cx();
     JS::Rooted<JSObject*> global(cx);
     rv = xpc->CreateSandbox(cx, principal, global.address());
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     // The CreateSandbox call returns a proxy to the actual sandbox object. We
     // don't need a proxy here.
@@ -217,20 +219,18 @@ DataStoreDB::UpgradeSchema(nsIDOMEvent* 
   nsCOMPtr<IDBVersionChangeEvent> event = do_QueryInterface(aEvent);
   MOZ_ASSERT(event);
 
   Nullable<uint64_t> version = event->GetNewVersion();
   MOZ_ASSERT(!version.IsNull());
   MOZ_ASSERT(version.Value() == DATASTOREDB_VERSION);
 #endif
 
-  AutoSafeJSContext cx;
-
   ErrorResult error;
-  JS::Rooted<JS::Value> result(cx);
+  JS::Rooted<JS::Value> result(nsContentUtils::RootingCx());
   mRequest->GetResult(&result, error);
   if (NS_WARN_IF(error.Failed())) {
     return error.StealNSResult();
   }
 
   MOZ_ASSERT(result.isObject());
 
   IDBDatabase* database = nullptr;
@@ -279,20 +279,18 @@ DataStoreDB::UpgradeSchema(nsIDOMEvent* 
   return NS_OK;
 }
 
 nsresult
 DataStoreDB::DatabaseOpened()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  AutoSafeJSContext cx;
-
   ErrorResult error;
-  JS::Rooted<JS::Value> result(cx);
+  JS::Rooted<JS::Value> result(nsContentUtils::RootingCx());
   mRequest->GetResult(&result, error);
   if (NS_WARN_IF(error.Failed())) {
     return error.StealNSResult();
   }
 
   MOZ_ASSERT(result.isObject());
 
   nsresult rv = UNWRAP_OBJECT(IDBDatabase, &result.toObject(), mDatabase);
--- a/dom/media/MediaPermissionGonk.cpp
+++ b/dom/media/MediaPermissionGonk.cpp
@@ -238,19 +238,22 @@ NS_IMETHODIMP
 MediaPermissionRequest::Allow(JS::HandleValue aChoices)
 {
   // check if JS object
   if (!aChoices.isObject()) {
     MOZ_ASSERT(false, "Not a correct format of PermissionChoice");
     return NS_ERROR_INVALID_ARG;
   }
   // iterate through audio-capture and video-capture
-  AutoSafeJSContext cx;
+  AutoJSAPI jsapi;
+  if (!jsapi.init(&aChoices.toObject())) {
+    return NS_ERROR_UNEXPECTED;
+  }
+  JSContext* cx = jsapi.cx();
   JS::Rooted<JSObject*> obj(cx, &aChoices.toObject());
-  JSAutoCompartment ac(cx, obj);
   JS::Rooted<JS::Value> v(cx);
 
   // get selected audio device name
   nsString audioDevice;
   if (mAudio) {
     if (!JS_GetProperty(cx, obj, AUDIO_PERMISSION_NAME, &v) || !v.isString()) {
       return NS_ERROR_FAILURE;
     }
--- a/dom/system/gonk/AudioManager.cpp
+++ b/dom/system/gonk/AudioManager.cpp
@@ -1129,18 +1129,17 @@ AudioManager::MaybeUpdateVolumeSettingTo
   }
 
   nsCOMPtr<nsISettingsServiceLock> lock = GetSettingServiceLock();
   if (NS_WARN_IF(!lock)) {
     return;
   }
 
   // Send events to update the Gaia volumes
-  mozilla::AutoSafeJSContext cx;
-  JS::Rooted<JS::Value> value(cx);
+  JS::Rooted<JS::Value> value(nsContentUtils::RootingCx());
   uint32_t volume = 0;
   for (uint32_t idx = 0; idx < MOZ_ARRAY_LENGTH(gVolumeData); ++idx) {
     int32_t streamType = gVolumeData[idx].mStreamType;
     VolumeStreamState* streamState = mStreamStates[streamType].get();
     if(!aForce && !streamState->IsDevicesChanged()) {
       continue;
     }
     // Get volume index of active device.
--- a/dom/system/gonk/AutoMounterSetting.cpp
+++ b/dom/system/gonk/AutoMounterSetting.cpp
@@ -204,18 +204,18 @@ public:
     MOZ_ASSERT(NS_IsMainThread());
     nsCOMPtr<nsISettingsService> settingsService =
       do_GetService("@mozilla.org/settingsService;1");
     NS_ENSURE_TRUE(settingsService, NS_ERROR_FAILURE);
     nsCOMPtr<nsISettingsServiceLock> lock;
     settingsService->CreateLock(nullptr, getter_AddRefs(lock));
     // lock may be null if this gets called during shutdown.
     if (lock) {
-      mozilla::AutoSafeJSContext cx;
-      JS::Rooted<JS::Value> value(cx, JS::Int32Value(mStatus));
+      JS::Rooted<JS::Value> value(nsContentUtils::RootingCx(),
+				  JS::Int32Value(mStatus));
       lock->Set(UMS_STATUS, value, nullptr, nullptr);
     }
     return NS_OK;
   }
 
 private:
   int32_t mStatus;
 };
--- a/dom/system/gonk/SystemWorkerManager.cpp
+++ b/dom/system/gonk/SystemWorkerManager.cpp
@@ -73,25 +73,23 @@ SystemWorkerManager::Init()
 {
   if (!XRE_IsParentProcess()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   NS_ASSERTION(NS_IsMainThread(), "We can only initialize on the main thread");
   NS_ASSERTION(!mShutdown, "Already shutdown!");
 
-  mozilla::AutoSafeJSContext cx;
-
-  nsresult rv = InitWifi(cx);
+  nsresult rv = InitWifi();
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to initialize WiFi Networking!");
     return rv;
   }
 
-  InitKeyStore(cx);
+  InitKeyStore();
 
   InitAutoMounter();
   InitializeTimeZoneSettingObserver();
   nsCOMPtr<nsIAudioManager> audioManager =
     do_GetService(NS_AUDIOMANAGER_CONTRACTID);
 
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (!obs) {
@@ -200,27 +198,27 @@ SystemWorkerManager::RegisterRilWorker(u
     return NS_ERROR_FAILURE;
   }
 
   return RilWorker::Register(aClientId, wctd);
 #endif // MOZ_B2G_RIL
 }
 
 nsresult
-SystemWorkerManager::InitWifi(JSContext *cx)
+SystemWorkerManager::InitWifi()
 {
   nsCOMPtr<nsIWorkerHolder> worker = do_CreateInstance(kWifiWorkerCID);
   NS_ENSURE_TRUE(worker, NS_ERROR_FAILURE);
 
   mWifiWorker = worker;
   return NS_OK;
 }
 
 nsresult
-SystemWorkerManager::InitKeyStore(JSContext *cx)
+SystemWorkerManager::InitKeyStore()
 {
   mKeyStore = new KeyStore();
   return NS_OK;
 }
 
 NS_IMPL_ISUPPORTS(SystemWorkerManager,
                   nsIObserver,
                   nsIInterfaceRequestor,
--- a/dom/system/gonk/SystemWorkerManager.h
+++ b/dom/system/gonk/SystemWorkerManager.h
@@ -54,18 +54,18 @@ public:
 
   static nsIInterfaceRequestor*
   GetInterfaceRequestor();
 
 private:
   SystemWorkerManager();
   ~SystemWorkerManager();
 
-  nsresult InitWifi(JSContext *cx);
-  nsresult InitKeyStore(JSContext *cx);
+  nsresult InitWifi();
+  nsresult InitKeyStore();
 
   nsCOMPtr<nsIWorkerHolder> mWifiWorker;
 
   RefPtr<mozilla::ipc::KeyStore> mKeyStore;
 
   bool mShutdown;
 };
 
--- a/dom/time/DateCacheCleaner.cpp
+++ b/dom/time/DateCacheCleaner.cpp
@@ -27,17 +27,16 @@ public:
   }
 
   ~DateCacheCleaner()
   {
     UnregisterSystemTimezoneChangeObserver(this);
   }
   void Notify(const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo)
   {
-    mozilla::AutoSafeJSContext cx;
     JS::ResetTimeZone();
   }
 
 };
 
 StaticAutoPtr<DateCacheCleaner> sDateCacheCleaner;
 
 void
--- a/dom/xbl/nsXBLPrototypeBinding.cpp
+++ b/dom/xbl/nsXBLPrototypeBinding.cpp
@@ -876,19 +876,22 @@ nsXBLPrototypeBinding::Read(nsIObjectInp
 
   for (; interfaceCount > 0; interfaceCount--) {
     nsIID iid;
     rv = aStream->ReadID(&iid);
     NS_ENSURE_SUCCESS(rv, rv);
     mInterfaceTable.Put(iid, mBinding);
   }
 
-  AutoSafeJSContext cx;
-  JS::Rooted<JSObject*> compilationGlobal(cx, xpc::CompilationScope());
-  JSAutoCompartment ac(cx, compilationGlobal);
+  // We're not directly using this AutoJSAPI here, but callees use it via
+  // AutoJSContext.
+  AutoJSAPI jsapi;
+  if (!jsapi.Init(xpc::CompilationScope())) {
+    return NS_ERROR_UNEXPECTED;
+  }
 
   bool isFirstBinding = aFlags & XBLBinding_Serialize_IsFirstBinding;
   rv = Init(id, aDocInfo, nullptr, isFirstBinding);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // We need to set the prototype binding before reading the nsXBLProtoImpl,
   // as it may be retrieved within.
   rv = aDocInfo->SetPrototypeBinding(id, this);
@@ -1019,19 +1022,22 @@ nsXBLPrototypeBinding::ReadNewBinding(ns
 
 nsresult
 nsXBLPrototypeBinding::Write(nsIObjectOutputStream* aStream)
 {
   // This writes out the binding. Note that mCheckedBaseProto,
   // mKeyHandlersRegistered and mKeyHandlers are not serialized as they are
   // computed on demand.
 
-  AutoSafeJSContext cx;
-  JS::Rooted<JSObject*> compilationGlobal(cx, xpc::CompilationScope());
-  JSAutoCompartment ac(cx, compilationGlobal);
+  // We're not directly using this AutoJSAPI here, but callees use it via
+  // AutoJSContext.
+  AutoJSAPI jsapi;
+  if (!jsapi.Init(xpc::CompilationScope())) {
+    return NS_ERROR_UNEXPECTED;
+  }
 
   uint8_t flags = mInheritStyle ? XBLBinding_Serialize_InheritStyle : 0;
 
   // mAlternateBindingURI is only set on the first binding.
   if (mAlternateBindingURI) {
     flags |= XBLBinding_Serialize_IsFirstBinding;
   }
 
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -2521,20 +2521,21 @@ nsXULPrototypeScript::~nsXULPrototypeScr
 }
 
 nsresult
 nsXULPrototypeScript::Serialize(nsIObjectOutputStream* aStream,
                                 nsXULPrototypeDocument* aProtoDoc,
                                 const nsTArray<RefPtr<mozilla::dom::NodeInfo>> *aNodeInfos)
 {
     NS_ENSURE_TRUE(aProtoDoc, NS_ERROR_UNEXPECTED);
-    AutoSafeJSContext cx;
-    JS::Rooted<JSObject*> global(cx, xpc::CompilationScope());
-    NS_ENSURE_TRUE(global, NS_ERROR_UNEXPECTED);
-    JSAutoCompartment ac(cx, global);
+
+    AutoJSAPI jsapi;
+    if (!jsapi.Init(xpc::CompilationScope())) {
+        return NS_ERROR_UNEXPECTED;
+    }
 
     NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nullptr ||
                  !mScriptObject,
                  "script source still loading when serializing?!");
     if (!mScriptObject)
         return NS_ERROR_FAILURE;
 
     // Write basic prototype data
@@ -2544,16 +2545,17 @@ nsXULPrototypeScript::Serialize(nsIObjec
     rv = aStream->Write32(mLangVersion);
     if (NS_FAILED(rv)) return rv;
 
     // Calling fromMarkedLocation() is safe because we trace mScriptObject in
     // TraceScriptObject() and because its value is never changed after it has
     // been set.
     JS::Handle<JSScript*> script =
         JS::Handle<JSScript*>::fromMarkedLocation(mScriptObject.address());
+    JSContext* cx = jsapi.cx();
     MOZ_ASSERT(xpc::CompilationScope() == JS::CurrentGlobalOrNull(cx));
     return nsContentUtils::XPConnect()->WriteScript(aStream, cx,
                                                     xpc_UnmarkGrayScript(script));
 }
 
 nsresult
 nsXULPrototypeScript::SerializeOutOfLine(nsIObjectOutputStream* aStream,
                                          nsXULPrototypeDocument* aProtoDoc)
@@ -2613,20 +2615,21 @@ nsXULPrototypeScript::Deserialize(nsIObj
                  "prototype script not well-initialized when deserializing?!");
 
     // Read basic prototype data
     rv = aStream->Read32(&mLineNo);
     if (NS_FAILED(rv)) return rv;
     rv = aStream->Read32(&mLangVersion);
     if (NS_FAILED(rv)) return rv;
 
-    AutoSafeJSContext cx;
-    JS::Rooted<JSObject*> global(cx, xpc::CompilationScope());
-    NS_ENSURE_TRUE(global, NS_ERROR_UNEXPECTED);
-    JSAutoCompartment ac(cx, global);
+    AutoJSAPI jsapi;
+    if (!jsapi.Init(xpc::CompilationScope())) {
+        return NS_ERROR_UNEXPECTED;
+    }
+    JSContext* cx = jsapi.cx();
 
     JS::Rooted<JSScript*> newScriptObject(cx);
     rv = nsContentUtils::XPConnect()->ReadScript(aStream, cx,
                                                  newScriptObject.address());
     NS_ENSURE_SUCCESS(rv, rv);
     Set(newScriptObject);
     return NS_OK;
 }
@@ -2741,23 +2744,25 @@ public:
 StaticAutoPtr<nsTArray<nsCOMPtr<nsIOffThreadScriptReceiver>>> NotifyOffThreadScriptCompletedRunnable::sReceivers;
 bool NotifyOffThreadScriptCompletedRunnable::sSetupClearOnShutdown = false;
 
 NS_IMETHODIMP
 NotifyOffThreadScriptCompletedRunnable::Run()
 {
     MOZ_ASSERT(NS_IsMainThread());
 
-    // Note: this unroots mScript so that it is available to be collected by the
-    // JS GC. The receiver needs to root the script before performing a call that
-    // could GC.
-    JSScript *script;
+    JS::Rooted<JSScript*> script(nsContentUtils::RootingCx());
     {
-        AutoSafeJSContext cx;
-        JSAutoCompartment ac(cx, xpc::CompilationScope());
+        AutoJSAPI jsapi;
+        if (!jsapi.Init(xpc::CompilationScope())) {
+            // Now what?  I guess we just leak... this should probably never
+            // happen.
+            return NS_ERROR_UNEXPECTED;
+        }
+        JSContext* cx = jsapi.cx();
         script = JS::FinishOffThreadScript(cx, JS_GetRuntime(cx), mToken);
     }
 
     if (!sReceivers) {
         // We've already shut down.
         return NS_OK;
     }
 
@@ -2782,18 +2787,21 @@ OffThreadScriptReceiverCallback(void *aT
 
 nsresult
 nsXULPrototypeScript::Compile(JS::SourceBufferHolder& aSrcBuf,
                               nsIURI* aURI, uint32_t aLineNo,
                               nsIDocument* aDocument,
                               nsIOffThreadScriptReceiver *aOffThreadReceiver /* = nullptr */)
 {
     // We'll compile the script in the compilation scope.
-    AutoSafeJSContext cx;
-    JSAutoCompartment ac(cx, xpc::CompilationScope());
+    AutoJSAPI jsapi;
+    if (!jsapi.Init(xpc::CompilationScope())) {
+        return NS_ERROR_UNEXPECTED;
+    }
+    JSContext* cx = jsapi.cx();
 
     nsAutoCString urlspec;
     nsContentUtils::GetWrapperSafeScriptFilename(aDocument, aURI, urlspec);
 
     // Ok, compile it to create a prototype script object!
     NS_ENSURE_TRUE(JSVersion(mLangVersion) != JSVERSION_UNKNOWN, NS_OK);
     JS::CompileOptions options(cx);
     options.setIntroductionType("scriptElement")
--- a/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp
+++ b/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp
@@ -16,16 +16,17 @@
 #include "nsContentUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsJSPrincipals.h"
 #include "nsIScriptError.h"
 #include "jswrapper.h"
 
 extern mozilla::LazyLogModule MCD;
 using mozilla::AutoSafeJSContext;
+using mozilla::dom::AutoJSAPI;
 
 //*****************************************************************************
 
 static JS::PersistentRooted<JSObject *> autoconfigSb;
 
 nsresult CentralizedAdminPrefManagerInit()
 {
     nsresult rv;
@@ -97,18 +98,21 @@ nsresult EvaluateAdminConfigScript(const
     }
 
     // Grab XPConnect.
     nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
     if (NS_FAILED(rv)) {
         return rv;
     }
 
-    AutoSafeJSContext cx;
-    JSAutoCompartment ac(cx, autoconfigSb);
+    AutoJSAPI jsapi;
+    if (!jsapi.Init(autoconfigSb)) {
+        return NS_ERROR_UNEXPECTED;
+    }
+    JSContext* cx = jsapi.cx();
 
     nsAutoCString script(js_buffer, length);
     JS::RootedValue v(cx);
 
     nsString convertedScript = NS_ConvertUTF8toUTF16(script);
     if (convertedScript.Length() == 0) {
       nsContentUtils::ReportToConsoleNonLocalized(
         NS_LITERAL_STRING("Your AutoConfig file is ASCII. Please convert it to UTF-8."),
--- a/ipc/testshell/XPCShellEnvironment.cpp
+++ b/ipc/testshell/XPCShellEnvironment.cpp
@@ -41,16 +41,18 @@
 
 #include "TestShellChild.h"
 #include "TestShellParent.h"
 
 using mozilla::ipc::XPCShellEnvironment;
 using mozilla::ipc::TestShellChild;
 using mozilla::ipc::TestShellParent;
 using mozilla::AutoSafeJSContext;
+using mozilla::dom::AutoJSAPI;
+using mozilla::dom::AutoEntryScript;
 using namespace JS;
 
 namespace {
 
 static const char kDefaultRuntimeScriptFilename[] = "xpcshell.js";
 
 class XPCShellDirProvider : public nsIDirectoryServiceProvider
 {
@@ -68,18 +70,21 @@ public:
 private:
     nsCOMPtr<nsIFile> mGREDir;
     nsCOMPtr<nsIFile> mGREBinDir;
 };
 
 inline XPCShellEnvironment*
 Environment(Handle<JSObject*> global)
 {
-    AutoSafeJSContext cx;
-    JSAutoCompartment ac(cx, global);
+    AutoJSAPI jsapi;
+    if (!jsapi.Init(global)) {
+        return nullptr;
+    }
+    JSContext* cx = jsapi.cx();
     Rooted<Value> v(cx);
     if (!JS_GetProperty(cx, global, "__XPCShellEnvironment", &v) ||
         !v.get().isDouble())
     {
         return nullptr;
     }
     return static_cast<XPCShellEnvironment*>(v.get().toPrivate());
 }
@@ -446,20 +451,24 @@ XPCShellEnvironment::CreateEnvironment()
 
 XPCShellEnvironment::XPCShellEnvironment()
 :   mQuitting(false)
 {
 }
 
 XPCShellEnvironment::~XPCShellEnvironment()
 {
+    if (GetGlobalObject()) {
+        AutoJSAPI jsapi;
+        if (!jsapi.Init(GetGlobalObject())) {
+            return;
+        }
+        JSContext* cx = jsapi.cx();
+        Rooted<JSObject*> global(cx, GetGlobalObject());
 
-    AutoSafeJSContext cx;
-    Rooted<JSObject*> global(cx, GetGlobalObject());
-    if (global) {
         {
             JSAutoCompartment ac(cx, global);
             JS_SetAllNonReservedSlotsToUndefined(cx, global);
         }
         mGlobalHolder.reset();
 
         JSRuntime *rt = JS_GetRuntime(cx);
         JS_GC(rt);
@@ -563,19 +572,19 @@ XPCShellEnvironment::Init()
 
     return true;
 }
 
 bool
 XPCShellEnvironment::EvaluateString(const nsString& aString,
                                     nsString* aResult)
 {
-  AutoSafeJSContext cx;
-  JS::Rooted<JSObject*> global(cx, GetGlobalObject());
-  JSAutoCompartment ac(cx, global);
+  AutoEntryScript aes(GetGlobalObject(),
+                      "ipc XPCShellEnvironment::EvaluateString");
+  JSContext* cx = aes.cx();
 
   JS::CompileOptions options(cx);
   options.setFileAndLine("typein", 0);
   JS::Rooted<JSScript*> script(cx);
   if (!JS_CompileUCScript(cx, aString.get(), aString.Length(), options,
                           &script))
   {
      return false;