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

This commit is contained in:
Bobby Holley 2014-08-14 18:47:15 -07:00
parent 0ab3acbee2
commit 850fc35028
6 changed files with 103 additions and 93 deletions

View File

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

View File

@ -9,6 +9,7 @@
#include "mozilla/Assertions.h"
#include "jsapi.h"
#include "xpcprivate.h" // For AutoCxPusher guts
#include "xpcpublic.h"
#include "nsIGlobalObject.h"
#include "nsIScriptGlobalObject.h"
@ -18,6 +19,7 @@
#include "nsPIDOMWindow.h"
#include "nsTArray.h"
#include "nsJSUtils.h"
#include "nsDOMJSUtils.h"
namespace mozilla {
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 mozilla

View File

@ -9,19 +9,52 @@
#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).
@ -184,7 +217,7 @@ protected:
AutoJSAPI(nsIGlobalObject* aGlobalObject, bool aIsMainThread, JSContext* aCx);
private:
mozilla::Maybe<AutoCxPusher> mCxPusher;
mozilla::Maybe<danger::AutoCxPusher> mCxPusher;
mozilla::Maybe<JSAutoNullableCompartment> mAutoNullableCompartment;
JSContext *mCx;
@ -242,7 +275,7 @@ class AutoNoJSAPI : protected ScriptSettingsStackEntry {
public:
explicit AutoNoJSAPI(bool aIsMainThread = NS_IsMainThread());
private:
mozilla::Maybe<AutoCxPusher> mCxPusher;
mozilla::Maybe<danger::AutoCxPusher> mCxPusher;
};
} // namespace dom

View File

@ -15,67 +15,6 @@ 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)
{

View File

@ -9,39 +9,13 @@
#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
@ -61,7 +35,7 @@ protected:
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
};

View File

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