Bug 820170 - JunkScope. r=bholley
authorGabor Krizsanits <gkrizsanits@mozilla.com>
Thu, 04 Apr 2013 11:27:43 +0200
changeset 127635 36fcd3edc6b832c818bbf8e504b4c02ecb0266ca
parent 127634 788e34b8872e21e19909570dfceeeda37bab9445
child 127636 372ae5eae8b9041cf58783980ac91ad6fdbdbb91
push id24509
push userryanvm@gmail.com
push dateFri, 05 Apr 2013 00:57:47 +0000
treeherdermozilla-central@55f9e3e3dae7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs820170
milestone23.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 820170 - JunkScope. r=bholley
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/src/xpcpublic.h
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -291,16 +291,24 @@ EnableUniversalXPConnect(JSContext *cx)
     // tests.
     XPCWrappedNativeScope *scope = priv->scope;
     if (!scope)
         return true;
     XPCCallContext ccx(NATIVE_CALLER, cx);
     return nsXPCComponents::AttachComponentsObject(ccx, scope);
 }
 
+JSObject *
+GetJunkScope()
+{
+    XPCJSRuntime *self = nsXPConnect::GetRuntimeInstance();
+    NS_ENSURE_TRUE(self, nullptr);
+    return self->GetJunkScope();
+}
+
 }
 
 static void
 CompartmentDestroyedCallback(JSFreeOp *fop, JSCompartment *compartment)
 {
     XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
     if (!self)
         return;
@@ -2646,17 +2654,18 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* 
    mVariantRoots(nullptr),
    mWrappedJSRoots(nullptr),
    mObjectHolderRoots(nullptr),
    mWatchdogLock(nullptr),
    mWatchdogWakeup(nullptr),
    mWatchdogThread(nullptr),
    mWatchdogHibernating(false),
    mLastActiveTime(-1),
-   mExceptionManagerNotAvailable(false)
+   mExceptionManagerNotAvailable(false),
+   mJunkScope(nullptr)
 #ifdef DEBUG
    , mObjectToUnlink(nullptr)
 #endif
 {
 #ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN
     DEBUG_WrappedNativeHashtable =
         JS_NewDHashTable(JS_DHashGetStubOps(), nullptr,
                          sizeof(JSDHashEntryStub), 128);
@@ -2995,8 +3004,41 @@ void
 XPCJSRuntime::RemoveGCCallback(JSGCCallback cb)
 {
     NS_ASSERTION(cb, "null callback");
     bool found = extraGCCallbacks.RemoveElement(cb);
     if (!found) {
         NS_ERROR("Removing a callback which was never added.");
     }
 }
+
+JSObject *
+XPCJSRuntime::GetJunkScope()
+{
+    if (!mJunkScope) {
+        JS::Value v;
+        SafeAutoJSContext cx;
+        SandboxOptions options;
+        options.sandboxName.AssignASCII("XPConnect Junk Compartment");
+        JSAutoRequest ac(cx);
+        nsresult rv = xpc_CreateSandboxObject(cx, &v,
+                                              nsContentUtils::GetSystemPrincipal(),
+                                              options);
+
+        NS_ENSURE_SUCCESS(rv, nullptr);
+
+        mJunkScope = js::UnwrapObject(&v.toObject());
+        JS_AddNamedObjectRoot(cx, &mJunkScope, "XPConnect Junk Compartment");
+    }
+    return mJunkScope;
+}
+
+void
+XPCJSRuntime::DeleteJunkScope()
+{
+    if(!mJunkScope)
+        return;
+
+    JSContext *cx = mJSContextStack->GetSafeJSContext();
+    JSAutoRequest ac(cx);
+    JS_RemoveObjectRoot(cx, &mJunkScope);
+    mJunkScope = nullptr;
+}
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -87,16 +87,17 @@ nsXPConnect::nsXPConnect()
 
     char* reportableEnv = PR_GetEnv("MOZ_REPORT_ALL_JS_EXCEPTIONS");
     if (reportableEnv && *reportableEnv)
         gReportAllJSExceptions = 1;
 }
 
 nsXPConnect::~nsXPConnect()
 {
+    mRuntime->DeleteJunkScope();
     nsCycleCollector_forgetJSRuntime();
 
     JSContext *cx = nullptr;
     if (mRuntime) {
         // Create our own JSContext rather than an XPCCallContext, since
         // otherwise we will create a new safe JS context and attach a
         // components object that won't get GCed.
         cx = JS_NewContext(mRuntime->GetJSRuntime(), 8192);
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -904,16 +904,18 @@ public:
     bool XBLScopesEnabled() {
         return gXBLScopesEnabled;
     }
 
     size_t SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf);
 
     AutoMarkingPtr**  GetAutoRootsAdr() {return &mAutoRoots;}
 
+    JSObject* GetJunkScope();
+    void DeleteJunkScope();
 private:
     XPCJSRuntime(); // no implementation
     XPCJSRuntime(nsXPConnect* aXPConnect);
 
     // The caller must be holding the GC lock
     void RescheduleWatchdog(XPCContext* ccx);
 
     static void WatchdogMain(void *arg);
@@ -954,16 +956,17 @@ private:
     PRLock *mWatchdogLock;
     PRCondVar *mWatchdogWakeup;
     PRThread *mWatchdogThread;
     nsTArray<JSGCCallback> extraGCCallbacks;
     bool mWatchdogHibernating;
     PRTime mLastActiveTime; // -1 if active NOW
     nsRefPtr<XPCIncrementalReleaseRunnable> mReleaseRunnable;
     JS::GCSliceCallback mPrevGCSliceCallback;
+    JSObject* mJunkScope;
 
     nsCOMPtr<nsIException>   mPendingException;
     nsCOMPtr<nsIExceptionManager> mExceptionManager;
     bool mExceptionManagerNotAvailable;
 
 #define XPCCCX_STRING_CACHE_SIZE 2
 
     // String wrapper entry, holds a string, and a boolean that tells
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -402,16 +402,30 @@ ReportJSRuntimeExplicitTreeStats(const J
 bool
 Throw(JSContext *cx, nsresult rv);
 
 /**
  * Every global should hold a native that implements the nsIGlobalObject interface.
  */
 nsIGlobalObject *
 GetNativeForGlobal(JSObject *global);
+
+/**
+ * In some cases a native object does not really belong to any compartment (XBL,
+ * document created from by XHR of a worker, etc.). But when for some reason we
+ * have to wrap these natives (because of an event for example) instead of just
+ * wrapping them into some random compartment we find on the context stack (like
+ * we did previously) a default compartment is used. This function returns that
+ * compartment's global. It is a singleton on the runtime.
+ * If you find yourself wanting to use this compartment, you're probably doing
+ * something wrong. Callers MUST consult with the XPConnect module owner before
+ * using this compartment. If you don't, bholley will hunt you down.
+ */
+JSObject *
+GetJunkScope();
 } // namespace xpc
 
 nsCycleCollectionParticipant *
 xpc_JSZoneParticipant();
 
 namespace mozilla {
 namespace dom {