mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 07:13:20 +00:00
Bug 868130 - Separate nsCxPusher an friends into their own file. r=gabor
We want to put a JSAutoRequest into nsCxPusher, but that would involve including jsapi.h in nsContentUtils.h, which we'd probably rather avoid doing. Let's just bite the bullet and do this.
This commit is contained in:
parent
cfe8b9c5d2
commit
3aeb0284ff
@ -41,6 +41,7 @@ EXPORTS += [
|
||||
'nsContentPolicyUtils.h',
|
||||
'nsContentUtils.h',
|
||||
'nsCopySupport.h',
|
||||
'nsCxPusher.h',
|
||||
'nsDOMFile.h',
|
||||
'nsDeprecatedOperationList.h',
|
||||
'nsDocElementCreatedNotificationRunner.h',
|
||||
|
@ -2266,40 +2266,6 @@ typedef nsCharSeparatedTokenizerTemplate<nsContentUtils::IsHTMLWhitespace>
|
||||
nsContentUtils::DropJSObjects(NS_CYCLE_COLLECTION_UPCAST(obj, clazz))
|
||||
|
||||
|
||||
class MOZ_STACK_CLASS nsCxPusher
|
||||
{
|
||||
public:
|
||||
nsCxPusher();
|
||||
~nsCxPusher(); // Calls Pop();
|
||||
|
||||
// Returns false if something erroneous happened.
|
||||
bool Push(mozilla::dom::EventTarget *aCurrentTarget);
|
||||
// If nothing has been pushed to stack, this works like Push.
|
||||
// Otherwise if context will change, Pop and Push will be called.
|
||||
bool RePush(mozilla::dom::EventTarget *aCurrentTarget);
|
||||
// If a null JSContext is passed to Push(), that will cause no
|
||||
// push to happen and false to be returned.
|
||||
void Push(JSContext *cx);
|
||||
// Explicitly push a null JSContext on the the stack
|
||||
void PushNull();
|
||||
|
||||
// Pop() will be a no-op if Push() or PushNull() fail
|
||||
void Pop();
|
||||
|
||||
nsIScriptContext* GetCurrentScriptContext() { return mScx; }
|
||||
private:
|
||||
// Combined code for PushNull() and Push(JSContext*)
|
||||
void DoPush(JSContext* cx);
|
||||
|
||||
nsCOMPtr<nsIScriptContext> mScx;
|
||||
bool mScriptIsRunning;
|
||||
bool mPushedSomething;
|
||||
#ifdef DEBUG
|
||||
JSContext* mPushedContext;
|
||||
unsigned mCompartmentDepthOnEntry;
|
||||
#endif
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS nsAutoScriptBlocker {
|
||||
public:
|
||||
nsAutoScriptBlocker(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) {
|
||||
@ -2341,70 +2307,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* 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:
|
||||
AutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
|
||||
operator JSContext*();
|
||||
|
||||
protected:
|
||||
AutoJSContext(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
|
||||
|
||||
private:
|
||||
// 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;
|
||||
nsCxPusher mPusher;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
/**
|
||||
* AutoSafeJSContext is similar to AutoJSContext but will only return the safe
|
||||
* JS context. That means it will never call ::GetCurrentJSContext().
|
||||
*/
|
||||
class MOZ_STACK_CLASS AutoSafeJSContext : public AutoJSContext {
|
||||
public:
|
||||
AutoSafeJSContext(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 MOZ_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); \
|
||||
@ -2473,4 +2375,6 @@ private:
|
||||
nsIMIMEHeaderParam* mService;
|
||||
};
|
||||
|
||||
#include "nsCxPusher.h"
|
||||
|
||||
#endif /* nsContentUtils_h___ */
|
||||
|
108
content/base/public/nsCxPusher.h
Normal file
108
content/base/public/nsCxPusher.h
Normal file
@ -0,0 +1,108 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
|
||||
#ifndef nsCxPusher_h___
|
||||
#define nsCxPusher_h___
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
class MOZ_STACK_CLASS nsCxPusher
|
||||
{
|
||||
public:
|
||||
nsCxPusher();
|
||||
~nsCxPusher(); // Calls Pop();
|
||||
|
||||
// Returns false if something erroneous happened.
|
||||
bool Push(mozilla::dom::EventTarget *aCurrentTarget);
|
||||
// If nothing has been pushed to stack, this works like Push.
|
||||
// Otherwise if context will change, Pop and Push will be called.
|
||||
bool RePush(mozilla::dom::EventTarget *aCurrentTarget);
|
||||
// If a null JSContext is passed to Push(), that will cause no
|
||||
// push to happen and false to be returned.
|
||||
void Push(JSContext *cx);
|
||||
// Explicitly push a null JSContext on the the stack
|
||||
void PushNull();
|
||||
|
||||
// Pop() will be a no-op if Push() or PushNull() fail
|
||||
void Pop();
|
||||
|
||||
nsIScriptContext* GetCurrentScriptContext() { return mScx; }
|
||||
private:
|
||||
// Combined code for PushNull() and Push(JSContext*)
|
||||
void DoPush(JSContext* cx);
|
||||
|
||||
nsCOMPtr<nsIScriptContext> mScx;
|
||||
bool mScriptIsRunning;
|
||||
bool mPushedSomething;
|
||||
#ifdef DEBUG
|
||||
JSContext* mPushedContext;
|
||||
unsigned mCompartmentDepthOnEntry;
|
||||
#endif
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* 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:
|
||||
AutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
|
||||
operator JSContext*();
|
||||
|
||||
protected:
|
||||
AutoJSContext(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
|
||||
|
||||
private:
|
||||
// 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;
|
||||
nsCxPusher mPusher;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
/**
|
||||
* AutoSafeJSContext is similar to AutoJSContext but will only return the safe
|
||||
* JS context. That means it will never call ::GetCurrentJSContext().
|
||||
*/
|
||||
class MOZ_STACK_CLASS AutoSafeJSContext : public AutoJSContext {
|
||||
public:
|
||||
AutoSafeJSContext(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 MOZ_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
|
||||
|
||||
#endif /* nsCxPusher_h___ */
|
@ -36,6 +36,7 @@ CPPSRCS = \
|
||||
nsCopySupport.cpp \
|
||||
nsCrossSiteListenerProxy.cpp \
|
||||
nsCSPService.cpp \
|
||||
nsCxPusher.cpp \
|
||||
nsDataDocumentContentPolicy.cpp \
|
||||
Attr.cpp \
|
||||
nsDOMAttributeMap.cpp \
|
||||
|
@ -2954,176 +2954,6 @@ nsContentUtils::GetEventArgNames(int32_t aNameSpaceID,
|
||||
}
|
||||
}
|
||||
|
||||
nsCxPusher::nsCxPusher()
|
||||
: mScriptIsRunning(false),
|
||||
mPushedSomething(false)
|
||||
{
|
||||
}
|
||||
|
||||
nsCxPusher::~nsCxPusher()
|
||||
{
|
||||
Pop();
|
||||
}
|
||||
|
||||
bool
|
||||
nsCxPusher::Push(EventTarget *aCurrentTarget)
|
||||
{
|
||||
if (mPushedSomething) {
|
||||
NS_ERROR("Whaaa! No double pushing with nsCxPusher::Push()!");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(aCurrentTarget, false);
|
||||
nsresult rv;
|
||||
nsIScriptContext* scx =
|
||||
aCurrentTarget->GetContextForEventHandlers(&rv);
|
||||
#ifdef DEBUG_smaug
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
#else
|
||||
if(NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!scx) {
|
||||
// The target may have a special JS context for event handlers.
|
||||
JSContext* cx = aCurrentTarget->GetJSContextForEventHandlers();
|
||||
if (cx) {
|
||||
DoPush(cx);
|
||||
}
|
||||
|
||||
// Nothing to do here, I guess. Have to return true so that event firing
|
||||
// will still work correctly even if there is no associated JSContext
|
||||
return true;
|
||||
}
|
||||
|
||||
JSContext* cx = scx ? scx->GetNativeContext() : nullptr;
|
||||
|
||||
// If there's no native context in the script context it must be
|
||||
// in the process or being torn down. We don't want to notify the
|
||||
// script context about scripts having been evaluated in such a
|
||||
// case, calling with a null cx is fine in that case.
|
||||
Push(cx);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nsCxPusher::RePush(EventTarget *aCurrentTarget)
|
||||
{
|
||||
if (!mPushedSomething) {
|
||||
return Push(aCurrentTarget);
|
||||
}
|
||||
|
||||
if (aCurrentTarget) {
|
||||
nsresult rv;
|
||||
nsIScriptContext* scx =
|
||||
aCurrentTarget->GetContextForEventHandlers(&rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
Pop();
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we have the same script context and native context is still
|
||||
// alive, no need to Pop/Push.
|
||||
if (scx && scx == mScx &&
|
||||
scx->GetNativeContext()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Pop();
|
||||
return Push(aCurrentTarget);
|
||||
}
|
||||
|
||||
void
|
||||
nsCxPusher::Push(JSContext *cx)
|
||||
{
|
||||
MOZ_ASSERT(!mPushedSomething, "No double pushing with nsCxPusher::Push()!");
|
||||
MOZ_ASSERT(cx);
|
||||
|
||||
// Hold a strong ref to the nsIScriptContext, just in case
|
||||
// XXXbz do we really need to? If we don't get one of these in Pop(), is
|
||||
// that really a problem? Or do we need to do this to effectively root |cx|?
|
||||
mScx = GetScriptContextFromJSContext(cx);
|
||||
|
||||
DoPush(cx);
|
||||
}
|
||||
|
||||
void
|
||||
nsCxPusher::DoPush(JSContext* cx)
|
||||
{
|
||||
nsIXPConnect *xpc = nsContentUtils::XPConnect();
|
||||
if (!xpc) {
|
||||
// If someone tries to push a cx when we don't have the relevant state,
|
||||
// it's probably safest to just crash.
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
// NB: The GetDynamicScriptContext is historical and might not be sane.
|
||||
if (cx && nsJSUtils::GetDynamicScriptContext(cx) &&
|
||||
xpc::danger::IsJSContextOnStack(cx))
|
||||
{
|
||||
// If the context is on the stack, that means that a script
|
||||
// is running at the moment in the context.
|
||||
mScriptIsRunning = true;
|
||||
}
|
||||
|
||||
if (!xpc::danger::PushJSContext(cx)) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
mPushedSomething = true;
|
||||
#ifdef DEBUG
|
||||
mPushedContext = cx;
|
||||
if (cx)
|
||||
mCompartmentDepthOnEntry = js::GetEnterCompartmentDepth(cx);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
nsCxPusher::PushNull()
|
||||
{
|
||||
DoPush(nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
nsCxPusher::Pop()
|
||||
{
|
||||
MOZ_ASSERT(nsContentUtils::XPConnect());
|
||||
if (!mPushedSomething) {
|
||||
mScx = nullptr;
|
||||
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));
|
||||
DebugOnly<JSContext*> stackTop;
|
||||
MOZ_ASSERT(mPushedContext == nsContentUtils::GetCurrentJSContext());
|
||||
xpc::danger::PopJSContext();
|
||||
|
||||
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.
|
||||
|
||||
mScx->ScriptEvaluated(true);
|
||||
}
|
||||
|
||||
mScx = nullptr;
|
||||
mScriptIsRunning = false;
|
||||
mPushedSomething = false;
|
||||
}
|
||||
|
||||
static const char gPropertiesFiles[nsContentUtils::PropertiesFile_COUNT][56] = {
|
||||
// Must line up with the enum values in |PropertiesFile| enum.
|
||||
"chrome://global/locale/css.properties",
|
||||
@ -6744,42 +6574,3 @@ nsContentUtils::InternalIsSupported(nsISupports* aObject,
|
||||
// Otherwise, we claim to support everything
|
||||
return true;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Init(aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT);
|
||||
}
|
||||
|
||||
void
|
||||
AutoJSContext::Init(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
|
||||
{
|
||||
MOZ_ASSERT(!mCx, "mCx should not be initialized!");
|
||||
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
|
||||
if (!aSafe) {
|
||||
mCx = nsContentUtils::GetCurrentJSContext();
|
||||
}
|
||||
|
||||
if (!mCx) {
|
||||
mCx = nsContentUtils::GetSafeJSContext();
|
||||
mPusher.Push(mCx);
|
||||
}
|
||||
}
|
||||
|
||||
AutoJSContext::operator JSContext*()
|
||||
{
|
||||
return mCx;
|
||||
}
|
||||
|
||||
AutoSafeJSContext::AutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
|
||||
: AutoJSContext(true MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
|
||||
{
|
||||
}
|
||||
|
230
content/base/src/nsCxPusher.cpp
Normal file
230
content/base/src/nsCxPusher.cpp
Normal file
@ -0,0 +1,230 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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 "nsContentUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "nsIScriptContext.h"
|
||||
#include "mozilla/dom/EventTarget.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsDOMJSUtils.h"
|
||||
#include "mozilla/Util.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
using mozilla::dom::EventTarget;
|
||||
using mozilla::DebugOnly;
|
||||
|
||||
nsCxPusher::nsCxPusher()
|
||||
: mScriptIsRunning(false),
|
||||
mPushedSomething(false)
|
||||
{
|
||||
}
|
||||
|
||||
nsCxPusher::~nsCxPusher()
|
||||
{
|
||||
Pop();
|
||||
}
|
||||
|
||||
bool
|
||||
nsCxPusher::Push(EventTarget *aCurrentTarget)
|
||||
{
|
||||
if (mPushedSomething) {
|
||||
NS_ERROR("Whaaa! No double pushing with nsCxPusher::Push()!");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(aCurrentTarget, false);
|
||||
nsresult rv;
|
||||
nsIScriptContext* scx =
|
||||
aCurrentTarget->GetContextForEventHandlers(&rv);
|
||||
#ifdef DEBUG_smaug
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
#else
|
||||
if(NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!scx) {
|
||||
// The target may have a special JS context for event handlers.
|
||||
JSContext* cx = aCurrentTarget->GetJSContextForEventHandlers();
|
||||
if (cx) {
|
||||
DoPush(cx);
|
||||
}
|
||||
|
||||
// Nothing to do here, I guess. Have to return true so that event firing
|
||||
// will still work correctly even if there is no associated JSContext
|
||||
return true;
|
||||
}
|
||||
|
||||
JSContext* cx = scx ? scx->GetNativeContext() : nullptr;
|
||||
|
||||
// If there's no native context in the script context it must be
|
||||
// in the process or being torn down. We don't want to notify the
|
||||
// script context about scripts having been evaluated in such a
|
||||
// case, calling with a null cx is fine in that case.
|
||||
Push(cx);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nsCxPusher::RePush(EventTarget *aCurrentTarget)
|
||||
{
|
||||
if (!mPushedSomething) {
|
||||
return Push(aCurrentTarget);
|
||||
}
|
||||
|
||||
if (aCurrentTarget) {
|
||||
nsresult rv;
|
||||
nsIScriptContext* scx =
|
||||
aCurrentTarget->GetContextForEventHandlers(&rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
Pop();
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we have the same script context and native context is still
|
||||
// alive, no need to Pop/Push.
|
||||
if (scx && scx == mScx &&
|
||||
scx->GetNativeContext()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Pop();
|
||||
return Push(aCurrentTarget);
|
||||
}
|
||||
|
||||
void
|
||||
nsCxPusher::Push(JSContext *cx)
|
||||
{
|
||||
MOZ_ASSERT(!mPushedSomething, "No double pushing with nsCxPusher::Push()!");
|
||||
MOZ_ASSERT(cx);
|
||||
|
||||
// Hold a strong ref to the nsIScriptContext, just in case
|
||||
// XXXbz do we really need to? If we don't get one of these in Pop(), is
|
||||
// that really a problem? Or do we need to do this to effectively root |cx|?
|
||||
mScx = GetScriptContextFromJSContext(cx);
|
||||
|
||||
DoPush(cx);
|
||||
}
|
||||
|
||||
void
|
||||
nsCxPusher::DoPush(JSContext* cx)
|
||||
{
|
||||
nsIXPConnect *xpc = nsContentUtils::XPConnect();
|
||||
if (!xpc) {
|
||||
// If someone tries to push a cx when we don't have the relevant state,
|
||||
// it's probably safest to just crash.
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
// NB: The GetDynamicScriptContext is historical and might not be sane.
|
||||
if (cx && nsJSUtils::GetDynamicScriptContext(cx) &&
|
||||
xpc::danger::IsJSContextOnStack(cx))
|
||||
{
|
||||
// If the context is on the stack, that means that a script
|
||||
// is running at the moment in the context.
|
||||
mScriptIsRunning = true;
|
||||
}
|
||||
|
||||
if (!xpc::danger::PushJSContext(cx)) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
mPushedSomething = true;
|
||||
#ifdef DEBUG
|
||||
mPushedContext = cx;
|
||||
if (cx)
|
||||
mCompartmentDepthOnEntry = js::GetEnterCompartmentDepth(cx);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
nsCxPusher::PushNull()
|
||||
{
|
||||
DoPush(nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
nsCxPusher::Pop()
|
||||
{
|
||||
MOZ_ASSERT(nsContentUtils::XPConnect());
|
||||
if (!mPushedSomething) {
|
||||
mScx = nullptr;
|
||||
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));
|
||||
DebugOnly<JSContext*> stackTop;
|
||||
MOZ_ASSERT(mPushedContext == nsContentUtils::GetCurrentJSContext());
|
||||
xpc::danger::PopJSContext();
|
||||
|
||||
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.
|
||||
|
||||
mScx->ScriptEvaluated(true);
|
||||
}
|
||||
|
||||
mScx = nullptr;
|
||||
mScriptIsRunning = false;
|
||||
mPushedSomething = false;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
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)
|
||||
{
|
||||
Init(aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT);
|
||||
}
|
||||
|
||||
void
|
||||
AutoJSContext::Init(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
|
||||
{
|
||||
MOZ_ASSERT(!mCx, "mCx should not be initialized!");
|
||||
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
|
||||
if (!aSafe) {
|
||||
mCx = nsContentUtils::GetCurrentJSContext();
|
||||
}
|
||||
|
||||
if (!mCx) {
|
||||
mCx = nsContentUtils::GetSafeJSContext();
|
||||
mPusher.Push(mCx);
|
||||
}
|
||||
}
|
||||
|
||||
AutoJSContext::operator JSContext*()
|
||||
{
|
||||
return mCx;
|
||||
}
|
||||
|
||||
AutoSafeJSContext::AutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
|
||||
: AutoJSContext(true MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
Loading…
Reference in New Issue
Block a user