Bug 1052052 - Hoist AutoCxPusher into ScriptSettings.h. r=gabor

This commit is contained in:
Bobby Holley 2014-08-14 12:53:52 -07:00
Родитель 9d7a41f0f8
Коммит 35f3a10cb0
6 изменённых файлов: 103 добавлений и 93 удалений

Просмотреть файл

@ -24,6 +24,7 @@
#include "mozilla/GuardObjects.h" #include "mozilla/GuardObjects.h"
#include "mozilla/TimeStamp.h" #include "mozilla/TimeStamp.h"
#include "nsContentListDeclarations.h" #include "nsContentListDeclarations.h"
#include "nsCxPusher.h"
#include "nsMathUtils.h" #include "nsMathUtils.h"
#include "nsTArrayForwardDeclare.h" #include "nsTArrayForwardDeclare.h"
#include "Units.h" #include "Units.h"

Просмотреть файл

@ -9,6 +9,7 @@
#include "mozilla/Assertions.h" #include "mozilla/Assertions.h"
#include "jsapi.h" #include "jsapi.h"
#include "xpcprivate.h" // For AutoCxPusher guts
#include "xpcpublic.h" #include "xpcpublic.h"
#include "nsIGlobalObject.h" #include "nsIGlobalObject.h"
#include "nsIScriptGlobalObject.h" #include "nsIScriptGlobalObject.h"
@ -18,6 +19,7 @@
#include "nsPIDOMWindow.h" #include "nsPIDOMWindow.h"
#include "nsTArray.h" #include "nsTArray.h"
#include "nsJSUtils.h" #include "nsJSUtils.h"
#include "nsDOMJSUtils.h"
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
@ -373,5 +375,66 @@ AutoNoJSAPI::AutoNoJSAPI(bool aIsMainThread)
} }
} }
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 dom
} // namespace mozilla } // namespace mozilla

Просмотреть файл

@ -9,19 +9,52 @@
#ifndef mozilla_dom_ScriptSettings_h #ifndef mozilla_dom_ScriptSettings_h
#define mozilla_dom_ScriptSettings_h #define mozilla_dom_ScriptSettings_h
#include "nsCxPusher.h"
#include "MainThreadUtils.h" #include "MainThreadUtils.h"
#include "nsIGlobalObject.h" #include "nsIGlobalObject.h"
#include "nsIPrincipal.h" #include "nsIPrincipal.h"
#include "mozilla/Maybe.h" #include "mozilla/Maybe.h"
#include "jsapi.h"
class nsPIDOMWindow; class nsPIDOMWindow;
class nsGlobalWindow; class nsGlobalWindow;
class nsIScriptContext;
namespace mozilla { namespace mozilla {
namespace dom { 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 * System-wide setup/teardown routines. Init and Destroy should be invoked
* once each, at startup and shutdown (respectively). * once each, at startup and shutdown (respectively).
@ -183,7 +216,7 @@ protected:
AutoJSAPI(nsIGlobalObject* aGlobalObject, bool aIsMainThread, JSContext* aCx); AutoJSAPI(nsIGlobalObject* aGlobalObject, bool aIsMainThread, JSContext* aCx);
private: private:
mozilla::Maybe<AutoCxPusher> mCxPusher; mozilla::Maybe<danger::AutoCxPusher> mCxPusher;
mozilla::Maybe<JSAutoNullableCompartment> mAutoNullableCompartment; mozilla::Maybe<JSAutoNullableCompartment> mAutoNullableCompartment;
JSContext *mCx; JSContext *mCx;
@ -241,7 +274,7 @@ class AutoNoJSAPI : protected ScriptSettingsStackEntry {
public: public:
explicit AutoNoJSAPI(bool aIsMainThread = NS_IsMainThread()); explicit AutoNoJSAPI(bool aIsMainThread = NS_IsMainThread());
private: private:
mozilla::Maybe<AutoCxPusher> mCxPusher; mozilla::Maybe<danger::AutoCxPusher> mCxPusher;
}; };
} // namespace dom } // namespace dom

Просмотреть файл

@ -15,67 +15,6 @@ using mozilla::DebugOnly;
namespace mozilla { 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) AutoJSContext::AutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
: mCx(nullptr) : mCx(nullptr)
{ {

Просмотреть файл

@ -9,39 +9,13 @@
#include "jsapi.h" #include "jsapi.h"
#include "mozilla/Maybe.h" #include "mozilla/Maybe.h"
#include "mozilla/dom/ScriptSettings.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
class nsIScriptContext; class nsIScriptContext;
namespace mozilla { 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 * 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 * passed as a parameter. AutoJSContext will take care of finding the most
@ -61,7 +35,7 @@ protected:
void Init(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM); void Init(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
JSContext* mCx; JSContext* mCx;
Maybe<AutoCxPusher> mPusher; Maybe<mozilla::dom::danger::AutoCxPusher> mPusher;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
}; };

Просмотреть файл

@ -2863,7 +2863,7 @@ public:
{ return &mStack; } { return &mStack; }
private: private:
friend class mozilla::AutoCxPusher; friend class mozilla::dom::danger::AutoCxPusher;
friend bool xpc::PushJSContextNoScriptContext(JSContext *aCx);; friend bool xpc::PushJSContextNoScriptContext(JSContext *aCx);;
friend void xpc::PopJSContextNoScriptContext(); friend void xpc::PopJSContextNoScriptContext();