Bug 910937: Remove xpc_UnmarkGrayObject and use JSAPI directly. r=mccr8
authorKyle Huey <khuey@kylehuey.com>
Sun, 08 Sep 2013 20:28:48 -0700
changeset 146107 e47089ae214d177d909b0d712bad1c36b6fba7cb
parent 146106 353aa004fed8365c64a5203df6fe73799c3422ca
child 146108 aa8d73a7b08a9ad9ad8da214e1d6131f1f4e72ad
push id25240
push useremorley@mozilla.com
push dateMon, 09 Sep 2013 12:09:06 +0000
treeherdermozilla-central@9846f07d5867 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8
bugs910937
milestone26.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 910937: Remove xpc_UnmarkGrayObject and use JSAPI directly. r=mccr8
content/base/src/EventSource.cpp
content/base/src/FragmentOrElement.cpp
content/base/src/WebSocket.cpp
content/base/src/nsXMLHttpRequest.cpp
content/canvas/src/ImageData.h
content/events/src/nsEventListenerManager.cpp
content/html/document/src/HTMLAllCollection.cpp
content/xbl/src/nsXBLDocumentInfo.cpp
content/xbl/src/nsXBLPrototypeHandler.cpp
content/xul/content/src/nsXULElement.cpp
content/xul/document/src/XULDocument.cpp
content/xul/document/src/nsXULPrototypeDocument.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsIJSEventListener.h
dom/base/nsJSEnvironment.cpp
dom/base/nsJSUtils.cpp
dom/base/nsWrapperCacheInlines.h
dom/bindings/BindingUtils.h
dom/bindings/CallbackObject.cpp
dom/bindings/CallbackObject.h
dom/bluetooth/BluetoothAdapter.cpp
dom/bluetooth/BluetoothDevice.cpp
js/public/GCAPI.h
js/xpconnect/src/XPCInlines.h
js/xpconnect/src/XPCWrappedJS.cpp
js/xpconnect/src/XPCWrappedNativeScope.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/src/xpcpublic.h
js/xpconnect/wrappers/WrapperFactory.cpp
layout/style/nsDOMCSSAttrDeclaration.cpp
security/manager/ssl/src/nsCrypto.cpp
--- a/content/base/src/EventSource.cpp
+++ b/content/base/src/EventSource.cpp
@@ -84,17 +84,18 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(EventSour
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(EventSource)
   bool isBlack = tmp->IsBlack();
   if (isBlack || tmp->mWaitingForOnStopRequest) {
     if (tmp->mListenerManager) {
       tmp->mListenerManager->MarkForCC();
     }
     if (!isBlack && tmp->PreservingWrapper()) {
-      xpc_UnmarkGrayObject(tmp->GetWrapperPreserveColor());
+      // This marks the wrapper black.
+      tmp->GetWrapper();
     }
     return true;
   }
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(EventSource)
   return tmp->IsBlack();
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
--- a/content/base/src/FragmentOrElement.cpp
+++ b/content/base/src/FragmentOrElement.cpp
@@ -1216,17 +1216,19 @@ FragmentOrElement::MarkUserDataHandler(v
 {
   xpc_TryUnmarkWrappedGrayObject(static_cast<nsISupports*>(aChild));
 }
 
 void
 FragmentOrElement::MarkNodeChildren(nsINode* aNode)
 {
   JSObject* o = GetJSObjectChild(aNode);
-  xpc_UnmarkGrayObject(o);
+  if (o) {
+    JS::ExposeObjectToActiveJS(o);
+  }
 
   nsEventListenerManager* elm = aNode->GetListenerManager(false);
   if (elm) {
     elm->MarkForCC();
   }
 
   if (aNode->HasProperties()) {
     nsIDocument* ownerDoc = aNode->OwnerDoc();
--- a/content/base/src/WebSocket.cpp
+++ b/content/base/src/WebSocket.cpp
@@ -576,17 +576,18 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(WebSocket
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(WebSocket)
   bool isBlack = tmp->IsBlack();
   if (isBlack|| tmp->mKeepingAlive) {
     if (tmp->mListenerManager) {
       tmp->mListenerManager->MarkForCC();
     }
     if (!isBlack && tmp->PreservingWrapper()) {
-      xpc_UnmarkGrayObject(tmp->GetWrapperPreserveColor());
+      // This marks the wrapper black.
+      tmp->GetWrapper();
     }
     return true;
   }
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(WebSocket)
   return tmp->IsBlack();
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -441,17 +441,18 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLHttp
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsXMLHttpRequest)
   bool isBlack = tmp->IsBlack();
   if (isBlack || tmp->mWaitingForOnStopRequest) {
     if (tmp->mListenerManager) {
       tmp->mListenerManager->MarkForCC();
     }
     if (!isBlack && tmp->PreservingWrapper()) {
-      xpc_UnmarkGrayObject(tmp->GetWrapperPreserveColor());
+      // This marks the wrapper black.
+      tmp->GetWrapper();
     }
     return true;
   }
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsXMLHttpRequest)
   return tmp->
     IsBlackAndDoesNotNeedTracing(static_cast<nsDOMEventTargetHelper*>(tmp));
--- a/content/canvas/src/ImageData.h
+++ b/content/canvas/src/ImageData.h
@@ -9,17 +9,17 @@
 
 #include "nsIDOMCanvasRenderingContext2D.h"
 
 #include "mozilla/Attributes.h"
 #include <stdint.h>
 
 #include "nsCycleCollectionParticipant.h"
 #include "nsTraceRefcnt.h"
-#include "xpcpublic.h"
+#include "js/GCAPI.h"
 
 namespace mozilla {
 namespace dom {
 
 class ImageData MOZ_FINAL : public nsISupports
 {
 public:
   ImageData(uint32_t aWidth, uint32_t aHeight, JSObject& aData)
@@ -49,17 +49,17 @@ public:
     return mHeight;
   }
   JSObject* Data(JSContext* cx, JS::Handle<JSObject*> /* unused */) const
   {
     return GetDataObject();
   }
   JSObject* GetDataObject() const
   {
-    xpc_UnmarkGrayObject(mData);
+    JS::ExposeObjectToActiveJS(mData);
     return mData;
   }
 
   JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> scope);
 
 private:
   void HoldData();
   void DropData();
--- a/content/events/src/nsEventListenerManager.cpp
+++ b/content/events/src/nsEventListenerManager.cpp
@@ -1325,19 +1325,21 @@ void
 nsEventListenerManager::MarkForCC()
 {
   uint32_t count = mListeners.Length();
   for (uint32_t i = 0; i < count; ++i) {
     const nsListenerStruct& ls = mListeners.ElementAt(i);
     nsIJSEventListener* jsl = ls.GetJSListener();
     if (jsl) {
       if (jsl->GetHandler().HasEventHandler()) {
-        xpc_UnmarkGrayObject(jsl->GetHandler().Ptr()->Callable());
+        JS::ExposeObjectToActiveJS(jsl->GetHandler().Ptr()->Callable());
       }
-      xpc_UnmarkGrayObject(jsl->GetEventScope());
+      if (JSObject* scope = jsl->GetEventScope()) {
+        JS::ExposeObjectToActiveJS(scope);
+      }
     } else if (ls.mListenerType == eWrappedJSListener) {
       xpc_TryUnmarkWrappedGrayObject(ls.mListener.GetXPCOMCallback());
     } else if (ls.mListenerType == eWebIDLListener) {
       // Callback() unmarks gray
       ls.mListener.GetWebIDLCallback()->Callback();
     }
   }
   if (mRefCnt.IsPurple()) {
--- a/content/html/document/src/HTMLAllCollection.cpp
+++ b/content/html/document/src/HTMLAllCollection.cpp
@@ -62,13 +62,14 @@ HTMLAllCollection::GetObject(JSContext* 
       return nullptr;
     }
 
     // Make the JSObject hold a reference to the document.
     JS_SetPrivate(mObject, ToSupports(mDocument));
     NS_ADDREF(mDocument);
   }
 
-  return xpc_UnmarkGrayObject(mObject);
+  JS::ExposeObjectToActiveJS(mObject);
+  return mObject;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/content/xbl/src/nsXBLDocumentInfo.cpp
+++ b/content/xbl/src/nsXBLDocumentInfo.cpp
@@ -208,17 +208,19 @@ void
 nsXBLDocGlobalObject::ClearGlobalObjectOwner()
 {
   mGlobalObjectOwner = nullptr;
 }
 
 void
 nsXBLDocGlobalObject::UnmarkCompilationGlobal()
 {
-  xpc_UnmarkGrayObject(mJSObject);
+  if (mJSObject) {
+    JS::ExposeObjectToActiveJS(mJSObject);
+  }
 }
 
 JSObject *
 nsXBLDocGlobalObject::GetCompilationGlobal()
 {
   // The prototype document has its own special secret script object
   // that can be used to compile scripts and event handlers.
   if (mJSObject || mDestroyed) {
@@ -352,17 +354,17 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsX
     ProtoTracer closure = { aCallbacks, aClosure };
     tmp->mBindingTable->Enumerate(TraceProtos, &closure);
   }
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 static void
 UnmarkXBLJSObject(void* aP, const char* aName, void* aClosure)
 {
-  xpc_UnmarkGrayObject(static_cast<JSObject*>(aP));
+  JS::ExposeObjectToActiveJS(static_cast<JSObject*>(aP));
 }
 
 static bool
 UnmarkProtos(nsHashKey* aKey, void* aData, void* aClosure)
 {
   nsXBLPrototypeBinding* proto = static_cast<nsXBLPrototypeBinding*>(aData);
   proto->Trace(TraceCallbackFunc(UnmarkXBLJSObject), nullptr);
   return kHashEnumerateNext;
--- a/content/xbl/src/nsXBLPrototypeHandler.cpp
+++ b/content/xbl/src/nsXBLPrototypeHandler.cpp
@@ -351,17 +351,17 @@ nsXBLPrototypeHandler::EnsureEventHandle
 {
   AutoPushJSContext cx(aBoundContext->GetNativeContext());
 
   // Check to see if we've already compiled this
   nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(aGlobal);
   if (pWindow) {
     JS::Rooted<JSObject*> cachedHandler(cx, pWindow->GetCachedXBLPrototypeHandler(this));
     if (cachedHandler) {
-      xpc_UnmarkGrayObject(cachedHandler);
+      JS::ExposeObjectToActiveJS(cachedHandler);
       aHandler.set(cachedHandler);
       NS_ENSURE_TRUE(aHandler, NS_ERROR_FAILURE);
       return NS_OK;
     }
   }
 
   // Ensure that we have something to compile
   nsDependentString handlerText(mHandlerText);
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -2633,17 +2633,19 @@ nsXULPrototypeScript::Compile(const PRUn
            .setFileAndLine(urlspec.get(), aLineNo)
            .setVersion(JSVersion(mLangVersion));
     // If the script was inline, tell the JS parser to save source for
     // Function.prototype.toSource(). If it's out of line, we retrieve the
     // source from the files on demand.
     options.setSourcePolicy(mOutOfLine ? JS::CompileOptions::LAZY_SOURCE
                                        : JS::CompileOptions::SAVE_SOURCE);
     JS::RootedObject scope(cx, JS::CurrentGlobalOrNull(cx));
-    xpc_UnmarkGrayObject(scope);
+    if (scope) {
+      JS::ExposeObjectToActiveJS(scope);
+    }
 
     if (aOffThreadReceiver && JS::CanCompileOffThread(cx, options)) {
         if (!JS::CompileOffThread(cx, scope, options,
                                   static_cast<const jschar*>(aText), aTextLength,
                                   OffThreadScriptReceiverCallback,
                                   static_cast<void*>(aOffThreadReceiver))) {
             return NS_ERROR_OUT_OF_MEMORY;
         }
--- a/content/xul/document/src/XULDocument.cpp
+++ b/content/xul/document/src/XULDocument.cpp
@@ -3663,17 +3663,20 @@ XULDocument::ExecuteScript(nsIScriptCont
     if (!aContext->GetScriptsEnabled())
         return NS_OK;
 
     // Execute the precompiled script with the given version
     nsAutoMicroTask mt;
     JSContext *cx = aContext->GetNativeContext();
     AutoCxPusher pusher(cx);
     JS::Rooted<JSObject*> global(cx, mScriptGlobalObject->GetGlobalJSObject());
-    xpc_UnmarkGrayObject(global);
+    // XXXkhuey can this ever be null?
+    if (global) {
+      JS::ExposeObjectToActiveJS(global);
+    }
     xpc_UnmarkGrayScript(aScriptObject);
     JSAutoCompartment ac(cx, global);
     JS::Rooted<JS::Value> unused(cx);
     if (!JS_ExecuteScript(cx, global, aScriptObject, unused.address()))
         nsJSUtils::ReportPendingException(cx);
     return NS_OK;
 }
 
--- a/content/xul/document/src/nsXULPrototypeDocument.cpp
+++ b/content/xul/document/src/nsXULPrototypeDocument.cpp
@@ -47,17 +47,22 @@ class nsXULPDGlobalObject : public nsISu
 public:
     nsXULPDGlobalObject(nsXULPrototypeDocument* owner);
 
     // nsISupports interface
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsXULPDGlobalObject)
 
     JSObject* GetCompilationGlobal();
-    void UnmarkCompilationGlobal() { xpc_UnmarkGrayObject(mJSObject); }
+    void UnmarkCompilationGlobal()
+    {
+        if (mJSObject) {
+            JS::ExposeObjectToActiveJS(mJSObject);
+        }
+    }
     void Destroy();
     nsIPrincipal* GetPrincipal();
     void ClearGlobalObjectOwner();
 
 protected:
     virtual ~nsXULPDGlobalObject();
 
     nsCOMPtr<nsIPrincipal> mCachedPrincipal;
@@ -725,19 +730,24 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULPDGlobalObject)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULPDGlobalObject)
 
 JSObject *
 nsXULPDGlobalObject::GetCompilationGlobal()
 {
-  if (mJSObject || mDestroyed) {
+  if (mJSObject) {
     // We've been initialized before. This is what we get.
-    return xpc_UnmarkGrayObject(mJSObject);
+    JS::ExposeObjectToActiveJS(mJSObject);
+    return mJSObject;
+  }
+
+  if (mDestroyed) {
+    return nullptr;
   }
 
   AutoSafeJSContext cx;
   JS::CompartmentOptions options;
   options.setZone(JS::SystemZone)
          .setInvisibleToDebugger(true);
   mJSObject = JS_NewGlobalObject(cx, &gSharedGlobalClass,
                                  nsJSPrincipals::get(GetPrincipal()),
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1554,17 +1554,17 @@ NS_INTERFACE_MAP_END
 
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindow)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindow)
 
 static PLDHashOperator
 MarkXBLHandlers(nsXBLPrototypeHandler* aKey, JS::Heap<JSObject*>& aData, void* aClosure)
 {
-  xpc_UnmarkGrayObject(aData);
+  JS::ExposeObjectToActiveJS(aData);
   return PL_DHASH_NEXT;
 }
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindow)
   if (tmp->IsBlackForCC()) {
     if (tmp->mCachedXBLPrototypeHandlers) {
       tmp->mCachedXBLPrototypeHandlers->Enumerate(MarkXBLHandlers, nullptr);
     }
@@ -2243,23 +2243,23 @@ nsGlobalWindow::SetNewDocument(nsIDocume
   if (reUseInnerWindow) {
     // We're reusing the current inner window.
     NS_ASSERTION(!currentInner->IsFrozen(),
                  "We should never be reusing a shared inner window");
     newInnerWindow = currentInner;
 
     if (aDocument != oldDoc) {
       JS::Rooted<JSObject*> obj(cx, currentInner->mJSObject);
-      xpc_UnmarkGrayObject(obj);
+      JS::ExposeObjectToActiveJS(obj);
     }
 
     // We're reusing the inner window, but this still counts as a navigation,
     // so all expandos and such defined on the outer window should go away. Force
     // all Xray wrappers to be recomputed.
-    xpc_UnmarkGrayObject(mJSObject);
+    JS::ExposeObjectToActiveJS(mJSObject);
     if (!JS_RefreshCrossCompartmentWrappers(cx, mJSObject)) {
       return NS_ERROR_FAILURE;
     }
 
     // Inner windows are only reused for same-origin principals, but the principals
     // don't necessarily match exactly. Update the principal on the compartment to
     // match the new document.
     // NB: We don't just call currentInner->RefreshCompartmentPrincipals() here
@@ -2354,18 +2354,18 @@ nsGlobalWindow::SetNewDocument(nsIDocume
 
     if (!mJSObject) {
       CreateOuterObject(newInnerWindow);
       mContext->DidInitializeContext();
 
       mJSObject = mContext->GetWindowProxy();
       SetWrapper(mJSObject);
     } else {
-      JS::Rooted<JSObject*> global(cx,
-        xpc_UnmarkGrayObject(newInnerWindow->mJSObject));
+      JS::ExposeObjectToActiveJS(newInnerWindow->mJSObject);
+      JS::Rooted<JSObject*> global(cx, newInnerWindow->mJSObject);
       JS::Rooted<JSObject*> outerObject(cx,
         NewOuterWindowProxy(cx, global, thisChrome));
       if (!outerObject) {
         NS_ERROR("out of memory");
         return NS_ERROR_FAILURE;
       }
 
       js::SetProxyExtra(mJSObject, 0, js::PrivateValue(NULL));
--- a/dom/base/nsIJSEventListener.h
+++ b/dom/base/nsIJSEventListener.h
@@ -196,17 +196,22 @@ public:
   void Disconnect()
   {
     mTarget = nullptr;
   }
 
   // Can return null if we already have a handler.
   JSObject* GetEventScope() const
   {
-    return xpc_UnmarkGrayObject(mScopeObject);
+    if (!mScopeObject) {
+      return nullptr;
+    }
+
+    JS::ExposeObjectToActiveJS(mScopeObject);
+    return mScopeObject;
   }
 
   const nsEventHandler& GetHandler() const
   {
     return mHandler;
   }
 
   nsIAtom* EventName() const
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -1039,34 +1039,39 @@ nsJSContext::JSObjectFromInterface(nsISu
 #ifdef DEBUG
   nsCOMPtr<nsISupports> targetSupp = do_QueryInterface(aTarget);
   nsCOMPtr<nsISupports> native =
     nsContentUtils::XPConnect()->GetNativeOfWrapper(cx,
                                                     JSVAL_TO_OBJECT(v));
   NS_ASSERTION(native == targetSupp, "Native should be the target!");
 #endif
 
-  *aRet = xpc_UnmarkGrayObject(JSVAL_TO_OBJECT(v));
-
+  JSObject* obj = v.toObjectOrNull();
+  if (obj) {
+    JS::ExposeObjectToActiveJS(obj);
+  }
+
+  *aRet = obj;
   return NS_OK;
 }
 
-
 nsresult
 nsJSContext::BindCompiledEventHandler(nsISupports* aTarget,
                                       JS::Handle<JSObject*> aScope,
                                       JS::Handle<JSObject*> aHandler,
                                       JS::MutableHandle<JSObject*> aBoundHandler)
 {
   NS_ENSURE_ARG(aHandler);
   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
   NS_PRECONDITION(!aBoundHandler, "Shouldn't already have a bound handler!");
 
-  xpc_UnmarkGrayObject(aScope);
-  xpc_UnmarkGrayObject(aHandler);
+  if (aScope) {
+    JS::ExposeObjectToActiveJS(aScope);
+  }
+  JS::ExposeObjectToActiveJS(aHandler);
   AutoPushJSContext cx(mContext);
 
   // Get the jsobject associated with this target
   JS::Rooted<JSObject*> target(cx);
   JS::Rooted<JSObject*> scope(cx, aScope);
   nsresult rv = JSObjectFromInterface(aTarget, scope, target.address());
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -2597,17 +2602,22 @@ void
 nsJSContext::SetWindowProxy(JS::Handle<JSObject*> aWindowProxy)
 {
   mWindowProxy = aWindowProxy;
 }
 
 JSObject*
 nsJSContext::GetWindowProxy()
 {
-  return xpc_UnmarkGrayObject(GetWindowProxyPreserveColor());
+  JSObject* windowProxy = GetWindowProxyPreserveColor();
+  if (windowProxy) {
+    JS::ExposeObjectToActiveJS(windowProxy);
+  }
+
+  return windowProxy;
 }
 
 JSObject*
 nsJSContext::GetWindowProxyPreserveColor()
 {
   return mWindowProxy;
 }
 
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -172,17 +172,19 @@ nsJSUtils::CompileFunction(JSContext* aC
 
   // Since aTarget and aCx are same-compartment, there should be no distinction
   // between the object principal and the cx principal.
   // However, aTarget may be null in the wacky aShared case. So use the cx.
   JSPrincipals* p = JS_GetCompartmentPrincipals(js::GetContextCompartment(aCx));
   aOptions.setPrincipals(p);
 
   // Do the junk Gecko is supposed to do before calling into JSAPI.
-  xpc_UnmarkGrayObject(aTarget);
+  if (aTarget) {
+    JS::ExposeObjectToActiveJS(aTarget);
+  }
 
   // Compile.
   JSFunction* fun = JS::CompileFunction(aCx, aTarget, aOptions,
                                         PromiseFlatCString(aName).get(),
                                         aArgCount, aArgArray,
                                         PromiseFlatString(aBody).get(),
                                         aBody.Length());
   if (!fun) {
@@ -233,17 +235,17 @@ nsJSUtils::EvaluateString(JSContext* aCx
   // Unfortunately, the JS engine actually compiles scripts with a return value
   // in a different, less efficient way.  Furthermore, it can't JIT them in many
   // cases.  So we need to be explicitly told whether the caller cares about the
   // return value.  Callers use null to indicate they don't care.
   if (aRetValue) {
     *aRetValue = JSVAL_VOID;
   }
 
-  xpc_UnmarkGrayObject(aScopeObject);
+  JS::ExposeObjectToActiveJS(aScopeObject);
   nsAutoMicroTask mt;
 
   JSPrincipals* p = JS_GetCompartmentPrincipals(js::GetObjectCompartment(aScopeObject));
   aCompileOptions.setPrincipals(p);
 
   bool ok = false;
   nsresult rv = nsContentUtils::GetSecurityManager()->
                   CanExecuteScripts(aCx, nsJSPrincipals::get(p), &ok);
--- a/dom/base/nsWrapperCacheInlines.h
+++ b/dom/base/nsWrapperCacheInlines.h
@@ -2,38 +2,41 @@
 /* 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/. */
 
 #ifndef nsWrapperCacheInline_h___
 #define nsWrapperCacheInline_h___
 
 #include "nsWrapperCache.h"
-#include "xpcpublic.h"
+#include "js/GCAPI.h"
+#include "jsapi.h"
 
 inline JSObject*
 nsWrapperCache::GetWrapper() const
 {
     JSObject* obj = GetWrapperPreserveColor();
-    xpc_UnmarkGrayObject(obj);
+    if (obj) {
+      JS::ExposeObjectToActiveJS(obj);
+    }
     return obj;
 }
 
 inline bool
 nsWrapperCache::IsBlack()
 {
   JSObject* o = GetWrapperPreserveColor();
-  return o && !xpc_IsGrayGCThing(o);
+  return o && !JS::GCThingIsMarkedGray(o);
 }
 
 static void
 SearchGray(void* aGCThing, const char* aName, void* aClosure)
 {
   bool* hasGrayObjects = static_cast<bool*>(aClosure);
-  if (!*hasGrayObjects && aGCThing && xpc_IsGrayGCThing(aGCThing)) {
+  if (!*hasGrayObjects && aGCThing && JS::GCThingIsMarkedGray(aGCThing)) {
     *hasGrayObjects = true;
   }
 }
 
 inline bool
 nsWrapperCache::IsBlackAndDoesNotNeedTracing(nsISupports* aThis)
 {
   if (IsBlack()) {
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -647,17 +647,17 @@ template <class T>
 MOZ_ALWAYS_INLINE bool
 WrapNewBindingObject(JSContext* cx, JS::Handle<JSObject*> scope, T* value,
                      JS::MutableHandle<JS::Value> rval)
 {
   MOZ_ASSERT(value);
   JSObject* obj = value->GetWrapperPreserveColor();
   bool couldBeDOMBinding = CouldBeDOMBinding(value);
   if (obj) {
-    xpc_UnmarkNonNullGrayObject(obj);
+    JS::ExposeObjectToActiveJS(obj);
   } else {
     // Inline this here while we have non-dom objects in wrapper caches.
     if (!couldBeDOMBinding) {
       return false;
     }
 
     obj = value->WrapObject(cx, scope);
     if (!obj) {
--- a/dom/bindings/CallbackObject.cpp
+++ b/dom/bindings/CallbackObject.cpp
@@ -101,17 +101,17 @@ CallbackObject::CallSetup::CallSetup(JS:
   // Unmark the callable, and stick it in a Rooted before it can go gray again.
   // Nothing before us in this function can trigger a CC, so it's safe to wait
   // until here it do the unmark. This allows us to order the following two
   // operations _after_ the Push() above, which lets us take advantage of the
   // JSAutoRequest embedded in the pusher.
   //
   // We can do this even though we're not in the right compartment yet, because
   // Rooted<> does not care about compartments.
-  xpc_UnmarkGrayObject(aCallback);
+  JS::ExposeObjectToActiveJS(aCallback);
   mRootedCallable.construct(cx, aCallback);
 
   // Check that it's ok to run this callback at all.
   // FIXME: Bug 807371: we want a less silly check here.
   // Make sure to unwrap aCallback before passing it in, because
   // getting principals from wrappers is silly.
   nsresult rv = nsContentUtils::GetSecurityManager()->
     CheckFunctionAccess(cx, js::UncheckedUnwrap(aCallback), nullptr);
--- a/dom/bindings/CallbackObject.h
+++ b/dom/bindings/CallbackObject.h
@@ -53,17 +53,17 @@ public:
 
   virtual ~CallbackObject()
   {
     DropCallback();
   }
 
   JS::Handle<JSObject*> Callback() const
   {
-    xpc_UnmarkGrayObject(mCallback);
+    JS::ExposeObjectToActiveJS(mCallback);
     return CallbackPreserveColor();
   }
 
   /*
    * This getter does not change the color of the JSObject meaning that the
    * object returned is not guaranteed to be kept alive past the next CC.
    *
    * This should only be called if you are certain that the return value won't
--- a/dom/bluetooth/BluetoothAdapter.cpp
+++ b/dom/bluetooth/BluetoothAdapter.cpp
@@ -416,29 +416,31 @@ JS::Value
 BluetoothAdapter::GetDevices(JSContext* aContext, ErrorResult& aRv)
 {
   if (!mJsDeviceAddresses) {
     NS_WARNING("Devices not yet set!\n");
     aRv.Throw(NS_ERROR_FAILURE);
     return JS::NullValue();
   }
 
-  return JS::ObjectValue(*xpc_UnmarkGrayObject(mJsDeviceAddresses));
+  JS::ExposeObjectToActiveJS(mJsDeviceAddresses);
+  return JS::ObjectValue(*mJsDeviceAddresses);
 }
 
 JS::Value
 BluetoothAdapter::GetUuids(JSContext* aContext, ErrorResult& aRv)
 {
   if (!mJsUuids) {
     NS_WARNING("UUIDs not yet set!\n");
     aRv.Throw(NS_ERROR_FAILURE);
     return JS::NullValue();
   }
 
-  return JS::ObjectValue(*xpc_UnmarkGrayObject(mJsUuids));
+  JS::ExposeObjectToActiveJS(mJsUuids);
+  return JS::ObjectValue(*mJsUuids);
 }
 
 already_AddRefed<DOMRequest>
 BluetoothAdapter::SetName(const nsAString& aName, ErrorResult& aRv)
 {
   if (mName.Equals(aName)) {
     return FirePropertyAlreadySet(GetOwner(), aRv);
   }
--- a/dom/bluetooth/BluetoothDevice.cpp
+++ b/dom/bluetooth/BluetoothDevice.cpp
@@ -201,28 +201,30 @@ JS::Value
 BluetoothDevice::GetUuids(JSContext* aCx, ErrorResult& aRv)
 {
   if (!mJsUuids) {
     NS_WARNING("UUIDs not yet set!\n");
     aRv.Throw(NS_ERROR_FAILURE);
     return JS::NullValue();
   }
 
-  return JS::ObjectValue(*xpc_UnmarkGrayObject(mJsUuids));
+  JS::ExposeObjectToActiveJS(mJsUuids);
+  return JS::ObjectValue(*mJsUuids);
 }
 
 JS::Value
 BluetoothDevice::GetServices(JSContext* aCx, ErrorResult& aRv)
 {
   if (!mJsServices) {
     NS_WARNING("Services not yet set!\n");
     aRv.Throw(NS_ERROR_FAILURE);
     return JS::Value(JSVAL_NULL);
   }
 
-  return JS::ObjectValue(*xpc_UnmarkGrayObject(mJsServices));
+  JS::ExposeObjectToActiveJS(mJsServices);
+  return JS::ObjectValue(*mJsServices);
 }
 
 JSObject*
 BluetoothDevice::WrapObject(JSContext* aContext, JS::Handle<JSObject*> aScope)
 {
   return BluetoothDeviceBinding::Wrap(aContext, aScope, this);
 }
--- a/js/public/GCAPI.h
+++ b/js/public/GCAPI.h
@@ -285,11 +285,17 @@ ExposeGCThingToActiveJS(void *thing, JSG
 
 static JS_ALWAYS_INLINE void
 ExposeValueToActiveJS(const Value &v)
 {
     if (v.isMarkable())
         ExposeGCThingToActiveJS(v.toGCThing(), v.gcKind());
 }
 
+static JS_ALWAYS_INLINE void
+ExposeObjectToActiveJS(JSObject *obj)
+{
+    ExposeGCThingToActiveJS(obj, JSTRACE_OBJECT);
+}
+
 } /* namespace JS */
 
 #endif /* js_GCAPI_h */
--- a/js/xpconnect/src/XPCInlines.h
+++ b/js/xpconnect/src/XPCInlines.h
@@ -483,17 +483,19 @@ JSObject* XPCWrappedNativeTearOff::GetJS
 {
     return reinterpret_cast<JSObject *>(reinterpret_cast<uintptr_t>(mJSObject) & ~1);
 }
 
 inline
 JSObject* XPCWrappedNativeTearOff::GetJSObject()
 {
     JSObject *obj = GetJSObjectPreserveColor();
-    xpc_UnmarkGrayObject(obj);
+    if (obj) {
+      JS::ExposeObjectToActiveJS(obj);
+    }
     return obj;
 }
 
 inline
 void XPCWrappedNativeTearOff::SetJSObject(JSObject*  JSObj)
 {
     MOZ_ASSERT(!IsMarked());
     mJSObject = JSObj;
--- a/js/xpconnect/src/XPCWrappedJS.cpp
+++ b/js/xpconnect/src/XPCWrappedJS.cpp
@@ -241,17 +241,18 @@ nsXPCWrappedJS::GetWeakReference(nsIWeak
         return mRoot->GetWeakReference(aInstancePtr);
 
     return nsSupportsWeakReference::GetWeakReference(aInstancePtr);
 }
 
 JSObject*
 nsXPCWrappedJS::GetJSObject()
 {
-    return xpc_UnmarkGrayObject(mJSObj);
+    JS::ExposeObjectToActiveJS(mJSObj);
+    return mJSObj;
 }
 
 static bool
 CheckMainThreadOnly(nsXPCWrappedJS *aWrapper)
 {
     if(aWrapper->IsMainThreadOnly())
         return NS_IsMainThread();
 
--- a/js/xpconnect/src/XPCWrappedNativeScope.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp
@@ -286,17 +286,17 @@ XPCWrappedNativeScope::AllowXBLScope()
 namespace xpc {
 JSObject *GetXBLScope(JSContext *cx, JSObject *contentScopeArg)
 {
     JS::RootedObject contentScope(cx, contentScopeArg);
     JSAutoCompartment ac(cx, contentScope);
     JSObject *scope = EnsureCompartmentPrivate(contentScope)->scope->EnsureXBLScope(cx);
     NS_ENSURE_TRUE(scope, nullptr); // See bug 858642.
     scope = js::UncheckedUnwrap(scope);
-    xpc_UnmarkGrayObject(scope);
+    JS::ExposeObjectToActiveJS(scope);
     return scope;
 }
 
 bool AllowXBLScope(JSCompartment *c)
 {
   XPCWrappedNativeScope *scope = EnsureCompartmentPrivate(c)->scope;
   return scope && scope->AllowXBLScope();
 }
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -1295,18 +1295,20 @@ public:
     nsXPCComponents*
     GetComponents() const {return mComponents;}
 
     // Returns the JS object reflection of the Components object.
     JSObject*
     GetComponentsJSObject();
 
     JSObject*
-    GetGlobalJSObject() const
-        {return xpc_UnmarkGrayObject(mGlobalJSObject);}
+    GetGlobalJSObject() const {
+        JS::ExposeObjectToActiveJS(mGlobalJSObject);
+        return mGlobalJSObject;
+    }
 
     JSObject*
     GetGlobalJSObjectPreserveColor() const {return mGlobalJSObject;}
 
     nsIPrincipal*
     GetPrincipal() const {
         JSCompartment *c = js::GetObjectCompartment(mGlobalJSObject);
         return nsJSPrincipals::get(JS_GetCompartmentPrincipals(c));
@@ -2024,17 +2026,20 @@ public:
 
     XPCWrappedNativeScope*
     GetScope()   const {return mScope;}
 
     XPCJSRuntime*
     GetRuntime() const {return mScope->GetRuntime();}
 
     JSObject*
-    GetJSProtoObject() const {return xpc_UnmarkGrayObject(mJSProtoObject);}
+    GetJSProtoObject() const {
+        JS::ExposeObjectToActiveJS(mJSProtoObject);
+        return mJSProtoObject;
+    }
 
     nsIClassInfo*
     GetClassInfo()     const {return mClassInfo;}
 
     XPCNativeSet*
     GetSet()           const {return mSet;}
 
     XPCNativeScriptableInfo*
@@ -2290,18 +2295,20 @@ public:
     GetIdentityObject() const {return mIdentity;}
 
     /**
      * This getter clears the gray bit before handing out the JSObject which
      * means that the object is guaranteed to be kept alive past the next CC.
      */
     JSObject*
     GetFlatJSObject() const
-        {xpc_UnmarkGrayObject(mFlatJSObject);
-         return mFlatJSObject;}
+    {
+        JS::ExposeObjectToActiveJS(mFlatJSObject);
+        return mFlatJSObject;
+    }
 
     /**
      * This getter does not change the color of the JSObject meaning that the
      * object returned is not guaranteed to be kept alive past the next CC.
      *
      * This should only be called if you are certain that the return value won't
      * be passed into a JS API function and that it won't be stored without
      * being rooted (or otherwise signaling the stored value to the CC).
@@ -2480,17 +2487,17 @@ public:
     void SetNeedsCOW() { mWrapper.setFlags(WRAPPER_NEEDS_COW); }
 
     JSObject* GetWrapperPreserveColor() const { return mWrapper.getPtr(); }
 
     JSObject* GetWrapper()
     {
         JSObject* wrapper = GetWrapperPreserveColor();
         if (wrapper) {
-            xpc_UnmarkGrayObject(wrapper);
+            JS::ExposeObjectToActiveJS(wrapper);
             // Call this to unmark mFlatJSObject.
             GetFlatJSObject();
         }
         return wrapper;
     }
     void SetWrapper(JSObject *obj)
     {
         JS::IncrementalObjectBarrier(GetWrapperPreserveColor());
@@ -3566,20 +3573,21 @@ public:
 
     static XPCVariant* newVariant(JSContext* cx, jsval aJSVal);
 
     /**
      * This getter clears the gray bit before handing out the jsval if the jsval
      * represents a JSObject. That means that the object is guaranteed to be
      * kept alive past the next CC.
      */
-    jsval GetJSVal() const
-        {if (!JSVAL_IS_PRIMITIVE(mJSVal))
-             xpc_UnmarkGrayObject(JSVAL_TO_OBJECT(mJSVal));
-         return mJSVal;}
+    jsval GetJSVal() const {
+        if (!JSVAL_IS_PRIMITIVE(mJSVal))
+            JS::ExposeObjectToActiveJS(&mJSVal.toObject());
+        return mJSVal;
+    }
 
     /**
      * This getter does not change the color of the jsval (if it represents a
      * JSObject) meaning that the value returned is not guaranteed to be kept
      * alive past the next CC.
      *
      * This should only be called if you are certain that the return value won't
      * be passed into a JS API function and that it won't be stored without
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -132,33 +132,16 @@ xpc_IsGrayGCThing(void *thing)
     return JS::GCThingIsMarkedGray(thing);
 }
 
 // The cycle collector only cares about some kinds of GCthings that are
 // reachable from an XPConnect root. Implemented in nsXPConnect.cpp.
 extern bool
 xpc_GCThingIsGrayCCThing(void *thing);
 
-// Unmark gray for known-nonnull cases
-MOZ_ALWAYS_INLINE void
-xpc_UnmarkNonNullGrayObject(JSObject *obj)
-{
-    JS::ExposeGCThingToActiveJS(obj, JSTRACE_OBJECT);
-}
-
-// Remove the gray color from the given JSObject and any other objects that can
-// be reached through it.
-MOZ_ALWAYS_INLINE JSObject *
-xpc_UnmarkGrayObject(JSObject *obj)
-{
-    if (obj)
-        xpc_UnmarkNonNullGrayObject(obj);
-    return obj;
-}
-
 inline JSScript *
 xpc_UnmarkGrayScript(JSScript *script)
 {
     if (script)
         JS::ExposeGCThingToActiveJS(script, JSTRACE_SCRIPT);
 
     return script;
 }
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -54,17 +54,22 @@ WrapperFactory::GetXrayWaiver(JSObject *
     // Object should come fully unwrapped but outerized.
     MOZ_ASSERT(obj == UncheckedUnwrap(obj));
     MOZ_ASSERT(!js::GetObjectClass(obj)->ext.outerObject);
     XPCWrappedNativeScope *scope = GetObjectScope(obj);
     MOZ_ASSERT(scope);
 
     if (!scope->mWaiverWrapperMap)
         return NULL;
-    return xpc_UnmarkGrayObject(scope->mWaiverWrapperMap->Find(obj));
+
+    JSObject* xrayWaiver = scope->mWaiverWrapperMap->Find(obj);
+    if (xrayWaiver)
+        JS::ExposeObjectToActiveJS(xrayWaiver);
+
+    return xrayWaiver;
 }
 
 JSObject *
 WrapperFactory::CreateXrayWaiver(JSContext *cx, HandleObject obj)
 {
     // The caller is required to have already done a lookup.
     // NB: This implictly performs the assertions of GetXrayWaiver.
     MOZ_ASSERT(!GetXrayWaiver(obj));
--- a/layout/style/nsDOMCSSAttrDeclaration.cpp
+++ b/layout/style/nsDOMCSSAttrDeclaration.cpp
@@ -38,20 +38,18 @@ nsDOMCSSAttributeDeclaration::~nsDOMCSSA
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsDOMCSSAttributeDeclaration, mElement)
 
 // mElement holds a strong ref to us, so if it's going to be
 // skipped, the attribute declaration can't be part of a garbage
 // cycle.
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsDOMCSSAttributeDeclaration)
   if (tmp->mElement && Element::CanSkip(tmp->mElement, true)) {
     if (tmp->PreservingWrapper()) {
-      // Not relying on GetWrapper to unmark us gray because the
-      // side-effect thing is pretty weird.
-      JSObject* o = tmp->GetWrapperPreserveColor();
-      xpc_UnmarkGrayObject(o);
+      // This marks the wrapper black.
+      tmp->GetWrapper();
     }
     return true;
   }
   return tmp->IsBlack();
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsDOMCSSAttributeDeclaration)
   return tmp->IsBlack() ||
--- a/security/manager/ssl/src/nsCrypto.cpp
+++ b/security/manager/ssl/src/nsCrypto.cpp
@@ -46,16 +46,17 @@
 #include "nsJSPrincipals.h"
 #include "nsJSUtils.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIGenKeypairInfoDlg.h"
 #include "nsIDOMCryptoDialogs.h"
 #include "nsIFormSigningDialog.h"
 #include "nsIContentSecurityPolicy.h"
+#include "nsIURI.h"
 #include "jsapi.h"
 #include "js/OldDebugAPI.h"
 #include <ctype.h>
 #include "pk11func.h"
 #include "keyhi.h"
 #include "cryptohi.h"
 #include "seccomon.h"
 #include "secerr.h"