Bug 937317 - Factor out the shareable parts of CallSetup into AutoEntryScript and AutoIncubentScript. r=bz

This commit is contained in:
Bobby Holley 2013-12-06 12:01:41 -08:00
parent 7bba051425
commit ef4bb3070d
5 changed files with 138 additions and 19 deletions

View File

@ -0,0 +1,54 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
// vim: ft=cpp tw=78 sw=2 et ts=2
/* 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 "mozilla/dom/ScriptSettings.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptContext.h"
#include "nsContentUtils.h"
namespace mozilla {
namespace dom {
AutoEntryScript::AutoEntryScript(nsIGlobalObject* aGlobalObject,
bool aIsMainThread,
JSContext* aCx)
{
MOZ_ASSERT(aGlobalObject);
if (!aCx) {
// If the caller didn't provide a cx, hunt one down. This isn't exactly
// fast, but the callers that care about performance can pass an explicit
// cx for now. Eventually, the whole cx pushing thing will go away
// entirely.
MOZ_ASSERT(aIsMainThread, "cx is mandatory off-main-thread");
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aGlobalObject);
if (sgo && sgo->GetScriptContext()) {
aCx = sgo->GetScriptContext()->GetNativeContext();
}
if (!aCx) {
aCx = nsContentUtils::GetSafeJSContext();
}
}
if (aIsMainThread) {
mCxPusher.Push(aCx);
}
mAc.construct(aCx, aGlobalObject->GetGlobalJSObject());
}
AutoIncumbentScript::AutoIncumbentScript(nsIGlobalObject* aGlobalObject)
{
MOZ_ASSERT(aGlobalObject);
}
AutoSystemCaller::AutoSystemCaller(bool aIsMainThread)
{
if (aIsMainThread) {
mCxPusher.PushNull();
}
}
} // namespace dom
} // namespace mozilla

61
dom/base/ScriptSettings.h Normal file
View File

@ -0,0 +1,61 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
// vim: ft=cpp tw=78 sw=2 et ts=2
/* 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/. */
/* 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 "mozilla/Maybe.h"
class nsIGlobalObject;
namespace mozilla {
namespace dom {
/*
* A class that represents a new script entry point.
*/
class AutoEntryScript {
public:
AutoEntryScript(nsIGlobalObject* aGlobalObject,
bool aIsMainThread = NS_IsMainThread(),
// Note: aCx is mandatory off-main-thread.
JSContext* aCx = nullptr);
private:
nsCxPusher mCxPusher;
mozilla::Maybe<JSAutoCompartment> mAc; // This can de-Maybe-fy when mCxPusher
// goes away.
};
/*
* A class that can be used to force a particular incumbent script on the stack.
*/
class AutoIncumbentScript {
public:
AutoIncumbentScript(nsIGlobalObject* aGlobalObject);
};
/*
* A class used for C++ to indicate that existing entry and incumbent scripts
* should not apply to anything in scope, and that callees should act as if
* they were invoked "from C++".
*/
class AutoSystemCaller {
public:
AutoSystemCaller(bool aIsMainThread = NS_IsMainThread());
private:
nsCxPusher mCxPusher;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_ScriptSettings_h

View File

@ -59,6 +59,7 @@ EXPORTS.mozilla.dom += [
'MessagePortList.h',
'Navigator.h',
'ScreenOrientation.h',
'ScriptSettings.h',
'StructuredCloneTags.h',
'URL.h',
]
@ -94,6 +95,7 @@ UNIFIED_SOURCES += [
'nsWindowMemoryReporter.cpp',
'nsWindowRoot.cpp',
'nsWrapperCache.cpp',
'ScriptSettings.cpp',
'URL.cpp',
'WindowNamedPropertiesHandler.cpp',
]

View File

@ -19,6 +19,7 @@
#include "xpcprivate.h"
#include "WorkerPrivate.h"
#include "nsGlobalWindow.h"
#include "WorkerScope.h"
namespace mozilla {
namespace dom {
@ -65,6 +66,7 @@ CallbackObject::CallSetup::CallSetup(JS::Handle<JSObject*> aCallback,
// First, find the real underlying callback.
JSObject* realCallback = js::UncheckedUnwrap(aCallback);
JSContext* cx = nullptr;
nsIGlobalObject* globalObject = nullptr;
if (mIsMainThread) {
// Now get the global and JSContext for this callback.
@ -85,17 +87,21 @@ CallbackObject::CallSetup::CallSetup(JS::Handle<JSObject*> aCallback,
// This happens - Removing it causes
// test_bug293235.xul to go orange.
: nsContentUtils::GetSafeJSContext();
globalObject = win;
} else {
// No DOM Window. Use the SafeJSContext.
// No DOM Window. Store the global and use the SafeJSContext.
JSObject* glob = js::GetGlobalForObjectCrossCompartment(realCallback);
globalObject = xpc::GetNativeForGlobal(glob);
MOZ_ASSERT(globalObject);
cx = nsContentUtils::GetSafeJSContext();
}
// Make sure our JSContext is pushed on the stack.
mCxPusher.Push(cx);
} else {
cx = workers::GetCurrentThreadJSContext();
globalObject = workers::GetCurrentThreadWorkerPrivate()->GlobalScope();
}
mAutoEntryScript.construct(globalObject, mIsMainThread, cx);
// Unmark the callable, and stick it in a Rooted before it can go gray again.
// Nothing before us in this function can trigger a CC, so it's safe to wait
// until here it do the unmark. This allows us to order the following two
@ -120,6 +126,10 @@ CallbackObject::CallSetup::CallSetup(JS::Handle<JSObject*> aCallback,
}
// Enter the compartment of our callback, so we can actually work with it.
//
// Note that if the callback is a wrapper, this will not be the same
// compartment that we ended up in with mAutoEntryScript above, because the
// entry point is based off of the unwrapped callback (realCallback).
mAc.construct(cx, aCallback);
// And now we're ready to go.
@ -194,17 +204,10 @@ CallbackObject::CallSetup::~CallSetup()
// But be careful: it might not have been constructed at all!
mAc.destroyIfConstructed();
// XXXbz For that matter why do we need to manually call ScriptEvaluated at
// all? nsCxPusher::Pop will do that nowadays if !mScriptIsRunning, so the
// concerns from bug 295983 don't seem relevant anymore. Do we want to make
// sure it's still called when !mScriptIsRunning? I guess play it safe for
// now and do what CallEventHandler did, which is call always.
// Popping an nsCxPusher is safe even if it never got pushed.
mCxPusher.Pop();
mAutoEntryScript.destroyIfConstructed();
// It is important that this is the last thing we do, after leaving the
// compartment and popping the context.
// compartment and undoing all our entry/incumbent script changes
if (mIsMainThread) {
nsContentUtils::LeaveMicroTask();
}

View File

@ -25,8 +25,8 @@
#include "mozilla/ErrorResult.h"
#include "mozilla/HoldDropJSObjects.h"
#include "mozilla/Util.h"
#include "mozilla/dom/ScriptSettings.h"
#include "nsContentUtils.h"
#include "nsCxPusher.h"
#include "nsWrapperCache.h"
#include "nsJSEnvironment.h"
#include "xpcpublic.h"
@ -153,17 +153,16 @@ protected:
JSCompartment* mCompartment;
// And now members whose construction/destruction order we need to control.
nsCxPusher mCxPusher;
Maybe<AutoEntryScript> mAutoEntryScript;
// Constructed the rooter within the scope of mCxPusher above, so that it's
// always within a request during its lifetime.
Maybe<JS::Rooted<JSObject*> > mRootedCallable;
// Can't construct a JSAutoCompartment without a JSContext either. Also,
// Put mAc after mCxPusher so that we exit the compartment before we pop the
// JSContext. Though in practice we'll often manually order those two
// things.
// Put mAc after mAutoEntryScript so that we exit the compartment before
// we pop the JSContext. Though in practice we'll often manually order
// those two things.
Maybe<JSAutoCompartment> mAc;
// An ErrorResult to possibly re-throw exceptions on and whether