Backed out 12 changesets (bug 899367) for Windows and OSX mochitest failures on a CLOSED TREE.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 27 Aug 2013 21:14:54 -0400
changeset 157522 4fa161a24995bea6c49d1d12661589fcbb1fb2f2
parent 157521 b1197402e4856f11493c434388c3eef4dafd728a
child 157523 aa33608f75c19d7edd9d0959fb9de2d89643ecdc
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs899367
milestone26.0a1
backs out46cf4c3eb447581cab18bd71bf3a59691b90a8b7
d8a876219fc7603780cf13ffc332545517972a15
d930333f95a762b17ad99e911044ae4ec2d1c0c3
efae8cc0fff87d1e3fc844ab2f6609b724ab673a
1dd262d146a6b7bbb93df4494cd13fe51e33cd19
4c396b8a51d002e2fb51c236a89f6d3ac2f78d07
c8c30176639afcd782ced7b8801c4d0d338b121a
aaa8fbcf9aaf70ab5abc472117fbe600d6e5f084
d1a782044a4bc632644fc5c149ae013670c89cd1
b2672ab550469cbf3f443be917e4365ef4ac83cb
fc4deb0b06fa25030f23fd69af8bd89c14050fbc
b9f1018a609c2ac9a14eb24a6982e5a6d1946bf2
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
Backed out 12 changesets (bug 899367) for Windows and OSX mochitest failures on a CLOSED TREE. Backed out changeset 46cf4c3eb447 (bug 899367) Backed out changeset d8a876219fc7 (bug 899367) Backed out changeset d930333f95a7 (bug 899367) Backed out changeset efae8cc0fff8 (bug 899367) Backed out changeset 1dd262d146a6 (bug 899367) Backed out changeset 4c396b8a51d0 (bug 899367) Backed out changeset c8c30176639a (bug 899367) Backed out changeset aaa8fbcf9aaf (bug 899367) Backed out changeset d1a782044a4b (bug 899367) Backed out changeset b2672ab55046 (bug 899367) Backed out changeset fc4deb0b06fa (bug 899367) Backed out changeset b9f1018a609c (bug 899367)
caps/src/nsSecurityManagerFactory.cpp
content/events/src/nsEventListenerManager.cpp
dom/base/nsDOMJSUtils.h
dom/base/nsGlobalWindow.cpp
dom/base/nsIScriptContext.h
dom/base/nsJSEnvironment.cpp
dom/base/nsJSEnvironment.h
dom/base/nsJSUtils.cpp
dom/bluetooth/BluetoothManager.cpp
dom/file/ArchiveRequest.cpp
dom/file/FileRequest.cpp
dom/mobilemessage/src/MobileMessageCallback.cpp
dom/mobilemessage/src/MobileMessageCursorCallback.cpp
dom/mobilemessage/src/MobileMessageManager.cpp
dom/workers/RuntimeService.cpp
js/jsd/jsd_xpc.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jscntxtinlines.h
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/vm/SelfHosting.cpp
js/xpconnect/idl/nsIXPConnect.idl
js/xpconnect/src/XPCJSContextStack.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/XPCWrappedJSClass.cpp
js/xpconnect/src/nsCxPusher.cpp
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/xpcpublic.h
xpcom/base/CycleCollectedJSRuntime.cpp
xpcom/base/CycleCollectedJSRuntime.h
--- a/caps/src/nsSecurityManagerFactory.cpp
+++ b/caps/src/nsSecurityManagerFactory.cpp
@@ -61,17 +61,17 @@ static const JSFunctionSpec PrivilegeMan
 /*
  * "Steal" calls to netscape.security.PrivilegeManager.enablePrivilege,
  * et al. so that code that worked with 4.0 can still work.
  */
 NS_IMETHODIMP
 nsSecurityNameSet::InitializeNameSet(nsIScriptContext* aScriptContext)
 {
     AutoJSContext cx;
-    JS::Rooted<JSObject*> global(cx, aScriptContext->GetWindowProxy());
+    JS::Rooted<JSObject*> global(cx, aScriptContext->GetNativeGlobal());
     JSAutoCompartment ac(cx, global);
 
     /*
      * Find Object.prototype's class by walking up the global object's
      * prototype chain.
      */
     JS::Rooted<JSObject*> obj(cx, global);
     JS::Rooted<JSObject*> proto(cx);
--- a/content/events/src/nsEventListenerManager.cpp
+++ b/content/events/src/nsEventListenerManager.cpp
@@ -903,17 +903,17 @@ nsEventListenerManager::CompileEventHand
     // the only thing with weird arg names and SVG doesn't map event
     // listeners to the window.
     nsContentUtils::GetEventArgNames(content ?
                                        content->GetNameSpaceID() :
                                        kNameSpaceID_None,
                                      aListenerStruct->mTypeAtom,
                                      &argCount, &argNames);
 
-    JSAutoCompartment ac(cx, context->GetWindowProxy());
+    JSAutoCompartment ac(cx, context->GetNativeGlobal());
     JS::CompileOptions options(cx);
     options.setFileAndLine(url.get(), lineNo)
            .setVersion(SCRIPTVERSION_DEFAULT);
 
     JS::Rooted<JSObject*> handlerFun(cx);
     result = nsJSUtils::CompileFunction(cx, JS::NullPtr(), options,
                                         nsAtomCString(aListenerStruct->mTypeAtom),
                                         argCount, argNames, *body, handlerFun.address());
--- a/dom/base/nsDOMJSUtils.h
+++ b/dom/base/nsDOMJSUtils.h
@@ -23,18 +23,16 @@ GetScriptContextFromJSContext(JSContext 
     do_QueryInterface(static_cast<nsISupports *>
                                  (::JS_GetContextPrivate(cx)));
 
   // This will return a pointer to something that's about to be
   // released, but that's ok here.
   return scx;
 }
 
-JSObject* GetDefaultScopeFromJSContext(JSContext *cx);
-
 // A factory function for turning a JS::Value argv into an nsIArray
 // but also supports an effecient way of extracting the original argv.
 // Bug 312003 describes why this must be "void *", but argv will be cast to
 // JS::Value* and the args are found at:
 //    ((JS::Value*)aArgv)[0], ..., ((JS::Value*)aArgv)[aArgc - 1]
 // The resulting object will take a copy of the array, and ensure each
 // element is rooted.
 // Optionally, aArgv may be NULL, in which case the array is allocated and
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2043,19 +2043,18 @@ nsGlobalWindow::CreateOuterObject(nsGlob
   return SetOuterObject(cx, outer);
 }
 
 nsresult
 nsGlobalWindow::SetOuterObject(JSContext* aCx, JS::Handle<JSObject*> aOuterObject)
 {
   JSAutoCompartment ac(aCx, aOuterObject);
 
-  // Inform the nsJSContext, which is the canonical holder of the outer.
-  MOZ_ASSERT(IsOuterWindow());
-  mContext->SetWindowProxy(aOuterObject);
+  // Indicate the default compartment object associated with this cx.
+  js::SetDefaultObjectForContext(aCx, aOuterObject);
 
   // Set up the prototype for the outer object.
   JS::Rooted<JSObject*> inner(aCx, JS_GetParent(aOuterObject));
   JS::Rooted<JSObject*> proto(aCx);
   if (!JS_GetPrototype(aCx, inner, &proto)) {
     return NS_ERROR_FAILURE;
   }
   JS_SetPrototype(aCx, aOuterObject, proto);
@@ -2357,17 +2356,17 @@ nsGlobalWindow::SetNewDocument(nsIDocume
     }
 
     mInnerWindow = newInnerWindow;
 
     if (!mJSObject) {
       CreateOuterObject(newInnerWindow);
       mContext->DidInitializeContext();
 
-      mJSObject = mContext->GetWindowProxy();
+      mJSObject = mContext->GetNativeGlobal();
       SetWrapper(mJSObject);
     } else {
       JS::Rooted<JSObject*> global(cx,
         xpc_UnmarkGrayObject(newInnerWindow->mJSObject));
       JS::Rooted<JSObject*> outerObject(cx,
         NewOuterWindowProxy(cx, global, thisChrome));
       if (!outerObject) {
         NS_ERROR("out of memory");
@@ -2441,17 +2440,21 @@ nsGlobalWindow::SetNewDocument(nsIDocume
 
     // Now that both the the inner and outer windows are initialized
     // let the script context do its magic to hook them together.
 #ifdef DEBUG
     JS::Rooted<JSObject*> newInnerJSObject(cx,
         newInnerWindow->FastGetGlobalJSObject());
 #endif
 
-    MOZ_ASSERT(mContext->GetWindowProxy() == mJSObject);
+    // Now that we're connecting the outer global to the inner one,
+    // we must have transplanted it. The JS engine tries to maintain
+    // the global object's compartment as its default compartment,
+    // so update that now since it might have changed.
+    js::SetDefaultObjectForContext(cx, mJSObject);
 #ifdef DEBUG
     JS::Rooted<JSObject*> rootedJSObject(cx, mJSObject);
     JS::Rooted<JSObject*> proto1(cx), proto2(cx);
     JS_GetPrototype(cx, rootedJSObject, &proto1);
     JS_GetPrototype(cx, newInnerJSObject, &proto2);
     NS_ASSERTION(proto1 == proto2,
                  "outer and inner globals should have the same prototype");
 #endif
--- a/dom/base/nsIScriptContext.h
+++ b/dom/base/nsIScriptContext.h
@@ -22,18 +22,18 @@ class nsIArray;
 class nsIVariant;
 class nsIObjectInputStream;
 class nsIObjectOutputStream;
 class nsIScriptObjectPrincipal;
 class nsIDOMWindow;
 class nsIURI;
 
 #define NS_ISCRIPTCONTEXT_IID \
-{ 0xf3859ce7, 0x7551, 0x4760, \
-  { 0x84, 0x29, 0x64, 0x4f, 0x26, 0x1e, 0xdb, 0x91 } }
+{ 0x1d931a17, 0x453a, 0x47fb, \
+  { 0x94, 0x66, 0x2d, 0x3e, 0xd1, 0xef, 0x7a, 0xc5 } }
 
 /* This MUST match JSVERSION_DEFAULT.  This version stuff if we don't
    know what language we have is a little silly... */
 #define SCRIPTVERSION_DEFAULT JSVERSION_DEFAULT
 
 class nsIOffThreadScriptReceiver;
 
 /**
@@ -99,16 +99,22 @@ public:
 
   /**
    * Return the native script context
    *
    **/
   virtual JSContext* GetNativeContext() = 0;
 
   /**
+   * Return the native global object for this context.
+   *
+   **/
+  virtual JSObject* GetNativeGlobal() = 0;
+
+  /**
    * Initialize the context generally. Does not create a global object.
    **/
   virtual nsresult InitContext() = 0;
 
   /**
    * Check to see if context is as yet intialized. Used to prevent
    * reentrancy issues during the initialization process.
    *
@@ -154,22 +160,16 @@ public:
    * Tell the context we're about to be reinitialize it.
    */
   virtual void WillInitializeContext() = 0;
 
   /**
    * Tell the context we're done reinitializing it.
    */
   virtual void DidInitializeContext() = 0;
-
-  /**
-   * Access the Window Proxy. The setter should only be called by nsGlobalWindow.
-   */
-  virtual void SetWindowProxy(JS::Handle<JSObject*> aWindowProxy) = 0;
-  virtual JSObject* GetWindowProxy() = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptContext, NS_ISCRIPTCONTEXT_IID)
 
 #define NS_IOFFTHREADSCRIPTRECEIVER_IID \
 {0x3a980010, 0x878d, 0x46a9,            \
   {0x93, 0xad, 0xbc, 0xfd, 0xd3, 0x8e, 0xa0, 0xc2}}
 
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -75,19 +75,17 @@
 #include "prlog.h"
 #include "prthread.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/CanvasRenderingContext2DBinding.h"
-#include "mozilla/CycleCollectedJSRuntime.h"
-
-#include "nsCycleCollectionNoteRootCallback.h"
+
 #include "GeckoProfiler.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 const size_t gStackSize = 8192;
 
 #ifdef PR_LOGGING
@@ -819,33 +817,31 @@ nsJSContext::JSOptionChangedCallback(con
     ::JS_SetGCZeal(context->mContext, (uint8_t)zeal, frequency);
 #endif
 
   return 0;
 }
 
 nsJSContext::nsJSContext(bool aGCOnDestruction,
                          nsIScriptGlobalObject* aGlobalObject)
-  : mWindowProxy(nullptr)
-  , mGCOnDestruction(aGCOnDestruction)
+  : mGCOnDestruction(aGCOnDestruction)
   , mGlobalObjectRef(aGlobalObject)
 {
   EnsureStatics();
 
   mNext = sContextList;
   mPrev = &sContextList;
   if (sContextList) {
     sContextList->mPrev = &mNext;
   }
   sContextList = this;
 
   ++sContextCount;
 
-  mDefaultJSOptions = JSOPTION_PRIVATE_IS_NSISUPPORTS |
-                      JSOPTION_NO_DEFAULT_COMPARTMENT_OBJECT;
+  mDefaultJSOptions = JSOPTION_PRIVATE_IS_NSISUPPORTS;
 
   mContext = ::JS_NewContext(sRuntime, gStackSize);
   if (mContext) {
     ::JS_SetContextPrivate(mContext, static_cast<nsIScriptContext *>(this));
 
     // Preserve any flags the context callback might have set.
     mDefaultJSOptions |= ::JS_GetOptions(mContext);
 
@@ -854,17 +850,16 @@ nsJSContext::nsJSContext(bool aGCOnDestr
 
     // Watch for the JS boolean options
     Preferences::RegisterCallback(JSOptionChangedCallback,
                                   js_options_dot_str, this);
   }
   mIsInitialized = false;
   mScriptsEnabled = true;
   mProcessingScriptTag = false;
-  NS_HOLD_JS_OBJECTS(this, nsJSContext);
 }
 
 nsJSContext::~nsJSContext()
 {
   *mPrev = mNext;
   if (mNext) {
     mNext->mPrev = mPrev;
   }
@@ -905,39 +900,41 @@ nsJSContext::DestroyJSContext()
                                   js_options_dot_str, this);
 
   if (mGCOnDestruction) {
     PokeGC(JS::gcreason::NSJSCONTEXT_DESTROY);
   }
 
   JS_DestroyContextNoGC(mContext);
   mContext = nullptr;
-  NS_DROP_JS_OBJECTS(this, nsJSContext);
 }
 
 // QueryInterface implementation for nsJSContext
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSContext)
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSContext)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mWindowProxy)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSContext)
   NS_ASSERTION(!tmp->mContext || !js::ContextHasOutstandingRequests(tmp->mContext),
                "Trying to unlink a context with outstanding requests.");
   tmp->mIsInitialized = false;
   tmp->mGCOnDestruction = false;
-  tmp->mWindowProxy = nullptr;
+  if (tmp->mContext) {
+    JSAutoRequest ar(tmp->mContext);
+    js::SetDefaultObjectForContext(tmp->mContext, nullptr);
+  }
   tmp->DestroyJSContext();
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobalObjectRef)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSContext)
   NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsJSContext, tmp->GetCCRefcnt())
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobalObjectRef)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mContext");
+  nsContentUtils::XPConnect()->NoteJSContext(tmp->mContext, cb);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSContext)
   NS_INTERFACE_MAP_ENTRY(nsIScriptContext)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 
@@ -1080,17 +1077,17 @@ nsJSContext::BindCompiledEventHandler(ns
 
   return rv;
 }
 
 nsIScriptGlobalObject *
 nsJSContext::GetGlobalObject()
 {
   AutoJSContext cx;
-  JS::Rooted<JSObject*> global(mContext, GetWindowProxy());
+  JS::Rooted<JSObject*> global(mContext, GetNativeGlobal());
   if (!global) {
     return nullptr;
   }
 
   if (mGlobalObjectRef)
     return mGlobalObjectRef;
 
 #ifdef DEBUG
@@ -1129,20 +1126,26 @@ nsJSContext::GetGlobalObject()
     sgo = do_QueryInterface(priv);
   }
 
   // This'll return a pointer to something we're about to release, but
   // that's ok, the JS object will hold it alive long enough.
   return sgo;
 }
 
+JSObject*
+nsJSContext::GetNativeGlobal()
+{
+    return js::DefaultObjectForContextOrNull(mContext);
+}
+
 JSContext*
 nsJSContext::GetNativeContext()
 {
-  return mContext;
+  return xpc_UnmarkGrayContext(mContext);
 }
 
 nsresult
 nsJSContext::InitContext()
 {
   // Make sure callers of this use
   // WillInitializeContext/DidInitializeContext around this call.
   NS_ENSURE_TRUE(!mIsInitialized, NS_ERROR_ALREADY_INITIALIZED);
@@ -1172,17 +1175,17 @@ nsJSContext::SetProperty(JS::Handle<JSOb
   uint32_t  argc;
   JS::Value *argv = nullptr;
 
   nsCxPusher pusher;
   pusher.Push(mContext);
 
   Maybe<nsRootedJSValueArray> tempStorage;
 
-  JS::Rooted<JSObject*> global(mContext, GetWindowProxy());
+  JS::Rooted<JSObject*> global(mContext, GetNativeGlobal());
   nsresult rv =
     ConvertSupportsTojsvals(aArgs, global, &argc, &argv, tempStorage);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // got the arguments, now attach them.
 
   for (uint32_t i = 0; i < argc; ++i) {
     if (!JS_WrapValue(mContext, &argv[i])) {
@@ -1468,17 +1471,17 @@ nsJSContext::AddSupportsPrimitiveTojsval
 
       p->GetData(getter_AddRefs(data));
       p->GetDataIID(&iid);
       NS_ENSURE_TRUE(iid, NS_ERROR_UNEXPECTED);
 
       AutoFree iidGuard(iid); // Free iid upon destruction.
 
       nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
-      JS::Rooted<JSObject*> global(cx, GetWindowProxy());
+      JS::Rooted<JSObject*> global(cx, xpc_UnmarkGrayObject(GetNativeGlobal()));
       JS::Rooted<JS::Value> v(cx);
       nsresult rv = nsContentUtils::WrapNative(cx, global,
                                                data, iid, v.address(),
                                                getter_AddRefs(wrapper));
       NS_ENSURE_SUCCESS(rv, rv);
 
       *aArgv = v;
 
@@ -2571,28 +2574,16 @@ void
 nsJSContext::ReportPendingException()
 {
   if (mIsInitialized) {
     nsJSUtils::ReportPendingException(mContext);
   }
 }
 
 void
-nsJSContext::SetWindowProxy(JS::Handle<JSObject*> aWindowProxy)
-{
-  mWindowProxy = aWindowProxy;
-}
-
-JSObject*
-nsJSContext::GetWindowProxy()
-{
-  return xpc_UnmarkGrayObject(mWindowProxy);
-}
-
-void
 nsJSContext::LikelyShortLivingObjectCreated()
 {
   ++sLikelyShortLivingObjectsNeedingGC;
 }
 
 void
 mozilla::dom::StartupJSEnvironment()
 {
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -14,17 +14,16 @@
 #include "nsIXPConnect.h"
 #include "nsIArray.h"
 #include "mozilla/Attributes.h"
 
 class nsICycleCollectorListener;
 class nsIXPConnectJSObjectHolder;
 class nsRootedJSValueArray;
 class nsScriptNameSpaceManager;
-class nsCycleCollectionNoteRootCallback;
 
 namespace mozilla {
 template <class> class Maybe;
 }
 
 // The amount of time we wait between a request to GC (due to leaving
 // a page) and doing the actual GC.
 #define NS_GC_DELAY                 4000 // ms
@@ -49,35 +48,33 @@ public:
                                             JS::Handle<JSObject*> aScope,
                                             JS::Handle<JSObject*> aHandler,
                                             JS::MutableHandle<JSObject*> aBoundHandler) MOZ_OVERRIDE;
 
   virtual nsIScriptGlobalObject *GetGlobalObject() MOZ_OVERRIDE;
   inline nsIScriptGlobalObject *GetGlobalObjectRef() { return mGlobalObjectRef; }
 
   virtual JSContext* GetNativeContext() MOZ_OVERRIDE;
+  virtual JSObject* GetNativeGlobal() MOZ_OVERRIDE;
   virtual nsresult InitContext() MOZ_OVERRIDE;
   virtual bool IsContextInitialized() MOZ_OVERRIDE;
 
   virtual bool GetScriptsEnabled() MOZ_OVERRIDE;
   virtual void SetScriptsEnabled(bool aEnabled, bool aFireTimeouts) MOZ_OVERRIDE;
 
   virtual nsresult SetProperty(JS::Handle<JSObject*> aTarget, const char* aPropName, nsISupports* aVal) MOZ_OVERRIDE;
 
   virtual bool GetProcessingScriptTag() MOZ_OVERRIDE;
   virtual void SetProcessingScriptTag(bool aResult) MOZ_OVERRIDE;
 
   virtual nsresult InitClasses(JS::Handle<JSObject*> aGlobalObj) MOZ_OVERRIDE;
 
   virtual void WillInitializeContext() MOZ_OVERRIDE;
   virtual void DidInitializeContext() MOZ_OVERRIDE;
 
-  virtual void SetWindowProxy(JS::Handle<JSObject*> aWindowProxy) MOZ_OVERRIDE;
-  virtual JSObject* GetWindowProxy() MOZ_OVERRIDE;
-
   static void LoadStart();
   static void LoadEnd();
 
   enum IsCompartment {
     CompartmentGC,
     NonCompartmentGC
   };
 
@@ -123,17 +120,17 @@ public:
   virtual void GC(JS::gcreason::Reason aReason) MOZ_OVERRIDE;
 
   static uint32_t CleanupsSinceLastGC();
 
   nsIScriptGlobalObject* GetCachedGlobalObject()
   {
     // Verify that we have a global so that this
     // does always return a null when GetGlobalObject() is null.
-    JSObject* global = GetWindowProxy();
+    JSObject* global = GetNativeGlobal();
     return global ? mGlobalObjectRef.get() : nullptr;
   }
 protected:
   nsresult InitializeExternalClasses();
 
   // Helper to convert xpcom datatypes to jsvals.
   nsresult ConvertSupportsTojsvals(nsISupports *aArgs,
                                    JS::Handle<JSObject*> aScope,
@@ -148,24 +145,22 @@ protected:
   nsresult JSObjectFromInterface(nsISupports *aSup,
                                  JS::Handle<JSObject*> aScript,
                                  JSObject **aRet);
 
   // Report the pending exception on our mContext, if any.  This
   // function will set aside the frame chain on mContext before
   // reporting.
   void ReportPendingException();
-
 private:
   void DestroyJSContext();
 
   nsrefcnt GetCCRefcnt();
 
   JSContext *mContext;
-  JS::Heap<JSObject*> mWindowProxy;
 
   bool mIsInitialized;
   bool mScriptsEnabled;
   bool mGCOnDestruction;
   bool mProcessingScriptTag;
 
   uint32_t mDefaultJSOptions;
   PRTime mOperationCallbackTime;
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -9,17 +9,16 @@
  * invoked from the JavaScript code generated from IDL interfaces.
  * The goal of the utility functions is to cut down on the size of
  * the generated code itself.
  */
 
 #include "nsJSUtils.h"
 #include "jsapi.h"
 #include "jsdbgapi.h"
-#include "jsfriendapi.h"
 #include "nsIScriptContext.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIXPConnect.h"
 #include "nsCOMPtr.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsPIDOMWindow.h"
 #include "GeckoProfiler.h"
 #include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
@@ -136,21 +135,17 @@ nsJSUtils::GetCurrentlyRunningCodeInnerW
 }
 
 void
 nsJSUtils::ReportPendingException(JSContext *aContext)
 {
   if (JS_IsExceptionPending(aContext)) {
     bool saved = JS_SaveFrameChain(aContext);
     {
-      nsIScriptContext* scx = GetScriptContextFromJSContext(aContext);
-      JS::Rooted<JSObject*> scope(aContext);
-      scope = scx ? scx->GetWindowProxy()
-                  : js::DefaultObjectForContextOrNull(aContext);
-      JSAutoCompartment ac(aContext, scope);
+      JSAutoCompartment ac(aContext, js::DefaultObjectForContextOrNull(aContext));
       JS_ReportPendingException(aContext);
     }
     if (saved) {
       JS_RestoreFrameChain(aContext);
     }
   }
 }
 
@@ -287,24 +282,8 @@ nsJSUtils::EvaluateString(JSContext* aCx
     }
   }
 
   // Wrap the return value into whatever compartment aCx was in.
   if (aRetValue && !JS_WrapValue(aCx, aRetValue))
     return NS_ERROR_OUT_OF_MEMORY;
   return rv;
 }
-
-//
-// nsDOMJSUtils.h
-//
-
-JSObject* GetDefaultScopeFromJSContext(JSContext *cx)
-{
-  // DOM JSContexts don't store their default compartment object on
-  // the cx, so in those cases we need to fetch it via the scx
-  // instead.
-  nsIScriptContext *scx = GetScriptContextFromJSContext(cx);
-  if (scx) {
-    return scx->GetWindowProxy();
-  }
-  return js::DefaultObjectForContextOrNull(cx);
-}
--- a/dom/bluetooth/BluetoothManager.cpp
+++ b/dom/bluetooth/BluetoothManager.cpp
@@ -63,17 +63,17 @@ public:
     if (!sc) {
       NS_WARNING("Cannot create script context!");
       SetError(NS_LITERAL_STRING("BluetoothScriptContextError"));
       return false;
     }
 
     AutoPushJSContext cx(sc->GetNativeContext());
 
-    JS::Rooted<JSObject*> global(cx, sc->GetWindowProxy());
+    JS::Rooted<JSObject*> global(cx, sc->GetNativeGlobal());
     rv = nsContentUtils::WrapNative(cx, global, adapter, aValue);
     if (NS_FAILED(rv)) {
       NS_WARNING("Cannot create native object!");
       SetError(NS_LITERAL_STRING("BluetoothNativeObjectError"));
       return false;
     }
 
     return true;
--- a/dom/file/ArchiveRequest.cpp
+++ b/dom/file/ArchiveRequest.cpp
@@ -130,17 +130,17 @@ ArchiveRequest::ReaderReady(nsTArray<nsC
   nsresult rv;
 
   nsIScriptContext* sc = GetContextForEventHandlers(&rv);
   NS_ENSURE_STATE(sc);
 
   AutoPushJSContext cx(sc->GetNativeContext());
   NS_ASSERTION(cx, "Failed to get a context!");
 
-  JS::Rooted<JSObject*> global(cx, sc->GetWindowProxy());
+  JS::Rooted<JSObject*> global(cx, sc->GetNativeGlobal());
   NS_ASSERTION(global, "Failed to get global object!");
 
   JSAutoCompartment ac(cx, global);
 
   JS::Rooted<JS::Value> result(cx);
   switch (mOperation) {
     case GetFilenames:
       rv = GetFilenamesResult(cx, result.address(), aFileList);
--- a/dom/file/FileRequest.cpp
+++ b/dom/file/FileRequest.cpp
@@ -74,17 +74,17 @@ FileRequest::NotifyHelperCompleted(FileH
   nsIScriptContext* sc = GetContextForEventHandlers(&rv);
   NS_ENSURE_STATE(sc);
 
   AutoPushJSContext cx(sc->GetNativeContext());
   NS_ASSERTION(cx, "Failed to get a context!");
 
   JS::Rooted<JS::Value> result(cx);
 
-  JS::Rooted<JSObject*> global(cx, sc->GetWindowProxy());
+  JS::Rooted<JSObject*> global(cx, sc->GetNativeGlobal());
   NS_ASSERTION(global, "Failed to get global object!");
 
   JSAutoCompartment ac(cx, global);
 
   rv = aFileHelper->GetSuccessResult(cx, result.address());
   if (NS_FAILED(rv)) {
     NS_WARNING("GetSuccessResult failed!");
   }
--- a/dom/mobilemessage/src/MobileMessageCallback.cpp
+++ b/dom/mobilemessage/src/MobileMessageCallback.cpp
@@ -51,17 +51,17 @@ MobileMessageCallback::NotifySuccess(nsI
   nsresult rv;
   nsIScriptContext* scriptContext = mDOMRequest->GetContextForEventHandlers(&rv);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(scriptContext, NS_ERROR_FAILURE);
 
   AutoPushJSContext cx(scriptContext->GetNativeContext());
   NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
 
-  JS::Rooted<JSObject*> global(cx, scriptContext->GetWindowProxy());
+  JS::Rooted<JSObject*> global(cx, scriptContext->GetNativeGlobal());
   NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
 
   JSAutoCompartment ac(cx, global);
 
   JS::Rooted<JS::Value> wrappedMessage(cx);
   rv = nsContentUtils::WrapNative(cx, global, aMessage,
                                   wrappedMessage.address());
   NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/mobilemessage/src/MobileMessageCursorCallback.cpp
+++ b/dom/mobilemessage/src/MobileMessageCursorCallback.cpp
@@ -62,17 +62,17 @@ MobileMessageCursorCallback::NotifyCurso
   nsresult rv;
   nsIScriptContext* scriptContext = mDOMCursor->GetContextForEventHandlers(&rv);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(scriptContext, NS_ERROR_FAILURE);
 
   AutoPushJSContext cx(scriptContext->GetNativeContext());
   NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
 
-  JS::Rooted<JSObject*> global(cx, scriptContext->GetWindowProxy());
+  JS::Rooted<JSObject*> global(cx, scriptContext->GetNativeGlobal());
   NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
 
   JSAutoCompartment ac(cx, global);
 
   JS::Rooted<JS::Value> wrappedResult(cx);
   rv = nsContentUtils::WrapNative(cx, global, aResult, wrappedResult.address());
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/dom/mobilemessage/src/MobileMessageManager.cpp
+++ b/dom/mobilemessage/src/MobileMessageManager.cpp
@@ -150,17 +150,17 @@ MobileMessageManager::Send(const JS::Val
   NS_ASSERTION(cx, "Failed to get a context!");
 
   JS::Rooted<JS::Value> aNumber(cx, aNumber_);
   if (!aNumber.isString() &&
       !(aNumber.isObject() && JS_IsArrayObject(cx, &aNumber.toObject()))) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  JS::Rooted<JSObject*> global(cx, sc->GetWindowProxy());
+  JS::Rooted<JSObject*> global(cx, sc->GetNativeGlobal());
   NS_ASSERTION(global, "Failed to get global object!");
 
   JSAutoCompartment ac(cx, global);
 
   if (aNumber.isString()) {
     JS::Rooted<JSString*> str(cx, aNumber.toString());
     return Send(cx, global, str, aMessage, aReturn);
   }
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -826,17 +826,18 @@ CreateJSContextForWorker(WorkerPrivate* 
 
 class WorkerJSRuntime : public mozilla::CycleCollectedJSRuntime
 {
 public:
   // The heap size passed here doesn't matter, we will change it later in the
   // call to JS_SetGCParameter inside CreateJSContextForWorker.
   WorkerJSRuntime(WorkerPrivate* aWorkerPrivate)
   : CycleCollectedJSRuntime(WORKER_DEFAULT_RUNTIME_HEAPSIZE,
-                            JS_NO_HELPER_THREADS),
+                            JS_NO_HELPER_THREADS,
+                            false),
     mWorkerPrivate(aWorkerPrivate)
   {
     // We need to ensure that a JSContext outlives the cycle collector, and
     // that the internal JSContext created by ctypes is not the last JSContext
     // to die.  So we create an unused JSContext here and destroy it after
     // the cycle collector shuts down.  Thus all cycles will be broken before
     // the last GC and all finalizers will be run.
     mLastJSContext = JS_NewContext(Runtime(), 0);
--- a/js/jsd/jsd_xpc.cpp
+++ b/js/jsd/jsd_xpc.cpp
@@ -25,17 +25,16 @@
 #include "jsdebug.h"
 #include "nsReadableUtils.h"
 #include "nsCRT.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/Attributes.h"
 
 /* XXX DOM dependency */
 #include "nsIScriptContext.h"
-#include "nsDOMJSUtils.h"
 #include "SandboxPrivate.h"
 #include "nsJSPrincipals.h"
 #include "nsContentUtils.h"
 #include "nsCxPusher.h"
 
 using mozilla::AutoSafeJSContext;
 using mozilla::AutoPushJSContext;
 
@@ -1692,17 +1691,17 @@ jsdContext::GetTag(uint32_t *_rval)
     *_rval = mTag;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 jsdContext::GetGlobalObject (jsdIValue **_rval)
 {
     ASSERT_VALID_EPHEMERAL;
-    JSObject *glob = GetDefaultScopeFromJSContext(mJSCx);
+    JSObject *glob = js::DefaultObjectForContextOrNull(mJSCx);
     JSDValue *jsdv = JSD_NewValue (mJSDCx, OBJECT_TO_JSVAL(glob));
     if (!jsdv)
         return NS_ERROR_FAILURE;
     *_rval = jsdValue::FromPtr (mJSDCx, jsdv);
     if (!*_rval)
         return NS_ERROR_FAILURE;
     return NS_OK;
 }
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -2394,25 +2394,16 @@ JS_DumpHeap(JSRuntime *rt, FILE *fp, voi
 #endif /* DEBUG */
 
 extern JS_PUBLIC_API(bool)
 JS_IsGCMarkingTracer(JSTracer *trc)
 {
     return IS_GC_MARKING_TRACER(trc);
 }
 
-#ifdef DEBUG
-extern JS_PUBLIC_API(bool)
-JS_IsMarkingGray(JSTracer *trc)
-{
-    JS_ASSERT(JS_IsGCMarkingTracer(trc));
-    return trc->callback == GCMarker::GrayCallback;
-}
-#endif
-
 JS_PUBLIC_API(void)
 JS_GC(JSRuntime *rt)
 {
     AssertHeapIsIdle(rt);
     JS::PrepareForFullGC(rt);
     GC(rt, GC_NORMAL, JS::gcreason::API);
 }
 
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1636,28 +1636,26 @@ JS_StringToVersion(const char *string);
                                                    uncaught exceptions from
                                                    being converted to error
                                                    reports */
 
 /* JS_BIT(9) is currently unused. */
 
 /* JS_BIT(10) is currently unused. */
 
-#define JSOPTION_NO_DEFAULT_COMPARTMENT_OBJECT JS_BIT(11)     /* This JSContext does not use a
-                                                                 default compartment object. Such
-                                                                 an object will not be set implicitly,
-                                                                 and attempts to get or set it will
-                                                                 assert. */
+/* JS_BIT(11) is currently unused. */
 
 #define JSOPTION_NO_SCRIPT_RVAL JS_BIT(12)      /* A promise to the compiler
                                                    that a null rval out-param
                                                    will be passed to each call
                                                    to JS_ExecuteScript. */
-
-/* JS_BIT(13) is currently unused. */
+#define JSOPTION_UNROOTED_GLOBAL JS_BIT(13)     /* The GC will not root the
+                                                   contexts' default compartment
+                                                   object, leaving that up to the
+                                                   embedding. */
 
 #define JSOPTION_BASELINE       JS_BIT(14)      /* Baseline compiler. */
 
 #define JSOPTION_TYPE_INFERENCE JS_BIT(16)      /* Perform type inference. */
 #define JSOPTION_STRICT_MODE    JS_BIT(17)      /* Provides a way to force
                                                    strict mode for all code
                                                    without requiring
                                                    "use strict" annotations. */
@@ -2322,22 +2320,16 @@ extern JS_PUBLIC_API(void)
 JS_SetGCCallback(JSRuntime *rt, JSGCCallback cb, void *data);
 
 extern JS_PUBLIC_API(void)
 JS_SetFinalizeCallback(JSRuntime *rt, JSFinalizeCallback cb);
 
 extern JS_PUBLIC_API(bool)
 JS_IsGCMarkingTracer(JSTracer *trc);
 
-/* For assertions only. */
-#ifdef DEBUG
-extern JS_PUBLIC_API(bool)
-JS_IsMarkingGray(JSTracer *trc);
-#endif
-
 /*
  * JS_IsAboutToBeFinalized checks if the given object is going to be finalized
  * at the end of the current GC. When called outside of the context of a GC,
  * this function will return false. Typically this function is used on weak
  * references, where the reference should be nulled out or destroyed if the
  * given object is about to be finalized.
  *
  * The argument to JS_IsAboutToBeFinalized is an in-out param: when the
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1274,17 +1274,17 @@ JSContext::sizeOfIncludingThis(mozilla::
 }
 
 void
 JSContext::mark(JSTracer *trc)
 {
     /* Stack frames and slots are traced by StackSpace::mark. */
 
     /* Mark other roots-by-definition in the JSContext. */
-    if (defaultCompartmentObject_)
+    if (defaultCompartmentObject_ && !hasOption(JSOPTION_UNROOTED_GLOBAL))
         MarkObjectRoot(trc, &defaultCompartmentObject_, "default compartment object");
     if (isExceptionPending())
         MarkValueRoot(trc, &exception, "exception");
 
     TraceCycleDetectionSet(trc, cycleDetectorSet);
 
     MarkValueRoot(trc, &iterValue, "iterValue");
 }
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -439,20 +439,17 @@ struct JSContext : public js::ExclusiveC
      * compartment will be set to the compartment of the "default compartment
      * object".
      */
   private:
     JSObject *defaultCompartmentObject_;
   public:
     inline void setDefaultCompartmentObject(JSObject *obj);
     inline void setDefaultCompartmentObjectIfUnset(JSObject *obj);
-    JSObject *maybeDefaultCompartmentObject() const {
-        JS_ASSERT(!hasOption(JSOPTION_NO_DEFAULT_COMPARTMENT_OBJECT));
-        return defaultCompartmentObject_;
-    }
+    JSObject *maybeDefaultCompartmentObject() const { return defaultCompartmentObject_; }
 
     /* Wrap cx->exception for the current compartment. */
     void wrapPendingException();
 
     /* State for object and array toSource conversion. */
     js::ObjectSet       cycleDetectorSet;
 
     /* Per-context optional error reporter. */
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -424,28 +424,24 @@ JSContext::setPendingException(js::Value
     this->throwing = true;
     this->exception = v;
     js::assertSameCompartment(this, v);
 }
 
 inline void
 JSContext::setDefaultCompartmentObject(JSObject *obj)
 {
-    JS_ASSERT(!hasOption(JSOPTION_NO_DEFAULT_COMPARTMENT_OBJECT));
     defaultCompartmentObject_ = obj;
 }
 
 inline void
 JSContext::setDefaultCompartmentObjectIfUnset(JSObject *obj)
 {
-    if (!hasOption(JSOPTION_NO_DEFAULT_COMPARTMENT_OBJECT) &&
-        !defaultCompartmentObject_)
-    {
+    if (!defaultCompartmentObject_)
         setDefaultCompartmentObject(obj);
-    }
 }
 
 inline void
 js::ExclusiveContext::enterCompartment(JSCompartment *c)
 {
     enterCompartmentDepth_++;
     c->enter();
     setCompartment(c);
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -764,16 +764,22 @@ js::GetContextStructuredCloneCallbacks(J
 #ifdef JS_THREADSAFE
 JS_FRIEND_API(bool)
 js::ContextHasOutstandingRequests(const JSContext *cx)
 {
     return cx->outstandingRequests > 0;
 }
 #endif
 
+JS_FRIEND_API(bool)
+js::HasUnrootedGlobal(const JSContext *cx)
+{
+    return cx->hasOption(JSOPTION_UNROOTED_GLOBAL);
+}
+
 JS_FRIEND_API(void)
 js::SetActivityCallback(JSRuntime *rt, ActivityCallback cb, void *arg)
 {
     rt->activityCallback = cb;
     rt->activityCallbackArg = arg;
 }
 
 JS_FRIEND_API(bool)
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -669,16 +669,19 @@ GetPCCountScriptSummary(JSContext *cx, s
 JS_FRIEND_API(JSString *)
 GetPCCountScriptContents(JSContext *cx, size_t script);
 
 #ifdef JS_THREADSAFE
 JS_FRIEND_API(bool)
 ContextHasOutstandingRequests(const JSContext *cx);
 #endif
 
+JS_FRIEND_API(bool)
+HasUnrootedGlobal(const JSContext *cx);
+
 typedef void
 (* ActivityCallback)(void *arg, bool active);
 
 /*
  * Sets a callback that is run whenever the runtime goes idle - the
  * last active request ceases - and begins activity - when it was
  * idle and a request begins.
  */
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -677,27 +677,22 @@ const JSFunctionSpec intrinsic_functions
 
     JS_FS_END
 };
 
 bool
 JSRuntime::initSelfHosting(JSContext *cx)
 {
     JS_ASSERT(!selfHostingGlobal_);
-
-    bool receivesDefaultObject = !cx->hasOption(JSOPTION_NO_DEFAULT_COMPARTMENT_OBJECT);
-    RootedObject savedGlobal(cx, receivesDefaultObject
-                                 ? js::DefaultObjectForContextOrNull(cx)
-                                 : NULL);
+    RootedObject savedGlobal(cx, js::DefaultObjectForContextOrNull(cx));
     if (!(selfHostingGlobal_ = JS_NewGlobalObject(cx, &self_hosting_global_class,
                                                   NULL, JS::DontFireOnNewGlobalHook)))
         return false;
     JSAutoCompartment ac(cx, selfHostingGlobal_);
-    if (receivesDefaultObject)
-        js::SetDefaultObjectForContext(cx, selfHostingGlobal_);
+    js::SetDefaultObjectForContext(cx, selfHostingGlobal_);
     Rooted<GlobalObject*> shg(cx, &selfHostingGlobal_->as<GlobalObject>());
     /*
      * During initialization of standard classes for the self-hosting global,
      * all self-hosted functions are ignored. Thus, we don't create cyclic
      * dependencies in the order of initialization.
      */
     if (!GlobalObject::initStandardClasses(cx, shg))
         return false;
@@ -756,18 +751,17 @@ JSRuntime::initSelfHosting(JSContext *cx
         }
 #else
         const char *src = rawSources;
 #endif
 
         ok = Evaluate(cx, shg, options, src, srcLen, &rv);
     }
     JS_SetErrorReporter(cx, oldReporter);
-    if (receivesDefaultObject)
-        js::SetDefaultObjectForContext(cx, savedGlobal);
+    js::SetDefaultObjectForContext(cx, savedGlobal);
     return ok;
 }
 
 void
 JSRuntime::finishSelfHosting()
 {
     selfHostingGlobal_ = NULL;
 
--- a/js/xpconnect/idl/nsIXPConnect.idl
+++ b/js/xpconnect/idl/nsIXPConnect.idl
@@ -42,32 +42,39 @@ class nsWrapperCache;
 [ptr] native JSFreeOpPtr(JSFreeOp);
 [ptr] native JSObjectPtr(JSObject);
 [ptr] native JSValPtr(JS::Value);
 [ptr] native JSValConstPtr(const JS::Value);
       native JSPropertyOp(JSPropertyOp);
       native JSEqualityOp(JSEqualityOp);
 [ptr] native JSScriptPtr(JSScript);
 [ptr] native voidPtrPtr(void*);
+[ptr] native nsScriptObjectTracerPtr(nsScriptObjectTracer);
+[ref] native nsCCTraversalCallbackRef(nsCycleCollectionTraversalCallback);
 [ptr] native nsAXPCNativeCallContextPtr(nsAXPCNativeCallContext);
 [ptr] native nsWrapperCachePtr(nsWrapperCache);
 [ref] native JSCompartmentOptions(JS::CompartmentOptions);
 [ref] native JSCallArgsRef(const JS::CallArgs);
       native JSHandleId(JS::Handle<jsid>);
 
 /***************************************************************************/
 
 // forward declarations...
 interface nsIXPCScriptable;
 interface nsIXPConnect;
 interface nsIXPConnectWrappedNative;
 interface nsIInterfaceInfo;
 interface nsIXPCSecurityManager;
 interface nsIPrincipal;
 
+%{C++
+class nsCycleCollectionTraversalCallback;
+class nsScriptObjectTracer;
+%}
+
 /***************************************************************************/
 [uuid(909e8641-7c54-4dff-9b94-ba631f057b33)]
 interface nsIXPConnectJSObjectHolder : nsISupports
 {
     [notxpcom, nostdcall] JSObjectPtr GetJSObject();
 };
 
 [uuid(2d08015d-7556-4f12-9e89-4c756d129310)]
@@ -286,17 +293,17 @@ interface nsIXPCFunctionThisTranslator :
 %{ C++
 // For use with the service manager
 // {CB6593E0-F9B2-11d2-BDD6-000064657374}
 #define NS_XPCONNECT_CID \
 { 0xcb6593e0, 0xf9b2, 0x11d2, \
     { 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }
 %}
 
-[uuid(c4d0187c-6a78-4bdf-9cd9-d218644b715a)]
+[uuid(0ebc00f0-f3ad-11e2-b778-0800200c9a66)]
 interface nsIXPConnect : nsISupports
 {
 %{ C++
   NS_DEFINE_STATIC_CID_ACCESSOR(NS_XPCONNECT_CID)
 %}
 
     /**
      * Initializes classes on a global object that has already been created.
@@ -555,16 +562,24 @@ interface nsIXPConnect : nsISupports
      *         to this method.
      */
     [noscript] jsval evalInSandboxObject(in AString source, in string filename,
                                          in JSContextPtr cx,
                                          in JSObjectPtr sandbox,
                                          in boolean returnStringOnly);
 
     /**
+     * Note aJSContext as a child to the cycle collector.
+     * @param aJSContext The JSContext to note.
+     * @param aCb The cycle collection traversal callback.
+     */
+    [noscript,notxpcom] void noteJSContext(in JSContextPtr aJSContext,
+                                           in nsCCTraversalCallbackRef aCb);
+
+    /**
      * Whether or not XPConnect should report all JS exceptions when returning
      * from JS into C++. False by default, although any value set in the
      * MOZ_REPORT_ALL_JS_EXCEPTIONS environment variable will override the value
      * passed here.
      */
     void setReportAllJSExceptions(in boolean reportAllJSExceptions);
 
     /**
--- a/js/xpconnect/src/XPCJSContextStack.cpp
+++ b/js/xpconnect/src/XPCJSContextStack.cpp
@@ -65,24 +65,20 @@ XPCJSContextStack::Push(JSContext *cx)
 
     XPCJSContextInfo &e = mStack[mStack.Length() - 1];
     if (e.cx) {
         // The cx we're pushing is also stack-top. In general we still need to
         // call JS_SaveFrameChain here. But if that would put us in a
         // compartment that's same-origin with the current one, we can skip it.
         nsIScriptSecurityManager* ssm = XPCWrapper::GetSecurityManager();
         if ((e.cx == cx) && ssm) {
-            // DOM JSContexts don't store their default compartment object on
-            // the cx, so in those cases we need to fetch it via the scx
-            // instead.
-            RootedObject defaultScope(cx, GetDefaultScopeFromJSContext(cx));
-
+            RootedObject defaultGlobal(cx, js::DefaultObjectForContextOrNull(cx));
             nsIPrincipal *currentPrincipal =
               GetCompartmentPrincipal(js::GetContextCompartment(cx));
-            nsIPrincipal *defaultPrincipal = GetObjectPrincipal(defaultScope);
+            nsIPrincipal *defaultPrincipal = GetObjectPrincipal(defaultGlobal);
             bool equal = false;
             currentPrincipal->Equals(defaultPrincipal, &equal);
             if (equal) {
                 mStack.AppendElement(cx);
                 return true;
             }
         }
 
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -2855,17 +2855,17 @@ SourceHook(JSContext *cx, JS::Handle<JSS
     xpc::Throw(cx, rv);
     return false;
   }
 
   return true;
 }
 
 XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
-   : CycleCollectedJSRuntime(32L * 1024L * 1024L, JS_USE_HELPER_THREADS),
+   : CycleCollectedJSRuntime(32L * 1024L * 1024L, JS_USE_HELPER_THREADS, true),
    mJSContextStack(new XPCJSContextStack()),
    mCallContext(nullptr),
    mAutoRoots(nullptr),
    mResolveName(JSID_VOID),
    mResolvingWrapper(nullptr),
    mWrappedJSMap(JSObject2WrappedJSMap::newMap(XPC_JS_MAP_SIZE)),
    mWrappedJSClassMap(IID2WrappedJSClassMap::newMap(XPC_JS_CLASS_MAP_SIZE)),
    mIID2NativeInterfaceMap(IID2NativeInterfaceMap::newMap(XPC_NATIVE_INTERFACE_MAP_SIZE)),
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -1147,17 +1147,17 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWra
     // convert natives to JSObjects, but we do NOT plan to pass those JSObjects
     // to our real callee.
     JSContext *context = GetContextFromObjectOrDefault(wrapper);
     XPCCallContext ccx(NATIVE_CALLER, context);
     if (!ccx.IsValid())
         return retval;
 
     XPCContext *xpcc = ccx.GetXPCContext();
-    JSContext *cx = ccx.GetJSContext();
+    JSContext *cx = xpc_UnmarkGrayContext(ccx.GetJSContext());
 
     if (!cx || !xpcc || !IsReflectable(methodIndex))
         return NS_ERROR_FAILURE;
 
     // [implicit_jscontext] and [optional_argc] have a different calling
     // convention, which we don't support for JS-implemented components.
     if (info->WantsOptArgc() || info->WantsContext()) {
         const char *str = "IDL methods marked with [implicit_jscontext] "
--- a/js/xpconnect/src/nsCxPusher.cpp
+++ b/js/xpconnect/src/nsCxPusher.cpp
@@ -119,24 +119,24 @@ AutoCxPusher::AutoCxPusher(JSContext* cx
 
 #ifdef DEBUG
   mPushedContext = cx;
   mCompartmentDepthOnEntry = cx ? js::GetEnterCompartmentDepth(cx) : 0;
 #endif
 
   // Enter a request and a compartment for the duration that the cx is on the
   // stack if non-null.
+  //
+  // NB: We call UnmarkGrayContext so that this can obsolete the need for the
+  // old XPCAutoRequest as well.
   if (cx) {
     mAutoRequest.construct(cx);
-
-    // DOM JSContexts don't store their default compartment object on the cx.
-    JSObject *compartmentObject = mScx ? mScx->GetWindowProxy()
-                                       : js::DefaultObjectForContextOrNull(cx);
-    if (compartmentObject)
-      mAutoCompartment.construct(cx, compartmentObject);
+    if (js::DefaultObjectForContextOrNull(cx))
+      mAutoCompartment.construct(cx, js::DefaultObjectForContextOrNull(cx));
+    xpc_UnmarkGrayContext(cx);
   }
 }
 
 NS_EXPORT
 AutoCxPusher::~AutoCxPusher()
 {
   // GC when we pop a script entry point. This is a useful heuristic that helps
   // us out on certain (flawed) benchmarks like sunspider, because it lets us
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -337,16 +337,24 @@ xpc_TryUnmarkWrappedGrayObject(nsISuppor
 {
     nsCOMPtr<nsIXPConnectWrappedJS> wjs = do_QueryInterface(aWrappedJS);
     if (wjs) {
         // Unmarks gray JSObject.
         static_cast<nsXPCWrappedJS*>(wjs.get())->GetJSObject();
     }
 }
 
+NS_IMETHODIMP_(void)
+nsXPConnect::NoteJSContext(JSContext *aJSContext,
+                           nsCycleCollectionTraversalCallback &aCb)
+{
+    aCb.NoteNativeChild(aJSContext, mozilla::CycleCollectedJSRuntime::JSContextParticipant());
+}
+
+
 /***************************************************************************/
 /***************************************************************************/
 // nsIXPConnect interface methods...
 
 inline nsresult UnexpectedFailure(nsresult rv)
 {
     NS_ERROR("This is not supposed to fail!");
     return rv;
@@ -1310,17 +1318,18 @@ xpc_ActivateDebugMode()
     nsXPConnect::XPConnect()->SetDebugModeWhenPossible(true, true);
     nsXPConnect::CheckForDebugMode(rt->Runtime());
 }
 
 /* virtual */
 JSContext*
 nsXPConnect::GetCurrentJSContext()
 {
-    return GetRuntime()->GetJSContextStack()->Peek();
+    JSContext *cx = GetRuntime()->GetJSContextStack()->Peek();
+    return xpc_UnmarkGrayContext(cx);
 }
 
 /* virtual */
 JSContext*
 nsXPConnect::GetSafeJSContext()
 {
     return GetRuntime()->GetJSContextStack()->GetSafeJSContext();
 }
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -157,16 +157,31 @@ inline JSScript *
 xpc_UnmarkGrayScript(JSScript *script)
 {
     if (script)
         JS::ExposeGCThingToActiveJS(script, JSTRACE_SCRIPT);
 
     return script;
 }
 
+inline JSContext *
+xpc_UnmarkGrayContext(JSContext *cx)
+{
+    if (cx) {
+        JSObject *global = js::DefaultObjectForContextOrNull(cx);
+        xpc_UnmarkGrayObject(global);
+        if (global && JS_IsInRequest(JS_GetRuntime(cx))) {
+            JSObject *scope = JS::CurrentGlobalOrNull(cx);
+            if (scope != global)
+                xpc_UnmarkGrayObject(scope);
+        }
+    }
+    return cx;
+}
+
 // If aVariant is an XPCVariant, this marks the object to be in aGeneration.
 // This also unmarks the gray JSObject.
 extern void
 xpc_MarkInCCGeneration(nsISupports* aVariant, uint32_t aGeneration);
 
 // If aWrappedJS is a JS wrapper, unmark its JSObject.
 extern void
 xpc_TryUnmarkWrappedGrayObject(nsISupports* aWrappedJS);
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -273,16 +273,57 @@ private:
         tracer->mAnyMarked = true;
       }
     }
   }
 
   bool mAnyMarked;
 };
 
+class JSContextParticipant : public nsCycleCollectionParticipant
+{
+public:
+  NS_IMETHOD Root(void *n)
+  {
+    return NS_OK;
+  }
+  NS_IMETHOD Unlink(void *n)
+  {
+    return NS_OK;
+  }
+  NS_IMETHOD Unroot(void *n)
+  {
+    return NS_OK;
+  }
+  NS_IMETHOD_(void) DeleteCycleCollectable(void *n)
+  {
+  }
+  NS_IMETHOD Traverse(void *n, nsCycleCollectionTraversalCallback &cb)
+  {
+    JSContext *cx = static_cast<JSContext*>(n);
+
+    // JSContexts do not have an internal refcount and always have a single
+    // owner (e.g., nsJSContext). Thus, the default refcount is 1. However,
+    // in the (abnormal) case of synchronous cycle-collection, the context
+    // may be actively executing code in which case we want to treat it as
+    // rooted by adding an extra refcount.
+    unsigned refCount = js::ContextHasOutstandingRequests(cx) ? 2 : 1;
+
+    cb.DescribeRefCountedNode(refCount, "JSContext");
+    if (JSObject *global = js::DefaultObjectForContextOrNull(cx)) {
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "[global object]");
+      cb.NoteJSChild(global);
+    }
+
+    return NS_OK;
+  }
+};
+
+static JSContextParticipant JSContext_cycleCollectorGlobal;
+
 struct Closure
 {
   bool cycleCollectionEnabled;
   nsCycleCollectionNoteRootCallback *cb;
 };
 
 static void
 CheckParticipatesInCycleCollection(void *aThing, const char *name, void *aClosure)
@@ -429,20 +470,22 @@ NoteJSChildGrayWrapperShim(void* aData, 
  * cycle.)
  */
 
 // NB: This is only used to initialize the participant in
 // CycleCollectedJSRuntime. It should never be used directly.
 static const JSZoneParticipant sJSZoneCycleCollectorGlobal;
 
 CycleCollectedJSRuntime::CycleCollectedJSRuntime(uint32_t aMaxbytes,
-                                                 JSUseHelperThreads aUseHelperThreads)
+                                                 JSUseHelperThreads aUseHelperThreads,
+                                                 bool aExpectUnrootedGlobals)
   : mGCThingCycleCollectorGlobal(sGCThingCycleCollectorGlobal),
     mJSZoneCycleCollectorGlobal(sJSZoneCycleCollectorGlobal),
-    mJSRuntime(nullptr)
+    mJSRuntime(nullptr),
+    mExpectUnrootedGlobals(aExpectUnrootedGlobals)
 #ifdef DEBUG
   , mObjectToUnlink(nullptr)
 #endif
 {
   mJSRuntime = JS_NewRuntime(aMaxbytes, aUseHelperThreads);
   if (!mJSRuntime) {
     MOZ_CRASH();
   }
@@ -493,16 +536,33 @@ UnmarkJSHolder(void* holder, nsScriptObj
 
 void
 CycleCollectedJSRuntime::UnmarkSkippableJSHolders()
 {
   mJSHolders.Enumerate(UnmarkJSHolder, nullptr);
 }
 
 void
+CycleCollectedJSRuntime::MaybeTraceGlobals(JSTracer* aTracer) const
+{
+  JSContext* iter = nullptr;
+  while (JSContext* acx = JS_ContextIterator(Runtime(), &iter)) {
+    MOZ_ASSERT(js::HasUnrootedGlobal(acx) == mExpectUnrootedGlobals);
+    if (!js::HasUnrootedGlobal(acx)) {
+      continue;
+    }
+
+    if (JSObject* global = js::DefaultObjectForContextOrNull(acx)) {
+      JS::AssertGCThingMustBeTenured(global);
+      JS_CallObjectTracer(aTracer, &global, "Global Object");
+    }
+  }
+}
+
+void
 CycleCollectedJSRuntime::DescribeGCThing(bool aIsMarked, void* aThing,
                                          JSGCTraceKind aTraceKind,
                                          nsCycleCollectionTraversalCallback& aCb) const
 {
   if (!aCb.WantDebugInfo()) {
     aCb.DescribeGCedNode(aIsMarked, "JS Object");
     return;
   }
@@ -669,19 +729,42 @@ CycleCollectedJSRuntime::TraverseObjectS
   TraverseObjectShimClosure* closure =
       static_cast<TraverseObjectShimClosure*>(aData);
 
   MOZ_ASSERT(js::GCThingTraceKind(aThing) == JSTRACE_OBJECT);
   closure->self->TraverseGCThing(CycleCollectedJSRuntime::TRAVERSE_CPP, aThing,
                                  JSTRACE_OBJECT, closure->cb);
 }
 
+// For all JS objects that are held by native objects but aren't held
+// through rooting or locking, we need to add all the native objects that
+// hold them so that the JS objects are colored correctly in the cycle
+// collector. This includes JSContexts that don't have outstanding requests,
+// because their global object wasn't marked by the JS GC. All other JS
+// roots were marked by the JS GC and will be colored correctly in the cycle
+// collector.
+void
+CycleCollectedJSRuntime::MaybeTraverseGlobals(nsCycleCollectionNoteRootCallback& aCb) const
+{
+  JSContext *iter = nullptr, *acx;
+  while ((acx = JS_ContextIterator(Runtime(), &iter))) {
+    // Add the context to the CC graph only if traversing it would
+    // end up doing something.
+    JSObject* global = js::DefaultObjectForContextOrNull(acx);
+    if (global && xpc_IsGrayGCThing(global)) {
+      aCb.NoteNativeRoot(acx, JSContextParticipant());
+    }
+  }
+}
+
 void
 CycleCollectedJSRuntime::TraverseNativeRoots(nsCycleCollectionNoteRootCallback& aCb)
 {
+  MaybeTraverseGlobals(aCb);
+
   // NB: This is here just to preserve the existing XPConnect order. I doubt it
   // would hurt to do this after the JS holders.
   TraverseAdditionalNativeRoots(aCb);
 
   Closure closure = { true, &aCb };
   mJSHolders.Enumerate(NoteJSHolder, &closure);
 }
 
@@ -751,16 +834,18 @@ TraceJSHolder(void* aHolder, nsScriptObj
   aTracer->Trace(aHolder, JsGcTracer(), aArg);
 
   return PL_DHASH_NEXT;
 }
 
 void
 CycleCollectedJSRuntime::TraceNativeGrayRoots(JSTracer* aTracer)
 {
+  MaybeTraceGlobals(aTracer);
+
   // NB: This is here just to preserve the existing XPConnect order. I doubt it
   // would hurt to do this after the JS holders.
   TraceAdditionalNativeGrayRoots(aTracer);
 
   mJSHolders.Enumerate(TraceJSHolder, aTracer);
 }
 
 void
@@ -826,16 +911,23 @@ CycleCollectedJSRuntime::AssertNoObjects
 {
   nsScriptObjectTracer* tracer = mJSHolders.Get(aPossibleJSHolder);
   if (tracer) {
     tracer->Trace(aPossibleJSHolder, TraceCallbackFunc(AssertNoGcThing), nullptr);
   }
 }
 #endif
 
+// static
+nsCycleCollectionParticipant*
+CycleCollectedJSRuntime::JSContextParticipant()
+{
+  return &JSContext_cycleCollectorGlobal;
+}
+
 nsCycleCollectionParticipant*
 CycleCollectedJSRuntime::GCThingParticipant()
 {
     return &mGCThingCycleCollectorGlobal;
 }
 
 nsCycleCollectionParticipant*
 CycleCollectedJSRuntime::ZoneParticipant()
@@ -875,28 +967,29 @@ CycleCollectedJSRuntime::UsefulToMergeZo
   if (!NS_IsMainThread()) {
     return false;
   }
 
   JSContext* iter = nullptr;
   JSContext* cx;
   JSAutoRequest ar(nsContentUtils::GetSafeJSContext());
   while ((cx = JS_ContextIterator(mJSRuntime, &iter))) {
-    // Skip anything without an nsIScriptContext.
+    // Skip anything without an nsIScriptContext, as well as any scx whose
+    // NativeGlobal() is not an outer window (this happens with XUL Prototype
+    // compilation scopes, for example, which we're not interested in).
     nsIScriptContext* scx = GetScriptContextFromJSContext(cx);
-    JS::RootedObject obj(cx, scx ? scx->GetWindowProxy() : nullptr);
-    if (!obj) {
+    JS::RootedObject global(cx, scx ? scx->GetNativeGlobal() : nullptr);
+    if (!global || !js::GetObjectParent(global)) {
       continue;
     }
-    MOZ_ASSERT(js::IsOuterObject(obj));
     // Grab the inner from the outer.
-    obj = JS_ObjectToInnerObject(cx, obj);
-    MOZ_ASSERT(!js::GetObjectParent(obj));
-    if (JS::GCThingIsMarkedGray(obj) &&
-        !js::IsSystemCompartment(js::GetObjectCompartment(obj))) {
+    global = JS_ObjectToInnerObject(cx, global);
+    MOZ_ASSERT(!js::GetObjectParent(global));
+    if (JS::GCThingIsMarkedGray(global) &&
+        !js::IsSystemCompartment(js::GetObjectCompartment(global))) {
       return true;
     }
   }
   return false;
 }
 
 void
 CycleCollectedJSRuntime::FixWeakMappingGrayBits() const
@@ -1089,17 +1182,31 @@ CycleCollectedJSRuntime::FinalizeDeferre
   }
 }
 
 void
 CycleCollectedJSRuntime::OnGC(JSGCStatus aStatus)
 {
   switch (aStatus) {
     case JSGC_BEGIN:
+    {
+      // XXXkhuey do we still need this?
+      // We seem to sometime lose the unrooted global flag. Restore it
+      // here. FIXME: bug 584495.
+      if (mExpectUnrootedGlobals){
+        JSContext* iter = nullptr;
+        while (JSContext* acx = JS_ContextIterator(Runtime(), &iter)) {
+          if (!js::HasUnrootedGlobal(acx)) {
+            JS_ToggleOptions(acx, JSOPTION_UNROOTED_GLOBAL);
+          }
+        }
+      }
+
       break;
+    }
     case JSGC_END:
     {
       /*
        * If the previous GC created a runnable to finalize objects
        * incrementally, and if it hasn't finished yet, finish it now. We
        * don't want these to build up. We also don't want to allow any
        * existing incremental finalize runnables to run after a
        * non-incremental GC, since they are often used to detect leaks.
@@ -1118,10 +1225,16 @@ CycleCollectedJSRuntime::OnGC(JSGCStatus
   }
 
   CustomGCCallback(aStatus);
 }
 
 bool
 CycleCollectedJSRuntime::OnContext(JSContext* aCx, unsigned aOperation)
 {
+  if (mExpectUnrootedGlobals && aOperation == JSCONTEXT_NEW) {
+    // XXXkhuey bholley is going to make this go away, but for now XPConnect
+    // needs it.
+    JS_ToggleOptions(aCx, JSOPTION_UNROOTED_GLOBAL);
+  }
+
   return CustomContextCallback(aCx, aOperation);
 }
--- a/xpcom/base/CycleCollectedJSRuntime.h
+++ b/xpcom/base/CycleCollectedJSRuntime.h
@@ -78,17 +78,18 @@ class IncrementalFinalizeRunnable;
 
 class CycleCollectedJSRuntime
 {
   friend class JSGCThingParticipant;
   friend class JSZoneParticipant;
   friend class IncrementalFinalizeRunnable;
 protected:
   CycleCollectedJSRuntime(uint32_t aMaxbytes,
-                          JSUseHelperThreads aUseHelperThreads);
+                          JSUseHelperThreads aUseHelperThreads,
+                          bool aExpectUnrootedGlobals);
   virtual ~CycleCollectedJSRuntime();
 
   JSRuntime* Runtime() const
   {
     MOZ_ASSERT(mJSRuntime);
     return mJSRuntime;
   }
 
@@ -143,18 +144,23 @@ private:
                   nsCycleCollectionTraversalCallback& aCb);
 
   void
   TraverseZone(JS::Zone* aZone, nsCycleCollectionTraversalCallback& aCb);
 
   static void
   TraverseObjectShim(void* aData, void* aThing);
 
+  void MaybeTraverseGlobals(nsCycleCollectionNoteRootCallback& aCb) const;
+
   void TraverseNativeRoots(nsCycleCollectionNoteRootCallback& aCb);
 
+  void MaybeTraceGlobals(JSTracer* aTracer) const;
+
+
   static void TraceBlackJS(JSTracer* aTracer, void* aData);
   static void TraceGrayJS(JSTracer* aTracer, void* aData);
   static void GCCallback(JSRuntime* aRuntime, JSGCStatus aStatus, void* aData);
   static bool ContextCallback(JSContext* aCx, unsigned aOperation,
                               void* aData);
 
   virtual void TraceNativeBlackRoots(JSTracer* aTracer) { };
   void TraceNativeGrayRoots(JSTracer* aTracer);
@@ -173,16 +179,19 @@ public:
   void AddJSHolder(void* aHolder, nsScriptObjectTracer* aTracer);
   void RemoveJSHolder(void* aHolder);
 #ifdef DEBUG
   bool IsJSHolder(void* aHolder);
   void SetObjectToUnlink(void* aObject) { mObjectToUnlink = aObject; }
   void AssertNoObjectsToTrace(void* aPossibleJSHolder);
 #endif
 
+  // This returns the singleton nsCycleCollectionParticipant for JSContexts.
+  static nsCycleCollectionParticipant* JSContextParticipant();
+
   nsCycleCollectionParticipant* GCThingParticipant();
   nsCycleCollectionParticipant* ZoneParticipant();
 
   nsresult BeginCycleCollection(nsCycleCollectionNoteRootCallback &aCb);
   bool UsefulToMergeZones() const;
   void FixWeakMappingGrayBits() const;
   bool NeedCollect() const;
   void Collect(uint32_t reason) const;
@@ -210,16 +219,18 @@ private:
 
   nsTArray<nsISupports*> mDeferredSupports;
   typedef nsDataHashtable<nsFuncPtrHashKey<DeferredFinalizeFunction>, void*>
     DeferredFinalizerTable;
   DeferredFinalizerTable mDeferredFinalizerTable;
 
   nsRefPtr<IncrementalFinalizeRunnable> mFinalizeRunnable;
 
+  bool mExpectUnrootedGlobals;
+
 #ifdef DEBUG
   void* mObjectToUnlink;
 #endif
 };
 
 } // namespace mozilla
 
 #endif // mozilla_CycleCollectedJSRuntime_h__