Bug 834732 - Introduce AutoPushJSContext. r=mrbkap
authorBobby Holley <bobbyholley@gmail.com>
Tue, 26 Feb 2013 11:04:12 -0800
changeset 123043 0e9081767ffd9528f2e63c52bfdc7a03f558479f
parent 123042 79519aeac030680d215502b12195a5fdccd840c6
child 123044 a099a2fcdc4eea37f1eb6545f5c1a50d9f2312d4
push id23632
push userbobbyholley@gmail.com
push dateTue, 26 Feb 2013 19:04:30 +0000
treeherdermozilla-inbound@a38bbae7a53b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs834732
milestone22.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 834732 - Introduce AutoPushJSContext. r=mrbkap It's annoying to add yet another RAII class, but we're solving a different problem here. In particular, there are lots of callers that grab a cx off of an nsIScriptContext and use it without pushing. Most of the time this is ok, since that cx is also the active cx. But it's hard to tell when we might potentially violate that invariant. What's more, we don't want to just use an nsCxPusher, because that does expensive things even when the cx matches the one on the top of the stack. Most of these consumers should just switch to AutoJSContext, but doing such a change en masse is a pretty risky thing to do. So let's introduce a class that gives us good performance in the common case and correctness in the uncommon case.
content/base/public/nsContentUtils.h
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -2297,16 +2297,43 @@ private:
  * SafeAutoJSContext is similar to AutoJSContext but will only return the safe
  * JS context. That means it will never call ::GetCurrentJSContext().
  */
 class NS_STACK_CLASS SafeAutoJSContext : public AutoJSContext {
 public:
   SafeAutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
 };
 
+/**
+ * Use AutoPushJSContext when you want to use a specific JSContext that may or
+ * may not be already on the stack. This differs from nsCxPusher in that it only
+ * pushes in the case that the given cx is not the active cx on the JSContext
+ * stack, which avoids an expensive JS_SaveFrameChain in the common case.
+ *
+ * Most consumers of this should probably just use AutoJSContext. But the goal
+ * here is to preserve the existing behavior while ensure proper cx-stack
+ * semantics in edge cases where the context being used doesn't match the active
+ * context.
+ *
+ * NB: This will not push a null cx even if aCx is null. Make sure you know what
+ * you're doing.
+ */
+class NS_STACK_CLASS AutoPushJSContext {
+  nsCxPusher mPusher;
+  JSContext* mCx;
+
+public:
+    AutoPushJSContext(JSContext* aCx) : mCx(aCx) {
+      if (mCx && mCx != nsContentUtils::GetCurrentJSContext()) {
+        mPusher.Push(mCx);
+      }
+    }
+    operator JSContext*() { return mCx; }
+};
+
 } // namespace mozilla
 
 #define NS_INTERFACE_MAP_ENTRY_TEAROFF(_interface, _allocator)                \
   if (aIID.Equals(NS_GET_IID(_interface))) {                                  \
     foundInterface = static_cast<_interface *>(_allocator);                   \
     if (!foundInterface) {                                                    \
       *aInstancePtr = nullptr;                                                 \
       return NS_ERROR_OUT_OF_MEMORY;                                          \