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 146469 e47089ae214d177d909b0d712bad1c36b6fba7cb
parent 146468 353aa004fed8365c64a5203df6fe73799c3422ca
child 146470 aa8d73a7b08a9ad9ad8da214e1d6131f1f4e72ad
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewersmccr8
bugs910937
milestone26.0a1
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"