Bug 1052052 - Hoist AutoCxPusher into ScriptSettings.h. r=gabor
authorBobby Holley <bobbyholley@gmail.com>
Thu, 14 Aug 2014 18:47:15 -0700
changeset 221290 74f2a2d657e38df442564bccd3ba9fcd329234cd
parent 221289 abb6a2af7cb508d2d745f6016a51ca55e380e5ca
child 221291 55783b8e332ce82b6652f8917319cfa7b00bc031
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgabor
bugs1052052
milestone34.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 1052052 - Hoist AutoCxPusher into ScriptSettings.h. r=gabor
content/base/public/nsContentUtils.h
dom/base/ScriptSettings.cpp
dom/base/ScriptSettings.h
js/xpconnect/src/nsCxPusher.cpp
js/xpconnect/src/nsCxPusher.h
js/xpconnect/src/xpcprivate.h
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -19,16 +19,17 @@
 
 #include "js/TypeDecls.h"
 #include "js/Value.h"
 #include "js/RootingAPI.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/GuardObjects.h"
 #include "mozilla/TimeStamp.h"
 #include "nsContentListDeclarations.h"
+#include "nsCxPusher.h"
 #include "nsMathUtils.h"
 #include "nsTArrayForwardDeclare.h"
 #include "Units.h"
 #include "mozilla/dom/AutocompleteInfoBinding.h"
 
 #if defined(XP_WIN)
 // Undefine LoadImage to prevent naming conflict with Windows.
 #undef LoadImage
--- a/dom/base/ScriptSettings.cpp
+++ b/dom/base/ScriptSettings.cpp
@@ -4,25 +4,27 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/ThreadLocal.h"
 #include "mozilla/Assertions.h"
 
 #include "jsapi.h"
+#include "xpcprivate.h" // For AutoCxPusher guts
 #include "xpcpublic.h"
 #include "nsIGlobalObject.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptContext.h"
 #include "nsContentUtils.h"
 #include "nsGlobalWindow.h"
 #include "nsPIDOMWindow.h"
 #include "nsTArray.h"
 #include "nsJSUtils.h"
+#include "nsDOMJSUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 static mozilla::ThreadLocal<ScriptSettingsStackEntry*> sScriptSettingsTLS;
 
 class ScriptSettingsStack {
 public:
@@ -368,10 +370,71 @@ AutoNoJSAPI::AutoNoJSAPI(bool aIsMainThr
   MOZ_ASSERT_IF(nsContentUtils::GetCurrentJSContextForThread(),
                 !JS_IsExceptionPending(nsContentUtils::GetCurrentJSContextForThread()));
   if (aIsMainThread) {
     mCxPusher.emplace(static_cast<JSContext*>(nullptr),
                       /* aAllowNull = */ true);
   }
 }
 
+danger::AutoCxPusher::AutoCxPusher(JSContext* cx, bool allowNull)
+{
+  MOZ_ASSERT_IF(!allowNull, cx);
+
+  // Hold a strong ref to the nsIScriptContext, if any. This ensures that we
+  // only destroy the mContext of an nsJSContext when it is not on the cx stack
+  // (and therefore not in use). See nsJSContext::DestroyJSContext().
+  if (cx)
+    mScx = GetScriptContextFromJSContext(cx);
+
+  XPCJSContextStack *stack = XPCJSRuntime::Get()->GetJSContextStack();
+  if (!stack->Push(cx)) {
+    MOZ_CRASH();
+  }
+  mStackDepthAfterPush = stack->Count();
+
+#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.
+  if (cx) {
+    mAutoRequest.emplace(cx);
+
+    // DOM JSContexts don't store their default compartment object on the cx.
+    JSObject *compartmentObject = mScx ? mScx->GetWindowProxy()
+                                       : js::DefaultObjectForContextOrNull(cx);
+    if (compartmentObject)
+      mAutoCompartment.emplace(cx, compartmentObject);
+  }
+}
+
+danger::AutoCxPusher::~AutoCxPusher()
+{
+  // Leave the compartment and request before popping.
+  mAutoCompartment.reset();
+  mAutoRequest.reset();
+
+  // 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));
+  DebugOnly<JSContext*> stackTop;
+  MOZ_ASSERT(mPushedContext == nsXPConnect::XPConnect()->GetCurrentJSContext());
+  XPCJSRuntime::Get()->GetJSContextStack()->Pop();
+  mScx = nullptr;
+}
+
+bool
+danger::AutoCxPusher::IsStackTop() const
+{
+  uint32_t currentDepth = XPCJSRuntime::Get()->GetJSContextStack()->Count();
+  MOZ_ASSERT(currentDepth >= mStackDepthAfterPush);
+  return currentDepth == mStackDepthAfterPush;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/ScriptSettings.h
+++ b/dom/base/ScriptSettings.h
@@ -4,29 +4,62 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* Utilities for managing the script settings object stack defined in webapps */
 
 #ifndef mozilla_dom_ScriptSettings_h
 #define mozilla_dom_ScriptSettings_h
 
-#include "nsCxPusher.h"
 #include "MainThreadUtils.h"
 #include "nsIGlobalObject.h"
 #include "nsIPrincipal.h"
 
 #include "mozilla/Maybe.h"
 
+#include "jsapi.h"
+
 class nsPIDOMWindow;
 class nsGlobalWindow;
+class nsIScriptContext;
 
 namespace mozilla {
 namespace dom {
 
+namespace danger {
+
+/**
+ * Fundamental cx pushing class. All other cx pushing classes are implemented
+ * in terms of this class.
+ */
+class MOZ_STACK_CLASS AutoCxPusher
+{
+public:
+  explicit AutoCxPusher(JSContext *aCx, bool aAllowNull = false);
+  ~AutoCxPusher();
+
+  nsIScriptContext* GetScriptContext() { return mScx; }
+
+  // Returns true if this AutoCxPusher performed the push that is currently at
+  // the top of the cx stack.
+  bool IsStackTop() const;
+
+private:
+  mozilla::Maybe<JSAutoRequest> mAutoRequest;
+  mozilla::Maybe<JSAutoCompartment> mAutoCompartment;
+  nsCOMPtr<nsIScriptContext> mScx;
+  uint32_t mStackDepthAfterPush;
+#ifdef DEBUG
+  JSContext* mPushedContext;
+  unsigned mCompartmentDepthOnEntry;
+#endif
+};
+
+} /* namespace danger */
+
 /*
  * System-wide setup/teardown routines. Init and Destroy should be invoked
  * once each, at startup and shutdown (respectively).
  */
 void InitScriptSettings();
 void DestroyScriptSettings();
 
 // This mostly gets the entry global, but doesn't entirely match the spec in
@@ -179,17 +212,17 @@ protected:
   // Protected constructor, allowing subclasses to specify a particular cx to
   // be used. This constructor initialises the AutoJSAPI, so Init must NOT be
   // called on subclasses that use this.
   // If aGlobalObject, its associated JS global or aCx are null this will cause
   // an assertion, as will setting aIsMainThread incorrectly.
   AutoJSAPI(nsIGlobalObject* aGlobalObject, bool aIsMainThread, JSContext* aCx);
 
 private:
-  mozilla::Maybe<AutoCxPusher> mCxPusher;
+  mozilla::Maybe<danger::AutoCxPusher> mCxPusher;
   mozilla::Maybe<JSAutoNullableCompartment> mAutoNullableCompartment;
   JSContext *mCx;
 
   void InitInternal(JSObject* aGlobal, JSContext* aCx, bool aIsMainThread);
 };
 
 /*
  * A class that represents a new script entry point.
@@ -237,15 +270,15 @@ private:
  * either popped or an AutoJSAPI instance is subsequently pushed.
  *
  * This class may not be instantiated if an exception is pending.
  */
 class AutoNoJSAPI : protected ScriptSettingsStackEntry {
 public:
   explicit AutoNoJSAPI(bool aIsMainThread = NS_IsMainThread());
 private:
-  mozilla::Maybe<AutoCxPusher> mCxPusher;
+  mozilla::Maybe<danger::AutoCxPusher> mCxPusher;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_ScriptSettings_h
--- a/js/xpconnect/src/nsCxPusher.cpp
+++ b/js/xpconnect/src/nsCxPusher.cpp
@@ -10,77 +10,16 @@
 #include "nsDOMJSUtils.h"
 #include "xpcprivate.h"
 #include "WorkerPrivate.h"
 
 using mozilla::DebugOnly;
 
 namespace mozilla {
 
-AutoCxPusher::AutoCxPusher(JSContext* cx, bool allowNull)
-{
-  MOZ_ASSERT_IF(!allowNull, cx);
-
-  // Hold a strong ref to the nsIScriptContext, if any. This ensures that we
-  // only destroy the mContext of an nsJSContext when it is not on the cx stack
-  // (and therefore not in use). See nsJSContext::DestroyJSContext().
-  if (cx)
-    mScx = GetScriptContextFromJSContext(cx);
-
-  XPCJSContextStack *stack = XPCJSRuntime::Get()->GetJSContextStack();
-  if (!stack->Push(cx)) {
-    MOZ_CRASH();
-  }
-  mStackDepthAfterPush = stack->Count();
-
-#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.
-  if (cx) {
-    mAutoRequest.emplace(cx);
-
-    // DOM JSContexts don't store their default compartment object on the cx.
-    JSObject *compartmentObject = mScx ? mScx->GetWindowProxy()
-                                       : js::DefaultObjectForContextOrNull(cx);
-    if (compartmentObject)
-      mAutoCompartment.emplace(cx, compartmentObject);
-  }
-}
-
-AutoCxPusher::~AutoCxPusher()
-{
-  // Leave the compartment and request before popping.
-  mAutoCompartment.reset();
-  mAutoRequest.reset();
-
-  // 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));
-  DebugOnly<JSContext*> stackTop;
-  MOZ_ASSERT(mPushedContext == nsXPConnect::XPConnect()->GetCurrentJSContext());
-  XPCJSRuntime::Get()->GetJSContextStack()->Pop();
-  mScx = nullptr;
-}
-
-bool
-AutoCxPusher::IsStackTop() const
-{
-  uint32_t currentDepth = XPCJSRuntime::Get()->GetJSContextStack()->Count();
-  MOZ_ASSERT(currentDepth >= mStackDepthAfterPush);
-  return currentDepth == mStackDepthAfterPush;
-}
-
 AutoJSContext::AutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
   : mCx(nullptr)
 {
   Init(false MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT);
 }
 
 AutoJSContext::AutoJSContext(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
   : mCx(nullptr)
--- a/js/xpconnect/src/nsCxPusher.h
+++ b/js/xpconnect/src/nsCxPusher.h
@@ -4,50 +4,24 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsCxPusher_h
 #define nsCxPusher_h
 
 #include "jsapi.h"
 #include "mozilla/Maybe.h"
+#include "mozilla/dom/ScriptSettings.h"
 #include "nsCOMPtr.h"
 
 class nsIScriptContext;
 
 namespace mozilla {
 
 /**
- * Fundamental cx pushing class. All other cx pushing classes are implemented
- * in terms of this class.
- */
-class MOZ_STACK_CLASS AutoCxPusher
-{
-public:
-  explicit AutoCxPusher(JSContext *aCx, bool aAllowNull = false);
-  ~AutoCxPusher();
-
-  nsIScriptContext* GetScriptContext() { return mScx; }
-
-  // Returns true if this AutoCxPusher performed the push that is currently at
-  // the top of the cx stack.
-  bool IsStackTop() const;
-
-private:
-  mozilla::Maybe<JSAutoRequest> mAutoRequest;
-  mozilla::Maybe<JSAutoCompartment> mAutoCompartment;
-  nsCOMPtr<nsIScriptContext> mScx;
-  uint32_t mStackDepthAfterPush;
-#ifdef DEBUG
-  JSContext* mPushedContext;
-  unsigned mCompartmentDepthOnEntry;
-#endif
-};
-
-/**
  * Use AutoJSContext when you need a JS context on the stack but don't have one
  * passed as a parameter. AutoJSContext will take care of finding the most
  * appropriate JS context and release it when leaving the stack.
  */
 class MOZ_STACK_CLASS AutoJSContext {
 public:
   explicit AutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
   operator JSContext*() const;
@@ -56,17 +30,17 @@ protected:
   explicit AutoJSContext(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
 
   // We need this Init() method because we can't use delegating constructor for
   // the moment. It is a C++11 feature and we do not require C++11 to be
   // supported to be able to compile Gecko.
   void Init(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
 
   JSContext* mCx;
-  Maybe<AutoCxPusher> mPusher;
+  Maybe<mozilla::dom::danger::AutoCxPusher> mPusher;
   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 /**
  * Use ThreadsafeAutoJSContext when you want an AutoJSContext but might be
  * running on a worker thread.
  */
 class MOZ_STACK_CLASS ThreadsafeAutoJSContext {
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -2858,17 +2858,17 @@ public:
     JSContext *GetSafeJSContext();
     JSObject *GetSafeJSContextGlobal();
     bool HasJSContext(JSContext *cx);
 
     const InfallibleTArray<XPCJSContextInfo>* GetStack()
     { return &mStack; }
 
 private:
-    friend class mozilla::AutoCxPusher;
+    friend class mozilla::dom::danger::AutoCxPusher;
     friend bool xpc::PushJSContextNoScriptContext(JSContext *aCx);;
     friend void xpc::PopJSContextNoScriptContext();
 
     // We make these private so that stack manipulation can only happen
     // through one of the above friends.
     JSContext *Pop();
     bool Push(JSContext *cx);