Bug 989528 - Introduce a mechanism to explicitly enter a null compartment. r=luke
authorBobby Holley <bobbyholley@gmail.com>
Mon, 14 Apr 2014 20:26:59 -0700
changeset 196937 b79772297b2e4465643ffc7bc8d9f06c9ed9d45b
parent 196936 81ce5041d5d944ca9c0464cd8703d2e80df64476
child 196938 3c079cc52af9b789e3ef1bf71dbea670d1c3a2cf
push idunknown
push userunknown
push dateunknown
reviewersluke
bugs989528
milestone31.0a1
Bug 989528 - Introduce a mechanism to explicitly enter a null compartment. r=luke
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jscntxt.h
js/src/jscntxtinlines.h
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -979,16 +979,29 @@ JSAutoCompartment::JSAutoCompartment(JSC
     cx_->enterCompartment(target->compartment());
 }
 
 JSAutoCompartment::~JSAutoCompartment()
 {
     cx_->leaveCompartment(oldCompartment_);
 }
 
+JSAutoNullCompartment::JSAutoNullCompartment(JSContext *cx)
+  : cx_(cx),
+    oldCompartment_(cx->compartment())
+{
+    AssertHeapIsIdleOrIterating(cx_);
+    cx_->enterNullCompartment();
+}
+
+JSAutoNullCompartment::~JSAutoNullCompartment()
+{
+    cx_->leaveCompartment(oldCompartment_);
+}
+
 JS_PUBLIC_API(void)
 JS_SetCompartmentPrivate(JSCompartment *compartment, void *data)
 {
     compartment->data = data;
 }
 
 JS_PUBLIC_API(void *)
 JS_GetCompartmentPrivate(JSCompartment *compartment)
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1672,16 +1672,25 @@ class JS_PUBLIC_API(JSAutoCompartment)
     JSContext *cx_;
     JSCompartment *oldCompartment_;
   public:
     JSAutoCompartment(JSContext *cx, JSObject *target);
     JSAutoCompartment(JSContext *cx, JSScript *target);
     ~JSAutoCompartment();
 };
 
+class JS_PUBLIC_API(JSAutoNullCompartment)
+{
+    JSContext *cx_;
+    JSCompartment *oldCompartment_;
+  public:
+    JSAutoNullCompartment(JSContext *cx);
+    ~JSAutoNullCompartment();
+};
+
 /* NB: This API is infallible; a nullptr return value does not indicate error. */
 extern JS_PUBLIC_API(JSCompartment *)
 JS_EnterCompartment(JSContext *cx, JSObject *target);
 
 extern JS_PUBLIC_API(void)
 JS_LeaveCompartment(JSContext *cx, JSCompartment *oldCompartment);
 
 typedef void (*JSIterateCompartmentCallback)(JSRuntime *rt, void *data, JSCompartment *compartment);
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -345,16 +345,17 @@ class ExclusiveContext : public ThreadSa
     }
 #ifdef DEBUG
     unsigned getEnterCompartmentDepth() const {
         return enterCompartmentDepth_;
     }
 #endif
 
     inline void enterCompartment(JSCompartment *c);
+    inline void enterNullCompartment();
     inline void leaveCompartment(JSCompartment *oldCompartment);
 
     void setWorkerThread(WorkerThread *workerThread);
     WorkerThread *workerThread() const { return workerThread_; }
 
     // Threads with an ExclusiveContext may freely access any data in their
     // compartment and zone.
     JSCompartment *compartment() const {
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -403,26 +403,34 @@ inline void
 js::ExclusiveContext::enterCompartment(JSCompartment *c)
 {
     enterCompartmentDepth_++;
     c->enter();
     setCompartment(c);
 }
 
 inline void
+js::ExclusiveContext::enterNullCompartment()
+{
+    enterCompartmentDepth_++;
+    setCompartment(nullptr);
+}
+
+inline void
 js::ExclusiveContext::leaveCompartment(JSCompartment *oldCompartment)
 {
     JS_ASSERT(hasEnteredCompartment());
     enterCompartmentDepth_--;
 
     // Only call leave() after we've setCompartment()-ed away from the current
     // compartment.
     JSCompartment *startingCompartment = compartment_;
     setCompartment(oldCompartment);
-    startingCompartment->leave();
+    if (startingCompartment)
+        startingCompartment->leave();
 }
 
 inline void
 js::ExclusiveContext::setCompartment(JSCompartment *comp)
 {
     // ExclusiveContexts can only be in the atoms zone or in exclusive zones.
     JS_ASSERT_IF(!isJSContext() && !runtime_->isAtomsCompartment(comp),
                  comp->zone()->usedByExclusiveThread);