Bug 825395 - Add debug checking for interleaved nsCxPusher and JSAutoEnterCompartment. r=bz,luke
authorBobby Holley <bobbyholley@gmail.com>
Wed, 16 Jan 2013 18:50:25 -0800
changeset 119102 e194999b0d6661de9f4f7d47bed4b918048d24c3
parent 119101 fa51126256532a4d8d2632d6e80de4d6a78915dd
child 119103 e51150a044d7fdac4d1c7cb686927ad804609b13
push id24189
push useremorley@mozilla.com
push dateThu, 17 Jan 2013 10:42:06 +0000
treeherdermozilla-central@712eca11a04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, luke
bugs825395
milestone21.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 825395 - Add debug checking for interleaved nsCxPusher and JSAutoEnterCompartment. r=bz,luke
content/base/public/nsContentUtils.h
content/base/src/nsContentUtils.cpp
js/src/jscntxt.h
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -2205,16 +2205,17 @@ private:
   // Combined code for PushNull() and Push(JSContext*)
   bool DoPush(JSContext* cx);
 
   nsCOMPtr<nsIScriptContext> mScx;
   bool mScriptIsRunning;
   bool mPushedSomething;
 #ifdef DEBUG
   JSContext* mPushedContext;
+  unsigned mCompartmentDepthOnEntry;
 #endif
 };
 
 class NS_STACK_CLASS nsAutoScriptBlocker {
 public:
   nsAutoScriptBlocker(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) {
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     nsContentUtils::AddScriptBlocker();
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -3071,16 +3071,18 @@ nsCxPusher::DoPush(JSContext* cx)
     mScriptIsRunning = false;
     mScx = nullptr;
     return false;
   }
 
   mPushedSomething = true;
 #ifdef DEBUG
   mPushedContext = cx;
+  if (cx)
+    mCompartmentDepthOnEntry = js::GetEnterCompartmentDepth(cx);
 #endif
   return true;
 }
 
 bool
 nsCxPusher::PushNull()
 {
   return DoPush(nullptr);
@@ -3095,16 +3097,24 @@ nsCxPusher::Pop()
     mPushedSomething = false;
 
     NS_ASSERTION(!mScriptIsRunning, "Huh, this can't be happening, "
                  "mScriptIsRunning can't be set here!");
 
     return;
   }
 
+  // When we push a context, we may save the frame chain and pretend like we
+  // haven't entered any compartment. This gets restored on Pop(), but we can
+  // run into trouble if a Push/Pop are interleaved with a
+  // JSAutoEnterCompartment. Make sure the compartment depth right before we
+  // pop is the same as it was right after we pushed.
+  MOZ_ASSERT_IF(mPushedContext, mCompartmentDepthOnEntry ==
+                                js::GetEnterCompartmentDepth(mPushedContext));
+
   JSContext *unused;
   stack->Pop(&unused);
 
   NS_ASSERTION(unused == mPushedContext, "Unexpected context popped");
 
   if (!mScriptIsRunning && mScx) {
     // No JS is running in the context, but executing the event handler might have
     // caused some JS to run. Tell the script context that it's done.
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1454,16 +1454,21 @@ struct JSContext : js::ContextFriendFiel
      * manually calling cx->enterCompartment/leaveCompartment.
      */
   private:
     unsigned            enterCompartmentDepth_;
   public:
     bool hasEnteredCompartment() const {
         return enterCompartmentDepth_ > 0;
     }
+#ifdef DEBUG
+    unsigned getEnterCompartmentDepth() const {
+        return enterCompartmentDepth_;
+    }
+#endif
 
     inline void enterCompartment(JSCompartment *c);
     inline void leaveCompartment(JSCompartment *oldCompartment);
 
     /* See JS_SaveFrameChain/JS_RestoreFrameChain. */
   private:
     struct SavedFrameChain {
         SavedFrameChain(JSCompartment *comp, unsigned count)
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -928,16 +928,24 @@ js::GetTestingFunctions(JSContext *cx)
         return NULL;
 
     if (!DefineTestingFunctions(cx, obj))
         return NULL;
 
     return obj;
 }
 
+#ifdef DEBUG
+JS_FRIEND_API(unsigned)
+js::GetEnterCompartmentDepth(JSContext *cx)
+{
+  return cx->getEnterCompartmentDepth();
+}
+#endif
+
 JS_FRIEND_API(void)
 js::SetRuntimeProfilingStack(JSRuntime *rt, ProfileEntry *stack, uint32_t *size, uint32_t max)
 {
     rt->spsProfiler.setProfilingStack(stack, size, max);
 }
 
 JS_FRIEND_API(void)
 js::EnableRuntimeProfilingStack(JSRuntime *rt, bool enabled)
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -967,16 +967,21 @@ CastToJSFreeOp(FreeOp *fop)
 
 /*
  * Get an error type name from a JSExnType constant.
  * Returns NULL for invalid arguments and JSEXN_INTERNALERR
  */
 extern JS_FRIEND_API(const jschar*)
 GetErrorTypeName(JSContext* cx, int16_t exnType);
 
+#ifdef DEBUG
+extern JS_FRIEND_API(unsigned)
+GetEnterCompartmentDepth(JSContext* cx);
+#endif
+
 /* Implemented in jswrapper.cpp. */
 typedef enum NukeReferencesToWindow {
     NukeWindowReferences,
     DontNukeWindowReferences
 } NukeReferencesToWindow;
 
 /*
  * These filters are designed to be ephemeral stack classes, and thus don't