зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-i to m-c, a=merge
This commit is contained in:
Коммит
98d7a9d9c5
|
@ -9,7 +9,6 @@
|
|||
#include "mozilla/Assertions.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "xpcprivate.h" // For AutoCxPusher guts
|
||||
#include "xpcpublic.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
#include "nsIDocShell.h"
|
||||
|
@ -38,8 +37,13 @@ public:
|
|||
static void Push(ScriptSettingsStackEntry *aEntry) {
|
||||
MOZ_ASSERT(!aEntry->mOlder);
|
||||
// Whenever JSAPI use is disabled, the next stack entry pushed must
|
||||
// always be a candidate entry point.
|
||||
MOZ_ASSERT_IF(!Top() || Top()->NoJSAPI(), aEntry->mIsCandidateEntryPoint);
|
||||
// not be an AutoIncumbentScript.
|
||||
MOZ_ASSERT_IF(!Top() || Top()->NoJSAPI(),
|
||||
!aEntry->IsIncumbentScript());
|
||||
// Whenever the top entry is not an incumbent canidate, the next stack entry
|
||||
// pushed must not be an AutoIncumbentScript.
|
||||
MOZ_ASSERT_IF(Top() && !Top()->IsIncumbentCandidate(),
|
||||
!aEntry->IsIncumbentScript());
|
||||
|
||||
aEntry->mOlder = Top();
|
||||
sScriptSettingsTLS.set(aEntry);
|
||||
|
@ -52,23 +56,24 @@ public:
|
|||
|
||||
static nsIGlobalObject* IncumbentGlobal() {
|
||||
ScriptSettingsStackEntry *entry = Top();
|
||||
if (!entry) {
|
||||
return nullptr;
|
||||
while (entry) {
|
||||
if (entry->IsIncumbentCandidate()) {
|
||||
return entry->mGlobalObject;
|
||||
}
|
||||
entry = entry->mOlder;
|
||||
}
|
||||
return entry->mGlobalObject;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static ScriptSettingsStackEntry* EntryPoint() {
|
||||
ScriptSettingsStackEntry *entry = Top();
|
||||
if (!entry) {
|
||||
return nullptr;
|
||||
}
|
||||
while (entry) {
|
||||
if (entry->mIsCandidateEntryPoint)
|
||||
if (entry->IsEntryCandidate()) {
|
||||
return entry;
|
||||
}
|
||||
entry = entry->mOlder;
|
||||
}
|
||||
MOZ_CRASH("Non-empty stack should always have an entry point");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static nsIGlobalObject* EntryGlobal() {
|
||||
|
@ -79,6 +84,19 @@ public:
|
|||
return entry->mGlobalObject;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static ScriptSettingsStackEntry* TopNonIncumbentScript() {
|
||||
ScriptSettingsStackEntry *entry = Top();
|
||||
while (entry) {
|
||||
if (!entry->IsIncumbentScript()) {
|
||||
return entry;
|
||||
}
|
||||
entry = entry->mOlder;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
};
|
||||
|
||||
static unsigned long gRunToCompletionListeners = 0;
|
||||
|
@ -123,35 +141,23 @@ ScriptSettingsInitialized()
|
|||
}
|
||||
|
||||
ScriptSettingsStackEntry::ScriptSettingsStackEntry(nsIGlobalObject *aGlobal,
|
||||
bool aCandidate)
|
||||
Type aType)
|
||||
: mGlobalObject(aGlobal)
|
||||
, mIsCandidateEntryPoint(aCandidate)
|
||||
, mType(aType)
|
||||
, mOlder(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(mGlobalObject);
|
||||
MOZ_ASSERT(mGlobalObject->GetGlobalJSObject(),
|
||||
MOZ_ASSERT_IF(IsIncumbentCandidate() && !NoJSAPI(), mGlobalObject);
|
||||
MOZ_ASSERT(!mGlobalObject || mGlobalObject->GetGlobalJSObject(),
|
||||
"Must have an actual JS global for the duration on the stack");
|
||||
MOZ_ASSERT(JS_IsGlobalObject(mGlobalObject->GetGlobalJSObject()),
|
||||
MOZ_ASSERT(!mGlobalObject ||
|
||||
JS_IsGlobalObject(mGlobalObject->GetGlobalJSObject()),
|
||||
"No outer windows allowed");
|
||||
|
||||
ScriptSettingsStack::Push(this);
|
||||
}
|
||||
|
||||
// This constructor is only for use by AutoNoJSAPI.
|
||||
ScriptSettingsStackEntry::ScriptSettingsStackEntry()
|
||||
: mGlobalObject(nullptr)
|
||||
, mIsCandidateEntryPoint(true)
|
||||
, mOlder(nullptr)
|
||||
{
|
||||
ScriptSettingsStack::Push(this);
|
||||
}
|
||||
|
||||
ScriptSettingsStackEntry::~ScriptSettingsStackEntry()
|
||||
{
|
||||
// We must have an actual JS global for the entire time this is on the stack.
|
||||
MOZ_ASSERT_IF(mGlobalObject, mGlobalObject->GetGlobalJSObject());
|
||||
|
||||
ScriptSettingsStack::Pop(this);
|
||||
}
|
||||
|
||||
// If the entry or incumbent global ends up being something that the subject
|
||||
|
@ -271,8 +277,16 @@ GetWebIDLCallerPrincipal()
|
|||
return aes->mWebIDLCallerPrincipal;
|
||||
}
|
||||
|
||||
bool
|
||||
IsJSAPIActive()
|
||||
{
|
||||
ScriptSettingsStackEntry* topEntry = ScriptSettingsStack::Top();
|
||||
return topEntry && !topEntry->NoJSAPI();
|
||||
}
|
||||
|
||||
AutoJSAPI::AutoJSAPI()
|
||||
: mCx(nullptr)
|
||||
: ScriptSettingsStackEntry(nullptr, eJSAPI)
|
||||
, mCx(nullptr)
|
||||
, mIsMainThread(false) // For lack of anything better
|
||||
{
|
||||
}
|
||||
|
@ -282,7 +296,9 @@ AutoJSAPI::~AutoJSAPI()
|
|||
if (!mCx) {
|
||||
// No need to do anything here: we never managed to Init, so can't have an
|
||||
// exception on our (nonexistent) JSContext. We also don't need to restore
|
||||
// any state on it.
|
||||
// any state on it. Finally, we never made it to pushing outselves onto the
|
||||
// ScriptSettingsStack, so shouldn't pop.
|
||||
MOZ_ASSERT(ScriptSettingsStack::Top() != this);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -291,6 +307,13 @@ AutoJSAPI::~AutoJSAPI()
|
|||
if (mOldWarningReporter.isSome()) {
|
||||
JS::SetWarningReporter(JS_GetRuntime(cx()), mOldWarningReporter.value());
|
||||
}
|
||||
|
||||
// Leave the request before popping.
|
||||
if (mIsMainThread) {
|
||||
mAutoRequest.reset();
|
||||
}
|
||||
|
||||
ScriptSettingsStack::Pop(this);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -313,16 +336,14 @@ AutoJSAPI::InitInternal(nsIGlobalObject* aGlobalObject, JSObject* aGlobal,
|
|||
mIsMainThread = aIsMainThread;
|
||||
mGlobalObject = aGlobalObject;
|
||||
if (aIsMainThread) {
|
||||
// This Rooted<> is necessary only as long as AutoCxPusher::AutoCxPusher
|
||||
// can GC, which is only possible because XPCJSContextStack::Push calls
|
||||
// nsIPrincipal.Equals. Once that is removed, the Rooted<> will no longer
|
||||
// be necessary.
|
||||
JS::Rooted<JSObject*> global(JS_GetRuntime(aCx), aGlobal);
|
||||
mCxPusher.emplace(mCx);
|
||||
mAutoNullableCompartment.emplace(mCx, global);
|
||||
} else {
|
||||
mAutoNullableCompartment.emplace(mCx, aGlobal);
|
||||
// We _could_ just unconditionally emplace mAutoRequest here. It's just not
|
||||
// needed on worker threads, and we're hoping to kill it on the main thread
|
||||
// too.
|
||||
mAutoRequest.emplace(mCx);
|
||||
}
|
||||
mAutoNullableCompartment.emplace(mCx, aGlobal);
|
||||
|
||||
ScriptSettingsStack::Push(this);
|
||||
|
||||
JSRuntime* rt = JS_GetRuntime(aCx);
|
||||
mOldWarningReporter.emplace(JS::GetWarningReporter(rt));
|
||||
|
@ -398,8 +419,10 @@ AutoJSAPI::InitInternal(nsIGlobalObject* aGlobalObject, JSObject* aGlobal,
|
|||
|
||||
AutoJSAPI::AutoJSAPI(nsIGlobalObject* aGlobalObject,
|
||||
bool aIsMainThread,
|
||||
JSContext* aCx)
|
||||
: mIsMainThread(aIsMainThread)
|
||||
JSContext* aCx,
|
||||
Type aType)
|
||||
: ScriptSettingsStackEntry(aGlobalObject, aType)
|
||||
, mIsMainThread(aIsMainThread)
|
||||
{
|
||||
MOZ_ASSERT(aGlobalObject);
|
||||
MOZ_ASSERT(aGlobalObject->GetGlobalJSObject(), "Must have a JS global");
|
||||
|
@ -583,7 +606,7 @@ AutoJSAPI::ReportException()
|
|||
bool
|
||||
AutoJSAPI::PeekException(JS::MutableHandle<JS::Value> aVal)
|
||||
{
|
||||
MOZ_ASSERT_IF(mIsMainThread, CxPusherIsStackTop());
|
||||
MOZ_ASSERT_IF(mIsMainThread, IsStackTop());
|
||||
MOZ_ASSERT(HasException());
|
||||
MOZ_ASSERT(js::GetContextCompartment(cx()));
|
||||
if (!JS_GetPendingException(cx(), aVal)) {
|
||||
|
@ -602,13 +625,21 @@ AutoJSAPI::StealException(JS::MutableHandle<JS::Value> aVal)
|
|||
return true;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool
|
||||
AutoJSAPI::IsStackTop() const
|
||||
{
|
||||
return ScriptSettingsStack::TopNonIncumbentScript() == this;
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
AutoEntryScript::AutoEntryScript(nsIGlobalObject* aGlobalObject,
|
||||
const char *aReason,
|
||||
bool aIsMainThread,
|
||||
JSContext* aCx)
|
||||
: AutoJSAPI(aGlobalObject, aIsMainThread,
|
||||
aCx ? aCx : nsContentUtils::GetSafeJSContext())
|
||||
, ScriptSettingsStackEntry(aGlobalObject, /* aCandidate = */ true)
|
||||
aCx ? aCx : nsContentUtils::GetSafeJSContext(),
|
||||
eEntryScript)
|
||||
, mWebIDLCallerPrincipal(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(aGlobalObject);
|
||||
|
@ -712,66 +743,28 @@ AutoEntryScript::DocshellEntryMonitor::Exit(JSContext* aCx)
|
|||
}
|
||||
|
||||
AutoIncumbentScript::AutoIncumbentScript(nsIGlobalObject* aGlobalObject)
|
||||
: ScriptSettingsStackEntry(aGlobalObject, /* aCandidate = */ false)
|
||||
: ScriptSettingsStackEntry(aGlobalObject, eIncumbentScript)
|
||||
, mCallerOverride(nsContentUtils::GetCurrentJSContextForThread())
|
||||
{
|
||||
ScriptSettingsStack::Push(this);
|
||||
}
|
||||
|
||||
AutoNoJSAPI::AutoNoJSAPI(bool aIsMainThread)
|
||||
: ScriptSettingsStackEntry()
|
||||
AutoIncumbentScript::~AutoIncumbentScript()
|
||||
{
|
||||
if (aIsMainThread) {
|
||||
mCxPusher.emplace(static_cast<JSContext*>(nullptr),
|
||||
/* aAllowNull = */ true);
|
||||
}
|
||||
ScriptSettingsStack::Pop(this);
|
||||
}
|
||||
|
||||
danger::AutoCxPusher::AutoCxPusher(JSContext* cx, bool allowNull)
|
||||
AutoNoJSAPI::AutoNoJSAPI()
|
||||
: ScriptSettingsStackEntry(nullptr, eNoJSAPI)
|
||||
{
|
||||
MOZ_ASSERT_IF(!allowNull, cx);
|
||||
|
||||
XPCJSContextStack *stack = XPCJSRuntime::Get()->GetJSContextStack();
|
||||
stack->Push(cx);
|
||||
|
||||
#ifdef DEBUG
|
||||
mStackDepthAfterPush = stack->Count();
|
||||
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);
|
||||
}
|
||||
ScriptSettingsStack::Push(this);
|
||||
}
|
||||
|
||||
danger::AutoCxPusher::~AutoCxPusher()
|
||||
AutoNoJSAPI::~AutoNoJSAPI()
|
||||
{
|
||||
// Leave the request before popping.
|
||||
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));
|
||||
MOZ_ASSERT(mPushedContext == nsXPConnect::XPConnect()->GetCurrentJSContext());
|
||||
XPCJSRuntime::Get()->GetJSContextStack()->Pop();
|
||||
ScriptSettingsStack::Pop(this);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool
|
||||
danger::AutoCxPusher::IsStackTop() const
|
||||
{
|
||||
uint32_t currentDepth = XPCJSRuntime::Get()->GetJSContextStack()->Count();
|
||||
MOZ_ASSERT(currentDepth >= mStackDepthAfterPush);
|
||||
return currentDepth == mStackDepthAfterPush;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace dom
|
||||
|
||||
AutoJSContext::AutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
|
||||
|
@ -779,13 +772,13 @@ AutoJSContext::AutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
|
|||
{
|
||||
JS::AutoSuppressGCAnalysis nogc;
|
||||
MOZ_ASSERT(!mCx, "mCx should not be initialized!");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
|
||||
nsXPConnect *xpc = nsXPConnect::XPConnect();
|
||||
mCx = xpc->GetCurrentJSContext();
|
||||
|
||||
if (!mCx) {
|
||||
if (IsJSAPIActive()) {
|
||||
mCx = nsContentUtils::GetSafeJSContext();
|
||||
} else {
|
||||
mJSAPI.Init();
|
||||
mCx = mJSAPI.cx();
|
||||
}
|
||||
|
|
|
@ -27,34 +27,6 @@ class nsIDocShell;
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
// For internal use only - use AutoJSAPI instead.
|
||||
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();
|
||||
|
||||
// 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;
|
||||
#ifdef DEBUG
|
||||
uint32_t mStackDepthAfterPush;
|
||||
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).
|
||||
|
@ -150,6 +122,11 @@ inline JSObject& IncumbentJSGlobal()
|
|||
return *GetIncumbentGlobal()->GetGlobalJSObject();
|
||||
}
|
||||
|
||||
// Returns whether JSAPI is active right now. If it is not, working with a
|
||||
// JSContext you grab from somewhere random is not OK and you should be doing
|
||||
// AutoJSAPI or AutoEntryScript to get yourself a properly set up JSContext.
|
||||
bool IsJSAPIActive();
|
||||
|
||||
class ScriptSettingsStack;
|
||||
class ScriptSettingsStackEntry {
|
||||
friend class ScriptSettingsStack;
|
||||
|
@ -157,19 +134,28 @@ class ScriptSettingsStackEntry {
|
|||
public:
|
||||
~ScriptSettingsStackEntry();
|
||||
|
||||
bool NoJSAPI() { return !mGlobalObject; }
|
||||
bool NoJSAPI() const { return mType == eNoJSAPI; }
|
||||
bool IsEntryCandidate() const {
|
||||
return mType == eEntryScript || mType == eNoJSAPI;
|
||||
}
|
||||
bool IsIncumbentCandidate() { return mType != eJSAPI; }
|
||||
bool IsIncumbentScript() { return mType == eIncumbentScript; }
|
||||
|
||||
protected:
|
||||
ScriptSettingsStackEntry(nsIGlobalObject *aGlobal, bool aCandidate);
|
||||
enum Type {
|
||||
eEntryScript,
|
||||
eIncumbentScript,
|
||||
eJSAPI,
|
||||
eNoJSAPI
|
||||
};
|
||||
|
||||
ScriptSettingsStackEntry(nsIGlobalObject *aGlobal,
|
||||
Type aEntryType);
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> mGlobalObject;
|
||||
bool mIsCandidateEntryPoint;
|
||||
Type mType;
|
||||
|
||||
private:
|
||||
// This constructor is only for use by AutoNoJSAPI.
|
||||
friend class AutoNoJSAPI;
|
||||
ScriptSettingsStackEntry();
|
||||
|
||||
ScriptSettingsStackEntry *mOlder;
|
||||
};
|
||||
|
||||
|
@ -186,19 +172,15 @@ private:
|
|||
* the JSContext stack.
|
||||
* * Entering an initial (possibly null) compartment, to ensure that the
|
||||
* previously entered compartment for that JSContext is not used by mistake.
|
||||
* * Reporting any exceptions left on the JSRuntime, unless the caller steals
|
||||
* or silences them.
|
||||
* * On main thread, entering a JSAutoRequest.
|
||||
*
|
||||
* Additionally, the following duties are planned, but not yet implemented:
|
||||
*
|
||||
* * De-poisoning the JSRuntime to allow manipulation of JSAPI. We can't
|
||||
* actually implement this poisoning until all the JSContext pushing in the
|
||||
* system goes through AutoJSAPI (see bug 951991). For now, this de-poisoning
|
||||
* * De-poisoning the JSRuntime to allow manipulation of JSAPI. This requires
|
||||
* implementing the poisoning first. For now, this de-poisoning
|
||||
* effectively corresponds to having a non-null cx on the stack.
|
||||
* * Reporting any exceptions left on the JSRuntime, unless the caller steals
|
||||
* or silences them.
|
||||
* * Entering a JSAutoRequest. At present, this is handled by the cx pushing
|
||||
* on the main thread, and by other code on workers. Depending on the order
|
||||
* in which various cleanup lands, this may never be necessary, because
|
||||
* JSAutoRequests may go away.
|
||||
*
|
||||
* In situations where the consumer expects to run script, AutoEntryScript
|
||||
* should be used, which does additional manipulation of the script settings
|
||||
|
@ -207,7 +189,7 @@ private:
|
|||
* fail. This prevents system code from accidentally triggering script
|
||||
* execution at inopportune moments via surreptitious getters and proxies.
|
||||
*/
|
||||
class MOZ_STACK_CLASS AutoJSAPI {
|
||||
class MOZ_STACK_CLASS AutoJSAPI : protected ScriptSettingsStackEntry {
|
||||
public:
|
||||
// Trivial constructor. One of the Init functions must be called before
|
||||
// accessing the JSContext through cx().
|
||||
|
@ -258,19 +240,19 @@ public:
|
|||
|
||||
JSContext* cx() const {
|
||||
MOZ_ASSERT(mCx, "Must call Init before using an AutoJSAPI");
|
||||
MOZ_ASSERT_IF(mIsMainThread, CxPusherIsStackTop());
|
||||
MOZ_ASSERT(IsStackTop());
|
||||
return mCx;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool CxPusherIsStackTop() const { return mCxPusher->IsStackTop(); }
|
||||
bool IsStackTop() const;
|
||||
#endif
|
||||
|
||||
// If HasException, report it. Otherwise, a no-op.
|
||||
void ReportException();
|
||||
|
||||
bool HasException() const {
|
||||
MOZ_ASSERT_IF(NS_IsMainThread(), CxPusherIsStackTop());
|
||||
MOZ_ASSERT(IsStackTop());
|
||||
return JS_IsExceptionPending(cx());
|
||||
};
|
||||
|
||||
|
@ -291,7 +273,7 @@ public:
|
|||
bool PeekException(JS::MutableHandle<JS::Value> aVal);
|
||||
|
||||
void ClearException() {
|
||||
MOZ_ASSERT_IF(NS_IsMainThread(), CxPusherIsStackTop());
|
||||
MOZ_ASSERT(IsStackTop());
|
||||
JS_ClearPendingException(cx());
|
||||
}
|
||||
|
||||
|
@ -301,15 +283,11 @@ protected:
|
|||
// 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);
|
||||
AutoJSAPI(nsIGlobalObject* aGlobalObject, bool aIsMainThread, JSContext* aCx,
|
||||
Type aType);
|
||||
|
||||
private:
|
||||
// We need to hold a strong ref to our global object, so it won't go away
|
||||
// while we're being used. This _could_ become a JS::Rooted<JSObject*> if we
|
||||
// grabbed our JSContext in our constructor instead of waiting for Init(), so
|
||||
// we could construct this at that point. It might be worth it do to that.
|
||||
RefPtr<nsIGlobalObject> mGlobalObject;
|
||||
mozilla::Maybe<danger::AutoCxPusher> mCxPusher;
|
||||
mozilla::Maybe<JSAutoRequest> mAutoRequest;
|
||||
mozilla::Maybe<JSAutoNullableCompartment> mAutoNullableCompartment;
|
||||
JSContext *mCx;
|
||||
|
||||
|
@ -331,8 +309,7 @@ private:
|
|||
* invoking JavaScript code: "setTimeout", "event", and so on. The devtools use
|
||||
* these strings to label JS execution in timeline and profiling displays.
|
||||
*/
|
||||
class MOZ_STACK_CLASS AutoEntryScript : public AutoJSAPI,
|
||||
protected ScriptSettingsStackEntry {
|
||||
class MOZ_STACK_CLASS AutoEntryScript : public AutoJSAPI {
|
||||
public:
|
||||
AutoEntryScript(nsIGlobalObject* aGlobalObject,
|
||||
const char *aReason,
|
||||
|
@ -407,6 +384,8 @@ private:
|
|||
class AutoIncumbentScript : protected ScriptSettingsStackEntry {
|
||||
public:
|
||||
explicit AutoIncumbentScript(nsIGlobalObject* aGlobalObject);
|
||||
~AutoIncumbentScript();
|
||||
|
||||
private:
|
||||
JS::AutoHideScriptedCaller mCallerOverride;
|
||||
};
|
||||
|
@ -421,9 +400,8 @@ private:
|
|||
*/
|
||||
class AutoNoJSAPI : protected ScriptSettingsStackEntry {
|
||||
public:
|
||||
explicit AutoNoJSAPI(bool aIsMainThread = NS_IsMainThread());
|
||||
private:
|
||||
mozilla::Maybe<danger::AutoCxPusher> mCxPusher;
|
||||
explicit AutoNoJSAPI();
|
||||
~AutoNoJSAPI();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -5469,7 +5469,10 @@ nsContentUtils::GetCurrentJSContext()
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(IsInitialized());
|
||||
return sXPConnect->GetCurrentJSContext();
|
||||
if (!IsJSAPIActive()) {
|
||||
return nullptr;
|
||||
}
|
||||
return GetSafeJSContext();
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
|
|
@ -1338,7 +1338,6 @@ GK_ATOM(zeroDigit, "zero-digit")
|
|||
GK_ATOM(percentage, "%")
|
||||
GK_ATOM(A, "A")
|
||||
GK_ATOM(alignment_baseline, "alignment-baseline")
|
||||
GK_ATOM(allowReorder, "allowReorder")
|
||||
GK_ATOM(amplitude, "amplitude")
|
||||
GK_ATOM(animate, "animate")
|
||||
GK_ATOM(animateColor, "animateColor")
|
||||
|
|
|
@ -1991,6 +1991,13 @@ ContentParent::RecvDeallocateLayerTreeId(const uint64_t& aId)
|
|||
|
||||
namespace {
|
||||
|
||||
void
|
||||
DelayedDeleteSubprocess(GeckoChildProcessHost* aSubprocess)
|
||||
{
|
||||
RefPtr<DeleteTask<GeckoChildProcessHost>> task = new DeleteTask<GeckoChildProcessHost>(aSubprocess);
|
||||
XRE_GetIOMessageLoop()->PostTask(task.forget());
|
||||
}
|
||||
|
||||
// This runnable only exists to delegate ownership of the
|
||||
// ContentParent to this runnable, until it's deleted by the event
|
||||
// system.
|
||||
|
@ -2122,10 +2129,9 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
|
|||
}
|
||||
mIdleListeners.Clear();
|
||||
|
||||
if (mSubprocess) {
|
||||
mSubprocess->DissociateActor();
|
||||
mSubprocess = nullptr;
|
||||
}
|
||||
MessageLoop::current()->
|
||||
PostTask(NewRunnableFunction(DelayedDeleteSubprocess, mSubprocess));
|
||||
mSubprocess = nullptr;
|
||||
|
||||
// IPDL rules require actors to live on past ActorDestroy, but it
|
||||
// may be that the kungFuDeathGrip above is the last reference to
|
||||
|
@ -3321,7 +3327,7 @@ ContentParent::AllocPCompositorBridgeParent(mozilla::ipc::Transport* aTransport,
|
|||
base::ProcessId aOtherProcess)
|
||||
{
|
||||
return GPUProcessManager::Get()->CreateTabCompositorBridge(
|
||||
aTransport, aOtherProcess, mSubprocess);
|
||||
aTransport, aOtherProcess);
|
||||
}
|
||||
|
||||
gfx::PVRManagerParent*
|
||||
|
@ -3335,7 +3341,7 @@ PImageBridgeParent*
|
|||
ContentParent::AllocPImageBridgeParent(mozilla::ipc::Transport* aTransport,
|
||||
base::ProcessId aOtherProcess)
|
||||
{
|
||||
return ImageBridgeParent::Create(aTransport, aOtherProcess, mSubprocess);
|
||||
return ImageBridgeParent::Create(aTransport, aOtherProcess);
|
||||
}
|
||||
|
||||
PBackgroundParent*
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include "base/basictypes.h"
|
||||
#include "base/file_path.h"
|
||||
#include "base/thread.h"
|
||||
#include "base/waitable_event.h"
|
||||
#include "chrome/common/child_process_host.h"
|
||||
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
||||
|
||||
|
@ -35,7 +34,6 @@ public:
|
|||
bool CanShutdown() override { return true; }
|
||||
const std::string& GetPluginFilePath() { return mGMPPath; }
|
||||
|
||||
using mozilla::ipc::GeckoChildProcessHost::GetShutDownEvent;
|
||||
using mozilla::ipc::GeckoChildProcessHost::GetChannel;
|
||||
using mozilla::ipc::GeckoChildProcessHost::GetChildProcessHandle;
|
||||
|
||||
|
|
|
@ -23,6 +23,16 @@ add_task(function*() {
|
|||
|
||||
ok(time > 2000, "Interval is throttled with no webaudio (" + time + " ms)");
|
||||
|
||||
// Set up a listener for the oscillator's demise
|
||||
let oscillatorDemisePromise = ContentTask.spawn(browser, null, function() {
|
||||
return new Promise(resolve => {
|
||||
let observer = () => resolve();
|
||||
// Record the observer on the content object so we can throw it out later
|
||||
content.__bug1181073_observer = observer;
|
||||
Services.obs.addObserver(observer, "webaudio-node-demise", false);
|
||||
});
|
||||
});
|
||||
|
||||
time = yield ContentTask.spawn(browser, null, function () {
|
||||
return new Promise(resolve => {
|
||||
// Start playing audio, save it on the window so it doesn't get GCed
|
||||
|
@ -46,6 +56,7 @@ add_task(function*() {
|
|||
|
||||
// Destroy the oscillator, but not the audio context
|
||||
yield new Promise(resolve => SpecialPowers.exactGC(browser.contentWindow, resolve));
|
||||
yield oscillatorDemisePromise;
|
||||
|
||||
time = yield ContentTask.spawn(browser, null, function () {
|
||||
return new Promise(resolve => {
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "base/file_path.h"
|
||||
#include "base/task.h"
|
||||
#include "base/thread.h"
|
||||
#include "base/waitable_event.h"
|
||||
#include "chrome/common/child_process_host.h"
|
||||
|
||||
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
||||
|
@ -66,7 +65,6 @@ public:
|
|||
|
||||
const std::string& GetPluginFilePath() { return mPluginFilePath; }
|
||||
|
||||
using mozilla::ipc::GeckoChildProcessHost::GetShutDownEvent;
|
||||
using mozilla::ipc::GeckoChildProcessHost::GetChannel;
|
||||
|
||||
void SetCallRunnableImmediately(bool aCallImmediately);
|
||||
|
|
|
@ -127,14 +127,10 @@ SVGSwitchElement::IsAttributeMapped(const nsIAtom* name) const
|
|||
nsIContent *
|
||||
SVGSwitchElement::FindActiveChild() const
|
||||
{
|
||||
bool allowReorder = AttrValueIs(kNameSpaceID_None,
|
||||
nsGkAtoms::allowReorder,
|
||||
nsGkAtoms::yes, eCaseMatters);
|
||||
|
||||
const nsAdoptingString& acceptLangs =
|
||||
Preferences::GetLocalizedString("intl.accept_languages");
|
||||
|
||||
if (allowReorder && !acceptLangs.IsEmpty()) {
|
||||
if (!acceptLangs.IsEmpty()) {
|
||||
int32_t bestLanguagePreferenceRank = -1;
|
||||
nsIContent *bestChild = nullptr;
|
||||
nsIContent *defaultChild = nullptr;
|
||||
|
|
|
@ -58,21 +58,7 @@ function run1()
|
|||
var second = doc.getElementById("second");
|
||||
var third = doc.getElementById("third");
|
||||
|
||||
/* test for an exact match */
|
||||
second.setAttribute("systemLanguage", "en-gb");
|
||||
checkBounds(s, 75, 100, 50, 50);
|
||||
|
||||
/* test for a close match i.e. the same language prefix */
|
||||
second.setAttribute("systemLanguage", "en-us");
|
||||
checkWidth(s, 50);
|
||||
|
||||
/* test that we pick the first match */
|
||||
first.setAttribute("systemLanguage", "it");
|
||||
checkWidth(s, 70);
|
||||
|
||||
/* this time with reordering */
|
||||
first.setAttribute("systemLanguage", "fr");
|
||||
s.setAttribute("allowReorder", "yes");
|
||||
|
||||
/* test for an exact match */
|
||||
second.setAttribute("systemLanguage", "en-gb");
|
||||
|
|
|
@ -32,13 +32,17 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(PlaceholderTxn)
|
|||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PlaceholderTxn,
|
||||
EditAggregateTxn)
|
||||
ImplCycleCollectionUnlink(*tmp->mStartSel);
|
||||
if (tmp->mStartSel) {
|
||||
ImplCycleCollectionUnlink(*tmp->mStartSel);
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEndSel);
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PlaceholderTxn,
|
||||
EditAggregateTxn)
|
||||
ImplCycleCollectionTraverse(cb, *tmp->mStartSel, "mStartSel", 0);
|
||||
if (tmp->mStartSel) {
|
||||
ImplCycleCollectionTraverse(cb, *tmp->mStartSel, "mStartSel", 0);
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEndSel);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
|
|
|
@ -192,6 +192,13 @@ GPUProcessHost::KillHard(const char* aReason)
|
|||
NewRunnableFunction(&ProcessWatcher::EnsureProcessTerminated, handle, /*force=*/true));
|
||||
}
|
||||
|
||||
static void
|
||||
DelayedDeleteSubprocess(GeckoChildProcessHost* aSubprocess)
|
||||
{
|
||||
XRE_GetIOMessageLoop()->
|
||||
PostTask(mozilla::MakeAndAddRef<DeleteTask<GeckoChildProcessHost>>(aSubprocess));
|
||||
}
|
||||
|
||||
void
|
||||
GPUProcessHost::DestroyProcess()
|
||||
{
|
||||
|
@ -202,7 +209,8 @@ GPUProcessHost::DestroyProcess()
|
|||
mTaskFactory.RevokeAll();
|
||||
}
|
||||
|
||||
DissociateActor();
|
||||
MessageLoop::current()->
|
||||
PostTask(NewRunnableFunction(DelayedDeleteSubprocess, this));
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
|
|
|
@ -170,10 +170,9 @@ GPUProcessManager::CreateTopLevelCompositor(widget::CompositorWidgetProxy* aProx
|
|||
|
||||
PCompositorBridgeParent*
|
||||
GPUProcessManager::CreateTabCompositorBridge(ipc::Transport* aTransport,
|
||||
base::ProcessId aOtherProcess,
|
||||
ipc::GeckoChildProcessHost* aSubprocess)
|
||||
base::ProcessId aOtherProcess)
|
||||
{
|
||||
return CompositorBridgeParent::Create(aTransport, aOtherProcess, aSubprocess);
|
||||
return CompositorBridgeParent::Create(aTransport, aOtherProcess);
|
||||
}
|
||||
|
||||
already_AddRefed<APZCTreeManager>
|
||||
|
|
|
@ -70,8 +70,7 @@ public:
|
|||
|
||||
layers::PCompositorBridgeParent* CreateTabCompositorBridge(
|
||||
ipc::Transport* aTransport,
|
||||
base::ProcessId aOtherProcess,
|
||||
ipc::GeckoChildProcessHost* aSubprocess);
|
||||
base::ProcessId aOtherProcess);
|
||||
|
||||
// This returns a reference to the APZCTreeManager to which
|
||||
// pan/zoom-related events can be sent.
|
||||
|
|
|
@ -68,7 +68,6 @@
|
|||
#endif
|
||||
#include "GeckoProfiler.h"
|
||||
#include "mozilla/ipc/ProtocolTypes.h"
|
||||
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/Hal.h"
|
||||
#include "mozilla/HalTypes.h"
|
||||
|
@ -1819,7 +1818,6 @@ public:
|
|||
explicit CrossProcessCompositorBridgeParent(Transport* aTransport)
|
||||
: CompositorBridgeParentIPCAllocator("CrossProcessCompositorBridgeParent")
|
||||
, mTransport(aTransport)
|
||||
, mSubprocess(nullptr)
|
||||
, mNotifyAfterRemotePaint(false)
|
||||
, mDestroyCalled(false)
|
||||
{
|
||||
|
@ -1998,7 +1996,6 @@ private:
|
|||
// ourself. This is released (deferred) in ActorDestroy().
|
||||
RefPtr<CrossProcessCompositorBridgeParent> mSelfRef;
|
||||
Transport* mTransport;
|
||||
ipc::GeckoChildProcessHost* mSubprocess;
|
||||
|
||||
RefPtr<CompositorThreadHolder> mCompositorThreadHolder;
|
||||
// If true, we should send a RemotePaintIsReady message when the layer transaction
|
||||
|
@ -2158,18 +2155,13 @@ OpenCompositor(CrossProcessCompositorBridgeParent* aCompositor,
|
|||
}
|
||||
|
||||
/*static*/ PCompositorBridgeParent*
|
||||
CompositorBridgeParent::Create(Transport* aTransport, ProcessId aOtherPid, GeckoChildProcessHost* aProcessHost)
|
||||
CompositorBridgeParent::Create(Transport* aTransport, ProcessId aOtherPid)
|
||||
{
|
||||
gfxPlatform::InitLayersIPC();
|
||||
|
||||
RefPtr<CrossProcessCompositorBridgeParent> cpcp =
|
||||
new CrossProcessCompositorBridgeParent(aTransport);
|
||||
|
||||
if (aProcessHost) {
|
||||
cpcp->mSubprocess = aProcessHost;
|
||||
aProcessHost->AssociateActor();
|
||||
}
|
||||
|
||||
cpcp->mSelfRef = cpcp;
|
||||
CompositorLoop()->PostTask(
|
||||
NewRunnableFunction(OpenCompositor, cpcp.get(),
|
||||
|
@ -2277,11 +2269,6 @@ CrossProcessCompositorBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
|
|||
RefPtr<CompositorLRU> lru = CompositorLRU::GetSingleton();
|
||||
lru->Remove(this);
|
||||
|
||||
if (mSubprocess) {
|
||||
mSubprocess->DissociateActor();
|
||||
mSubprocess = nullptr;
|
||||
}
|
||||
|
||||
// We must keep this object alive untill the code handling message
|
||||
// reception is finished on this thread.
|
||||
MessageLoop::current()->PostTask(NewRunnableMethod(this, &CrossProcessCompositorBridgeParent::DeferredDestroy));
|
||||
|
@ -2758,7 +2745,7 @@ CrossProcessCompositorBridgeParent::CloneToplevel(
|
|||
Transport* transport = OpenDescriptor(aFds[i].fd(),
|
||||
Transport::MODE_SERVER);
|
||||
PCompositorBridgeParent* compositor =
|
||||
CompositorBridgeParent::Create(transport, base::GetProcId(aPeerProcess), mSubprocess);
|
||||
CompositorBridgeParent::Create(transport, base::GetProcId(aPeerProcess));
|
||||
compositor->CloneManagees(this, aCtx);
|
||||
compositor->IToplevelProtocol::SetTransport(transport);
|
||||
// The reference to the compositor thread is held in OnChannelConnected().
|
||||
|
|
|
@ -51,7 +51,6 @@ class GPUProcessManager;
|
|||
} // namespace gfx
|
||||
|
||||
namespace ipc {
|
||||
class GeckoChildProcessHost;
|
||||
class Shmem;
|
||||
} // namespace ipc
|
||||
|
||||
|
@ -400,7 +399,7 @@ public:
|
|||
* directly to us. Transport is to its thread context.
|
||||
*/
|
||||
static PCompositorBridgeParent*
|
||||
Create(Transport* aTransport, ProcessId aOtherProcess, mozilla::ipc::GeckoChildProcessHost* aProcessHost);
|
||||
Create(Transport* aTransport, ProcessId aOtherProcess);
|
||||
|
||||
struct LayerTreeState {
|
||||
LayerTreeState();
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
|
||||
#include "mozilla/ipc/ProtocolUtils.h"
|
||||
#include "mozilla/ipc/Transport.h" // for Transport
|
||||
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
||||
#include "mozilla/media/MediaSystemResourceManagerParent.h" // for MediaSystemResourceManagerParent
|
||||
#include "mozilla/layers/CompositableTransactionParent.h"
|
||||
#include "mozilla/layers/LayerManagerComposite.h"
|
||||
|
@ -58,7 +57,6 @@ ImageBridgeParent::ImageBridgeParent(MessageLoop* aLoop,
|
|||
, mTransport(aTransport)
|
||||
, mSetChildThreadPriority(false)
|
||||
, mClosed(false)
|
||||
, mSubprocess(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
sMainLoop = MessageLoop::current();
|
||||
|
@ -100,11 +98,6 @@ ImageBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
|
|||
// Can't alloc/dealloc shmems from now on.
|
||||
mClosed = true;
|
||||
|
||||
if (mSubprocess) {
|
||||
mSubprocess->DissociateActor();
|
||||
mSubprocess = nullptr;
|
||||
}
|
||||
|
||||
MessageLoop::current()->PostTask(NewRunnableMethod(this, &ImageBridgeParent::DeferredDestroy));
|
||||
|
||||
// It is very important that this method gets called at shutdown (be it a clean
|
||||
|
@ -203,16 +196,11 @@ ConnectImageBridgeInParentProcess(ImageBridgeParent* aBridge,
|
|||
}
|
||||
|
||||
/*static*/ PImageBridgeParent*
|
||||
ImageBridgeParent::Create(Transport* aTransport, ProcessId aChildProcessId, GeckoChildProcessHost* aProcessHost)
|
||||
ImageBridgeParent::Create(Transport* aTransport, ProcessId aChildProcessId)
|
||||
{
|
||||
MessageLoop* loop = CompositorThreadHolder::Loop();
|
||||
RefPtr<ImageBridgeParent> bridge = new ImageBridgeParent(loop, aTransport, aChildProcessId);
|
||||
|
||||
if (aProcessHost) {
|
||||
bridge->mSubprocess = aProcessHost;
|
||||
aProcessHost->AssociateActor();
|
||||
}
|
||||
|
||||
loop->PostTask(NewRunnableFunction(ConnectImageBridgeInParentProcess,
|
||||
bridge.get(), aTransport, aChildProcessId));
|
||||
return bridge.get();
|
||||
|
@ -369,7 +357,7 @@ ImageBridgeParent::CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds
|
|||
if (aFds[i].protocolId() == unsigned(GetProtocolId())) {
|
||||
Transport* transport = OpenDescriptor(aFds[i].fd(),
|
||||
Transport::MODE_SERVER);
|
||||
PImageBridgeParent* bridge = Create(transport, base::GetProcId(aPeerProcess), mSubprocess);
|
||||
PImageBridgeParent* bridge = Create(transport, base::GetProcId(aPeerProcess));
|
||||
bridge->CloneManagees(this, aCtx);
|
||||
bridge->IToplevelProtocol::SetTransport(transport);
|
||||
// The reference to the compositor thread is held in OnChannelConnected().
|
||||
|
|
|
@ -28,7 +28,6 @@ class Thread;
|
|||
namespace mozilla {
|
||||
namespace ipc {
|
||||
class Shmem;
|
||||
class GeckoChildProcessHost;
|
||||
} // namespace ipc
|
||||
|
||||
namespace layers {
|
||||
|
@ -55,7 +54,7 @@ public:
|
|||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
static PImageBridgeParent*
|
||||
Create(Transport* aTransport, ProcessId aChildProcessId, ipc::GeckoChildProcessHost* aProcessHost);
|
||||
Create(Transport* aTransport, ProcessId aChildProcessId);
|
||||
|
||||
// CompositableParentManager
|
||||
virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) override;
|
||||
|
@ -155,8 +154,6 @@ private:
|
|||
bool mSetChildThreadPriority;
|
||||
bool mClosed;
|
||||
|
||||
ipc::GeckoChildProcessHost* mSubprocess;
|
||||
|
||||
/**
|
||||
* Map of all living ImageBridgeParent instances
|
||||
*/
|
||||
|
|
|
@ -16,7 +16,11 @@ namespace mozilla {
|
|||
namespace gfx {
|
||||
|
||||
# if defined(MOZILLA_MAY_SUPPORT_NEON)
|
||||
# if defined(__clang__)
|
||||
void __attribute((noinline))
|
||||
# else
|
||||
void __attribute((noinline,optimize("-fomit-frame-pointer")))
|
||||
# endif
|
||||
yuv42x_to_rgb565_row_neon(uint16 *dst,
|
||||
const uint8 *y,
|
||||
const uint8 *u,
|
||||
|
|
|
@ -27,12 +27,10 @@ UNIFIED_SOURCES += [
|
|||
'src/base/timer.cc',
|
||||
'src/chrome/common/child_process.cc',
|
||||
'src/chrome/common/child_process_host.cc',
|
||||
'src/chrome/common/child_process_info.cc',
|
||||
'src/chrome/common/child_thread.cc',
|
||||
'src/chrome/common/chrome_switches.cc',
|
||||
'src/chrome/common/ipc_channel.cc',
|
||||
'src/chrome/common/ipc_message.cc',
|
||||
'src/chrome/common/notification_service.cc',
|
||||
]
|
||||
|
||||
if os_win:
|
||||
|
@ -54,7 +52,6 @@ if os_win:
|
|||
'src/base/thread_local_storage_win.cc',
|
||||
'src/base/thread_local_win.cc',
|
||||
'src/base/time_win.cc',
|
||||
'src/base/waitable_event_watcher_win.cc',
|
||||
'src/base/waitable_event_win.cc',
|
||||
'src/base/win_util.cc',
|
||||
'src/chrome/common/ipc_channel_win.cc',
|
||||
|
@ -82,7 +79,6 @@ if os_posix:
|
|||
'src/base/thread_local_posix.cc',
|
||||
'src/base/thread_local_storage_posix.cc',
|
||||
'src/base/waitable_event_posix.cc',
|
||||
'src/base/waitable_event_watcher_posix.cc',
|
||||
'src/chrome/common/file_descriptor_set_posix.cc',
|
||||
'src/chrome/common/ipc_channel_posix.cc',
|
||||
'src/chrome/common/process_watcher_posix_sigchld.cc',
|
||||
|
|
|
@ -54,16 +54,6 @@ class WaitableEvent {
|
|||
// waiting thread has been released.
|
||||
WaitableEvent(bool manual_reset, bool initially_signaled);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Create a WaitableEvent from an Event HANDLE which has already been
|
||||
// created. This objects takes ownership of the HANDLE and will close it when
|
||||
// deleted.
|
||||
explicit WaitableEvent(HANDLE event_handle);
|
||||
|
||||
// Releases ownership of the handle from this object.
|
||||
HANDLE Release();
|
||||
#endif
|
||||
|
||||
~WaitableEvent();
|
||||
|
||||
// Put the event in the un-signaled state.
|
||||
|
|
|
@ -1,156 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_WAITABLE_EVENT_WATCHER_H_
|
||||
#define BASE_WAITABLE_EVENT_WATCHER_H_
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "base/object_watcher.h"
|
||||
#else
|
||||
#include "base/message_loop.h"
|
||||
#include "base/waitable_event.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
|
||||
class Flag;
|
||||
class AsyncWaiter;
|
||||
class AsyncCallbackTask;
|
||||
class WaitableEvent;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// This class provides a way to wait on a WaitableEvent asynchronously.
|
||||
//
|
||||
// Each instance of this object can be waiting on a single WaitableEvent. When
|
||||
// the waitable event is signaled, a callback is made in the thread of a given
|
||||
// MessageLoop. This callback can be deleted by deleting the waiter.
|
||||
//
|
||||
// Typical usage:
|
||||
//
|
||||
// class MyClass : public base::WaitableEventWatcher::Delegate {
|
||||
// public:
|
||||
// void DoStuffWhenSignaled(WaitableEvent *waitable_event) {
|
||||
// watcher_.StartWatching(waitable_event, this);
|
||||
// }
|
||||
// virtual void OnWaitableEventSignaled(WaitableEvent* waitable_event) {
|
||||
// // OK, time to do stuff!
|
||||
// }
|
||||
// private:
|
||||
// base::WaitableEventWatcher watcher_;
|
||||
// };
|
||||
//
|
||||
// In the above example, MyClass wants to "do stuff" when waitable_event
|
||||
// becomes signaled. WaitableEventWatcher makes this task easy. When MyClass
|
||||
// goes out of scope, the watcher_ will be destroyed, and there is no need to
|
||||
// worry about OnWaitableEventSignaled being called on a deleted MyClass
|
||||
// pointer.
|
||||
//
|
||||
// BEWARE: With automatically reset WaitableEvents, a signal may be lost if it
|
||||
// occurs just before a WaitableEventWatcher is deleted. There is currently no
|
||||
// safe way to stop watching an automatic reset WaitableEvent without possibly
|
||||
// missing a signal.
|
||||
//
|
||||
// NOTE: you /are/ allowed to delete the WaitableEvent while still waiting on
|
||||
// it with a Watcher. It will act as if the event was never signaled.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class WaitableEventWatcher
|
||||
#if defined(OS_POSIX)
|
||||
: public MessageLoop::DestructionObserver
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
|
||||
WaitableEventWatcher();
|
||||
~WaitableEventWatcher();
|
||||
|
||||
class Delegate {
|
||||
public:
|
||||
virtual ~Delegate() { }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// This is called on the MessageLoop thread when WaitableEvent has been
|
||||
// signaled.
|
||||
//
|
||||
// Note: the event may not be signaled by the time that this function is
|
||||
// called. This indicates only that it has been signaled at some point in
|
||||
// the past.
|
||||
// -------------------------------------------------------------------------
|
||||
virtual void OnWaitableEventSignaled(WaitableEvent* waitable_event) = 0;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// When @event is signaled, the given delegate is called on the thread of the
|
||||
// current message loop when StartWatching is called. The delegate is not
|
||||
// deleted.
|
||||
// ---------------------------------------------------------------------------
|
||||
bool StartWatching(WaitableEvent* event, Delegate* delegate);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Cancel the current watch. Must be called from the same thread which
|
||||
// started the watch.
|
||||
//
|
||||
// Does nothing if no event is being watched, nor if the watch has completed.
|
||||
// The delegate will *not* be called for the current watch after this
|
||||
// function returns. Since the delegate runs on the same thread as this
|
||||
// function, it cannot be called during this function either.
|
||||
// ---------------------------------------------------------------------------
|
||||
void StopWatching();
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Return the currently watched event, or NULL if no object is currently being
|
||||
// watched.
|
||||
// ---------------------------------------------------------------------------
|
||||
WaitableEvent* GetWatchedEvent();
|
||||
|
||||
private:
|
||||
WaitableEvent* event_;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// ---------------------------------------------------------------------------
|
||||
// The helper class exists because, if WaitableEventWatcher were to inherit
|
||||
// from ObjectWatcher::Delegate, then it couldn't also have an inner class
|
||||
// called Delegate (at least on Windows). Thus this object exists to proxy
|
||||
// the callback function
|
||||
// ---------------------------------------------------------------------------
|
||||
class ObjectWatcherHelper : public ObjectWatcher::Delegate {
|
||||
public:
|
||||
ObjectWatcherHelper(WaitableEventWatcher* watcher);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Implementation of ObjectWatcher::Delegate
|
||||
// -------------------------------------------------------------------------
|
||||
void OnObjectSignaled(HANDLE h);
|
||||
|
||||
private:
|
||||
WaitableEventWatcher *const watcher_;
|
||||
};
|
||||
|
||||
void OnObjectSignaled();
|
||||
|
||||
Delegate* delegate_;
|
||||
ObjectWatcherHelper helper_;
|
||||
ObjectWatcher watcher_;
|
||||
#else
|
||||
// ---------------------------------------------------------------------------
|
||||
// Implementation of MessageLoop::DestructionObserver
|
||||
// ---------------------------------------------------------------------------
|
||||
void WillDestroyCurrentMessageLoop();
|
||||
|
||||
MessageLoop* message_loop_;
|
||||
RefPtr<Flag> cancel_flag_;
|
||||
AsyncWaiter* waiter_;
|
||||
RefPtr<AsyncCallbackTask> callback_task_;
|
||||
RefPtr<WaitableEvent::WaitableEventKernel> kernel_;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_WAITABLE_EVENT_WATCHER_H_
|
|
@ -1,287 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/waitable_event_watcher.h"
|
||||
|
||||
#include "base/condition_variable.h"
|
||||
#include "base/lock.h"
|
||||
#include "base/message_loop.h"
|
||||
#include "base/waitable_event.h"
|
||||
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// WaitableEventWatcher (async waits).
|
||||
//
|
||||
// The basic design is that we add an AsyncWaiter to the wait-list of the event.
|
||||
// That AsyncWaiter has a pointer to MessageLoop, and a Task to be posted to it.
|
||||
// The MessageLoop ends up running the task, which calls the delegate.
|
||||
//
|
||||
// Since the wait can be canceled, we have a thread-safe Flag object which is
|
||||
// set when the wait has been canceled. At each stage in the above, we check the
|
||||
// flag before going onto the next stage. Since the wait may only be canceled in
|
||||
// the MessageLoop which runs the Task, we are assured that the delegate cannot
|
||||
// be called after canceling...
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// A thread-safe, reference-counted, write-once flag.
|
||||
// -----------------------------------------------------------------------------
|
||||
class Flag final {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Flag)
|
||||
Flag() { flag_ = false; }
|
||||
|
||||
void Set() {
|
||||
AutoLock locked(lock_);
|
||||
flag_ = true;
|
||||
}
|
||||
|
||||
bool value() const {
|
||||
AutoLock locked(lock_);
|
||||
return flag_;
|
||||
}
|
||||
|
||||
protected:
|
||||
~Flag() {}
|
||||
private:
|
||||
mutable Lock lock_;
|
||||
bool flag_;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// This is an asynchronous waiter which posts a task to a MessageLoop when
|
||||
// fired. An AsyncWaiter may only be in a single wait-list.
|
||||
// -----------------------------------------------------------------------------
|
||||
class AsyncWaiter final : public WaitableEvent::Waiter {
|
||||
public:
|
||||
AsyncWaiter(MessageLoop* message_loop,
|
||||
already_AddRefed<mozilla::Runnable> task, Flag* flag)
|
||||
: message_loop_(message_loop),
|
||||
cb_task_(task),
|
||||
flag_(flag) { }
|
||||
|
||||
bool Fire(WaitableEvent* event) {
|
||||
if (flag_->value()) {
|
||||
// If the callback has been canceled, we don't enqueue the task, we just
|
||||
// delete it instead.
|
||||
cb_task_ = nullptr;
|
||||
} else {
|
||||
message_loop_->PostTask(cb_task_.forget());
|
||||
}
|
||||
|
||||
// We are removed from the wait-list by the WaitableEvent itself. It only
|
||||
// remains to delete ourselves.
|
||||
delete this;
|
||||
|
||||
// We can always return true because an AsyncWaiter is never in two
|
||||
// different wait-lists at the same time.
|
||||
return true;
|
||||
}
|
||||
|
||||
// See StopWatching for discussion
|
||||
bool Compare(void* tag) {
|
||||
return tag == flag_.get();
|
||||
}
|
||||
|
||||
private:
|
||||
MessageLoop *const message_loop_;
|
||||
RefPtr<mozilla::Runnable> cb_task_;
|
||||
RefPtr<Flag> flag_;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// For async waits we need to make a callback in a MessageLoop thread. We do
|
||||
// this by posting this task, which calls the delegate and keeps track of when
|
||||
// the event is canceled.
|
||||
// -----------------------------------------------------------------------------
|
||||
class AsyncCallbackTask : public mozilla::Runnable {
|
||||
public:
|
||||
AsyncCallbackTask(Flag* flag, WaitableEventWatcher::Delegate* delegate,
|
||||
WaitableEvent* event)
|
||||
: flag_(flag),
|
||||
delegate_(delegate),
|
||||
event_(event) {
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override {
|
||||
// Runs in MessageLoop thread.
|
||||
if (!flag_->value()) {
|
||||
// This is to let the WaitableEventWatcher know that the event has occured
|
||||
// because it needs to be able to return NULL from GetWatchedObject
|
||||
flag_->Set();
|
||||
delegate_->OnWaitableEventSignaled(event_);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
// We are deleted by the MessageLoop
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<Flag> flag_;
|
||||
WaitableEventWatcher::Delegate *const delegate_;
|
||||
WaitableEvent *const event_;
|
||||
};
|
||||
|
||||
WaitableEventWatcher::WaitableEventWatcher()
|
||||
: event_(NULL),
|
||||
message_loop_(NULL),
|
||||
cancel_flag_(NULL) {
|
||||
}
|
||||
|
||||
WaitableEventWatcher::~WaitableEventWatcher() {
|
||||
StopWatching();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// The Handle is how the user cancels a wait. After deleting the Handle we
|
||||
// insure that the delegate cannot be called.
|
||||
// -----------------------------------------------------------------------------
|
||||
bool WaitableEventWatcher::StartWatching
|
||||
(WaitableEvent* event, WaitableEventWatcher::Delegate* delegate) {
|
||||
MessageLoop *const current_ml = MessageLoop::current();
|
||||
DCHECK(current_ml) << "Cannot create WaitableEventWatcher without a "
|
||||
"current MessageLoop";
|
||||
|
||||
// A user may call StartWatching from within the callback function. In this
|
||||
// case, we won't know that we have finished watching, expect that the Flag
|
||||
// will have been set in AsyncCallbackTask::Run()
|
||||
if (cancel_flag_.get() && cancel_flag_->value()) {
|
||||
if (message_loop_) {
|
||||
message_loop_->RemoveDestructionObserver(this);
|
||||
message_loop_ = NULL;
|
||||
}
|
||||
|
||||
cancel_flag_ = NULL;
|
||||
}
|
||||
|
||||
DCHECK(!cancel_flag_.get()) << "StartWatching called while still watching";
|
||||
|
||||
cancel_flag_ = new Flag;
|
||||
callback_task_ = new AsyncCallbackTask(cancel_flag_, delegate, event);
|
||||
WaitableEvent::WaitableEventKernel* kernel = event->kernel_.get();
|
||||
|
||||
AutoLock locked(kernel->lock_);
|
||||
|
||||
if (kernel->signaled_) {
|
||||
if (!kernel->manual_reset_)
|
||||
kernel->signaled_ = false;
|
||||
|
||||
// No hairpinning - we can't call the delegate directly here. We have to
|
||||
// enqueue a task on the MessageLoop as normal.
|
||||
RefPtr<AsyncCallbackTask> addrefedTask = callback_task_;
|
||||
current_ml->PostTask(addrefedTask.forget());
|
||||
return true;
|
||||
}
|
||||
|
||||
message_loop_ = current_ml;
|
||||
current_ml->AddDestructionObserver(this);
|
||||
|
||||
event_ = event;
|
||||
kernel_ = kernel;
|
||||
RefPtr<AsyncCallbackTask> addrefedTask = callback_task_;
|
||||
waiter_ = new AsyncWaiter(current_ml, addrefedTask.forget(), cancel_flag_);
|
||||
event->Enqueue(waiter_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WaitableEventWatcher::StopWatching() {
|
||||
if (message_loop_) {
|
||||
message_loop_->RemoveDestructionObserver(this);
|
||||
message_loop_ = NULL;
|
||||
}
|
||||
|
||||
if (!cancel_flag_.get()) // if not currently watching...
|
||||
return;
|
||||
|
||||
if (cancel_flag_->value()) {
|
||||
// In this case, the event has fired, but we haven't figured that out yet.
|
||||
// The WaitableEvent may have been deleted too.
|
||||
cancel_flag_ = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!kernel_.get()) {
|
||||
// We have no kernel. This means that we never enqueued a Waiter on an
|
||||
// event because the event was already signaled when StartWatching was
|
||||
// called.
|
||||
//
|
||||
// In this case, a task was enqueued on the MessageLoop and will run.
|
||||
// We set the flag in case the task hasn't yet run. The flag will stop the
|
||||
// delegate getting called. If the task has run then we have the last
|
||||
// reference to the flag and it will be deleted immedately after.
|
||||
cancel_flag_->Set();
|
||||
cancel_flag_ = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
AutoLock locked(kernel_->lock_);
|
||||
// We have a lock on the kernel. No one else can signal the event while we
|
||||
// have it.
|
||||
|
||||
// We have a possible ABA issue here. If Dequeue was to compare only the
|
||||
// pointer values then it's possible that the AsyncWaiter could have been
|
||||
// fired, freed and the memory reused for a different Waiter which was
|
||||
// enqueued in the same wait-list. We would think that that waiter was our
|
||||
// AsyncWaiter and remove it.
|
||||
//
|
||||
// To stop this, Dequeue also takes a tag argument which is passed to the
|
||||
// virtual Compare function before the two are considered a match. So we need
|
||||
// a tag which is good for the lifetime of this handle: the Flag. Since we
|
||||
// have a reference to the Flag, its memory cannot be reused while this object
|
||||
// still exists. So if we find a waiter with the correct pointer value, and
|
||||
// which shares a Flag pointer, we have a real match.
|
||||
if (kernel_->Dequeue(waiter_, cancel_flag_.get())) {
|
||||
// Case 2: the waiter hasn't been signaled yet; it was still on the wait
|
||||
// list. We've removed it, thus we can delete it and the task (which cannot
|
||||
// have been enqueued with the MessageLoop because the waiter was never
|
||||
// signaled)
|
||||
delete waiter_;
|
||||
callback_task_ = nullptr;
|
||||
cancel_flag_ = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// Case 3: the waiter isn't on the wait-list, thus it was signaled. It may
|
||||
// not have run yet, so we set the flag to tell it not to bother enqueuing the
|
||||
// task on the MessageLoop, but to delete it instead. The Waiter deletes
|
||||
// itself once run.
|
||||
cancel_flag_->Set();
|
||||
cancel_flag_ = NULL;
|
||||
|
||||
// If the waiter has already run then the task has been enqueued. If the Task
|
||||
// hasn't yet run, the flag will stop the delegate from getting called. (This
|
||||
// is thread safe because one may only delete a Handle from the MessageLoop
|
||||
// thread.)
|
||||
//
|
||||
// If the delegate has already been called then we have nothing to do. The
|
||||
// task has been deleted by the MessageLoop.
|
||||
}
|
||||
|
||||
WaitableEvent* WaitableEventWatcher::GetWatchedEvent() {
|
||||
if (!cancel_flag_.get())
|
||||
return NULL;
|
||||
|
||||
if (cancel_flag_->value())
|
||||
return NULL;
|
||||
|
||||
return event_;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// This is called when the MessageLoop which the callback will be run it is
|
||||
// deleted. We need to cancel the callback as if we had been deleted, but we
|
||||
// will still be deleted at some point in the future.
|
||||
// -----------------------------------------------------------------------------
|
||||
void WaitableEventWatcher::WillDestroyCurrentMessageLoop() {
|
||||
StopWatching();
|
||||
}
|
||||
|
||||
} // namespace base
|
|
@ -1,62 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/waitable_event_watcher.h"
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/object_watcher.h"
|
||||
#include "base/waitable_event.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
WaitableEventWatcher::ObjectWatcherHelper::ObjectWatcherHelper(
|
||||
WaitableEventWatcher* watcher)
|
||||
: watcher_(watcher) {
|
||||
};
|
||||
|
||||
void WaitableEventWatcher::ObjectWatcherHelper::OnObjectSignaled(HANDLE h) {
|
||||
watcher_->OnObjectSignaled();
|
||||
}
|
||||
|
||||
|
||||
WaitableEventWatcher::WaitableEventWatcher()
|
||||
: event_(NULL),
|
||||
ALLOW_THIS_IN_INITIALIZER_LIST(helper_(this)),
|
||||
delegate_(NULL) {
|
||||
}
|
||||
|
||||
WaitableEventWatcher::~WaitableEventWatcher() {
|
||||
}
|
||||
|
||||
bool WaitableEventWatcher::StartWatching(WaitableEvent* event,
|
||||
Delegate* delegate) {
|
||||
delegate_ = delegate;
|
||||
event_ = event;
|
||||
|
||||
return watcher_.StartWatching(event->handle(), &helper_);
|
||||
}
|
||||
|
||||
void WaitableEventWatcher::StopWatching() {
|
||||
delegate_ = NULL;
|
||||
event_ = NULL;
|
||||
watcher_.StopWatching();
|
||||
}
|
||||
|
||||
WaitableEvent* WaitableEventWatcher::GetWatchedEvent() {
|
||||
return event_;
|
||||
}
|
||||
|
||||
void WaitableEventWatcher::OnObjectSignaled() {
|
||||
WaitableEvent* event = event_;
|
||||
Delegate* delegate = delegate_;
|
||||
event_ = NULL;
|
||||
delegate_ = NULL;
|
||||
DCHECK(event);
|
||||
|
||||
delegate->OnWaitableEventSignaled(event);
|
||||
}
|
||||
|
||||
} // namespace base
|
|
@ -21,21 +21,10 @@ WaitableEvent::WaitableEvent(bool manual_reset, bool signaled)
|
|||
CHECK(handle_);
|
||||
}
|
||||
|
||||
WaitableEvent::WaitableEvent(HANDLE handle)
|
||||
: handle_(handle) {
|
||||
CHECK(handle) << "Tried to create WaitableEvent from NULL handle";
|
||||
}
|
||||
|
||||
WaitableEvent::~WaitableEvent() {
|
||||
CloseHandle(handle_);
|
||||
}
|
||||
|
||||
HANDLE WaitableEvent::Release() {
|
||||
HANDLE rv = handle_;
|
||||
handle_ = INVALID_HANDLE_VALUE;
|
||||
return rv;
|
||||
}
|
||||
|
||||
void WaitableEvent::Reset() {
|
||||
ResetEvent(handle_);
|
||||
}
|
||||
|
|
|
@ -13,9 +13,7 @@
|
|||
ChildProcess* ChildProcess::child_process_;
|
||||
|
||||
ChildProcess::ChildProcess(ChildThread* child_thread)
|
||||
: child_thread_(child_thread),
|
||||
ref_count_(0),
|
||||
shutdown_event_(true, false) {
|
||||
: child_thread_(child_thread) {
|
||||
DCHECK(!child_process_);
|
||||
child_process_ = this;
|
||||
if (child_thread_.get()) // null in unittests.
|
||||
|
@ -25,37 +23,8 @@ ChildProcess::ChildProcess(ChildThread* child_thread)
|
|||
ChildProcess::~ChildProcess() {
|
||||
DCHECK(child_process_ == this);
|
||||
|
||||
// Signal this event before destroying the child process. That way all
|
||||
// background threads can cleanup.
|
||||
// For example, in the renderer the RenderThread instances will be able to
|
||||
// notice shutdown before the render process begins waiting for them to exit.
|
||||
shutdown_event_.Signal();
|
||||
|
||||
if (child_thread_.get())
|
||||
child_thread_->Stop();
|
||||
|
||||
child_process_ = NULL;
|
||||
}
|
||||
|
||||
void ChildProcess::AddRefProcess() {
|
||||
DCHECK(!child_thread_.get() || // null in unittests.
|
||||
MessageLoop::current() == child_thread_->message_loop());
|
||||
ref_count_++;
|
||||
}
|
||||
|
||||
void ChildProcess::ReleaseProcess() {
|
||||
DCHECK(!child_thread_.get() || // null in unittests.
|
||||
MessageLoop::current() == child_thread_->message_loop());
|
||||
DCHECK(ref_count_);
|
||||
DCHECK(child_process_);
|
||||
if (--ref_count_)
|
||||
return;
|
||||
|
||||
if (child_thread_.get()) // null in unittests.
|
||||
child_thread_->OnProcessFinalRelease();
|
||||
}
|
||||
|
||||
base::WaitableEvent* ChildProcess::GetShutDownEvent() {
|
||||
DCHECK(child_process_);
|
||||
return &child_process_->shutdown_event_;
|
||||
}
|
||||
|
|
|
@ -29,24 +29,6 @@ class ChildProcess {
|
|||
// Getter for this process' main thread.
|
||||
ChildThread* child_thread() { return child_thread_.get(); }
|
||||
|
||||
// A global event object that is signalled when the main thread's message
|
||||
// loop exits. This gives background threads a way to observe the main
|
||||
// thread shutting down. This can be useful when a background thread is
|
||||
// waiting for some information from the browser process. If the browser
|
||||
// process goes away prematurely, the background thread can at least notice
|
||||
// the child processes's main thread exiting to determine that it should give
|
||||
// up waiting.
|
||||
// For example, see the renderer code used to implement
|
||||
// webkit_glue::GetCookies.
|
||||
base::WaitableEvent* GetShutDownEvent();
|
||||
|
||||
// These are used for ref-counting the child process. The process shuts
|
||||
// itself down when the ref count reaches 0.
|
||||
// For example, in the renderer process, generally each tab managed by this
|
||||
// process will hold a reference to the process, and release when closed.
|
||||
void AddRefProcess();
|
||||
void ReleaseProcess();
|
||||
|
||||
// Getter for the one ChildProcess object for this process.
|
||||
static ChildProcess* current() { return child_process_; }
|
||||
|
||||
|
@ -55,11 +37,6 @@ class ChildProcess {
|
|||
// it depends on it (indirectly through IPC::SyncChannel).
|
||||
mozilla::UniquePtr<ChildThread> child_thread_;
|
||||
|
||||
int ref_count_;
|
||||
|
||||
// An event that will be signalled when we shutdown.
|
||||
base::WaitableEvent shutdown_event_;
|
||||
|
||||
// The singleton instance for this process.
|
||||
static ChildProcess* child_process_;
|
||||
|
||||
|
|
|
@ -16,64 +16,17 @@
|
|||
#include "mozilla/ipc/BrowserProcessSubThread.h"
|
||||
#include "mozilla/ipc/Transport.h"
|
||||
typedef mozilla::ipc::BrowserProcessSubThread ChromeThread;
|
||||
#include "chrome/common/notification_service.h"
|
||||
#include "chrome/common/notification_type.h"
|
||||
#include "chrome/common/process_watcher.h"
|
||||
#include "chrome/common/result_codes.h"
|
||||
|
||||
using mozilla::ipc::FileDescriptor;
|
||||
|
||||
namespace {
|
||||
typedef std::list<ChildProcessHost*> ChildProcessList;
|
||||
|
||||
// The NotificationTask is used to notify about plugin process connection/
|
||||
// disconnection. It is needed because the notifications in the
|
||||
// NotificationService must happen in the main thread.
|
||||
class ChildNotificationTask : public mozilla::Runnable {
|
||||
public:
|
||||
ChildNotificationTask(
|
||||
NotificationType notification_type, ChildProcessInfo* info)
|
||||
: notification_type_(notification_type), info_(*info) { }
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
NotificationService::current()->
|
||||
Notify(notification_type_, NotificationService::AllSources(),
|
||||
Details<ChildProcessInfo>(&info_));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
NotificationType notification_type_;
|
||||
ChildProcessInfo info_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
|
||||
ChildProcessHost::ChildProcessHost(ProcessType type)
|
||||
:
|
||||
ChildProcessInfo(type),
|
||||
ALLOW_THIS_IN_INITIALIZER_LIST(listener_(this)),
|
||||
opening_channel_(false),
|
||||
process_event_(nullptr) {
|
||||
Singleton<ChildProcessList>::get()->push_back(this);
|
||||
ChildProcessHost::ChildProcessHost()
|
||||
: ALLOW_THIS_IN_INITIALIZER_LIST(listener_(this)),
|
||||
opening_channel_(false) {
|
||||
}
|
||||
|
||||
|
||||
ChildProcessHost::~ChildProcessHost() {
|
||||
Singleton<ChildProcessList>::get()->remove(this);
|
||||
|
||||
if (handle()) {
|
||||
watcher_.StopWatching();
|
||||
ProcessWatcher::EnsureProcessTerminated(handle());
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Above call took ownership, so don't want WaitableEvent to assert because
|
||||
// the handle isn't valid anymore.
|
||||
process_event_->Release();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool ChildProcessHost::CreateChannel() {
|
||||
|
@ -104,79 +57,18 @@ bool ChildProcessHost::CreateChannel(FileDescriptor& aFileDescriptor) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void ChildProcessHost::SetHandle(base::ProcessHandle process) {
|
||||
#if defined(OS_WIN)
|
||||
process_event_.reset(new base::WaitableEvent(process));
|
||||
|
||||
DCHECK(!handle());
|
||||
set_handle(process);
|
||||
watcher_.StartWatching(process_event_.get(), this);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ChildProcessHost::InstanceCreated() {
|
||||
Notify(NotificationType(NotificationType::CHILD_INSTANCE_CREATED));
|
||||
}
|
||||
|
||||
bool ChildProcessHost::Send(IPC::Message* msg) {
|
||||
if (!channel_.get()) {
|
||||
delete msg;
|
||||
return false;
|
||||
}
|
||||
return channel_->Send(msg);
|
||||
}
|
||||
|
||||
void ChildProcessHost::Notify(NotificationType type) {
|
||||
MessageLoop* loop = ChromeThread::GetMessageLoop(ChromeThread::IO);
|
||||
if (!loop)
|
||||
loop = mozilla::ipc::ProcessChild::message_loop();
|
||||
if (!loop)
|
||||
loop = MessageLoop::current();
|
||||
RefPtr<ChildNotificationTask> task = new ChildNotificationTask(type, this);
|
||||
loop->PostTask(task.forget());
|
||||
}
|
||||
|
||||
void ChildProcessHost::OnWaitableEventSignaled(base::WaitableEvent *event) {
|
||||
#if defined(OS_WIN)
|
||||
HANDLE object = event->handle();
|
||||
DCHECK(handle());
|
||||
DCHECK_EQ(object, handle());
|
||||
|
||||
bool did_crash = base::DidProcessCrash(NULL, object);
|
||||
if (did_crash) {
|
||||
// Report that this child process crashed.
|
||||
Notify(NotificationType(NotificationType::CHILD_PROCESS_CRASHED));
|
||||
}
|
||||
// Notify in the main loop of the disconnection.
|
||||
Notify(NotificationType(NotificationType::CHILD_PROCESS_HOST_DISCONNECTED));
|
||||
#endif
|
||||
}
|
||||
|
||||
ChildProcessHost::ListenerHook::ListenerHook(ChildProcessHost* host)
|
||||
: host_(host) {
|
||||
}
|
||||
|
||||
void ChildProcessHost::ListenerHook::OnMessageReceived(
|
||||
IPC::Message&& msg) {
|
||||
|
||||
bool msg_is_ok = true;
|
||||
bool handled = false;
|
||||
|
||||
if (!handled) {
|
||||
host_->OnMessageReceived(mozilla::Move(msg));
|
||||
}
|
||||
|
||||
if (!msg_is_ok)
|
||||
base::KillProcess(host_->handle(), ResultCodes::KILLED_BAD_MESSAGE, false);
|
||||
|
||||
host_->OnMessageReceived(mozilla::Move(msg));
|
||||
}
|
||||
|
||||
void ChildProcessHost::ListenerHook::OnChannelConnected(int32_t peer_pid) {
|
||||
host_->opening_channel_ = false;
|
||||
host_->OnChannelConnected(peer_pid);
|
||||
|
||||
// Notify in the main loop of the connection.
|
||||
host_->Notify(NotificationType(NotificationType::CHILD_PROCESS_HOST_CONNECTED));
|
||||
}
|
||||
|
||||
void ChildProcessHost::ListenerHook::OnChannelError() {
|
||||
|
@ -187,33 +79,3 @@ void ChildProcessHost::ListenerHook::OnChannelError() {
|
|||
void ChildProcessHost::ListenerHook::GetQueuedMessages(std::queue<IPC::Message>& queue) {
|
||||
host_->GetQueuedMessages(queue);
|
||||
}
|
||||
|
||||
ChildProcessHost::Iterator::Iterator() : all_(true) {
|
||||
iterator_ = Singleton<ChildProcessList>::get()->begin();
|
||||
}
|
||||
|
||||
ChildProcessHost::Iterator::Iterator(ProcessType type)
|
||||
: all_(false), type_(type) {
|
||||
iterator_ = Singleton<ChildProcessList>::get()->begin();
|
||||
if (!Done() && (*iterator_)->type() != type_)
|
||||
++(*this);
|
||||
}
|
||||
|
||||
ChildProcessHost* ChildProcessHost::Iterator::operator++() {
|
||||
do {
|
||||
++iterator_;
|
||||
if (Done())
|
||||
break;
|
||||
|
||||
if (!all_ && (*iterator_)->type() != type_)
|
||||
continue;
|
||||
|
||||
return *iterator_;
|
||||
} while (true);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool ChildProcessHost::Iterator::Done() {
|
||||
return iterator_ == Singleton<ChildProcessList>::get()->end();
|
||||
}
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
#include <list>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/waitable_event_watcher.h"
|
||||
#include "chrome/common/child_process_info.h"
|
||||
#include "chrome/common/ipc_channel.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
|
@ -23,43 +21,14 @@ class FileDescriptor;
|
|||
}
|
||||
}
|
||||
|
||||
class NotificationType;
|
||||
|
||||
// Plugins/workers and other child processes that live on the IO thread should
|
||||
// derive from this class.
|
||||
class ChildProcessHost :
|
||||
public IPC::Message::Sender,
|
||||
public ChildProcessInfo,
|
||||
public base::WaitableEventWatcher::Delegate,
|
||||
public IPC::Channel::Listener {
|
||||
class ChildProcessHost : public IPC::Channel::Listener {
|
||||
public:
|
||||
virtual ~ChildProcessHost();
|
||||
|
||||
// ResourceDispatcherHost::Receiver implementation:
|
||||
virtual bool Send(IPC::Message* msg);
|
||||
|
||||
// The Iterator class allows iteration through either all child processes, or
|
||||
// ones of a specific type, depending on which constructor is used. Note that
|
||||
// this should be done from the IO thread and that the iterator should not be
|
||||
// kept around as it may be invalidated on subsequent event processing in the
|
||||
// event loop.
|
||||
class Iterator {
|
||||
public:
|
||||
Iterator();
|
||||
explicit Iterator(ProcessType type);
|
||||
ChildProcessHost* operator->() { return *iterator_; }
|
||||
ChildProcessHost* operator*() { return *iterator_; }
|
||||
ChildProcessHost* operator++();
|
||||
bool Done();
|
||||
|
||||
private:
|
||||
bool all_;
|
||||
ProcessType type_;
|
||||
std::list<ChildProcessHost*>::iterator iterator_;
|
||||
};
|
||||
|
||||
protected:
|
||||
explicit ChildProcessHost(ProcessType type);
|
||||
explicit ChildProcessHost();
|
||||
|
||||
// Derived classes return true if it's ok to shut down the child process.
|
||||
virtual bool CanShutdown() = 0;
|
||||
|
@ -69,13 +38,6 @@ class ChildProcessHost :
|
|||
|
||||
bool CreateChannel(mozilla::ipc::FileDescriptor& aFileDescriptor);
|
||||
|
||||
// Once the subclass gets a handle to the process, it needs to tell
|
||||
// ChildProcessHost using this function.
|
||||
void SetHandle(base::ProcessHandle handle);
|
||||
|
||||
// Notifies us that an instance has been created on this child process.
|
||||
void InstanceCreated();
|
||||
|
||||
// IPC::Channel::Listener implementation:
|
||||
virtual void OnMessageReceived(IPC::Message&& msg) { }
|
||||
virtual void OnChannelConnected(int32_t peer_pid) { }
|
||||
|
@ -84,19 +46,9 @@ class ChildProcessHost :
|
|||
bool opening_channel() { return opening_channel_; }
|
||||
const std::wstring& channel_id() { return channel_id_; }
|
||||
|
||||
base::WaitableEvent* GetProcessEvent() { return process_event_.get(); }
|
||||
|
||||
const IPC::Channel& channel() const { return *channel_; }
|
||||
IPC::Channel* channelp() const { return channel_.get(); }
|
||||
|
||||
private:
|
||||
// Sends the given notification to the notification service on the UI thread.
|
||||
void Notify(NotificationType type);
|
||||
|
||||
protected:
|
||||
// WaitableEventWatcher::Delegate implementation:
|
||||
virtual void OnWaitableEventSignaled(base::WaitableEvent *event);
|
||||
|
||||
private:
|
||||
// By using an internal class as the IPC::Channel::Listener, we can intercept
|
||||
// OnMessageReceived/OnChannelConnected and do our own processing before
|
||||
|
@ -122,11 +74,6 @@ class ChildProcessHost :
|
|||
|
||||
// IPC Channel's id.
|
||||
std::wstring channel_id_;
|
||||
|
||||
// Used to watch the child process handle.
|
||||
base::WaitableEventWatcher watcher_;
|
||||
|
||||
mozilla::UniquePtr<base::WaitableEvent> process_event_;
|
||||
};
|
||||
|
||||
#endif // CHROME_COMMON_CHILD_PROCESS_HOST_H_
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/common/child_process_info.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
std::wstring ChildProcessInfo::GetTypeNameInEnglish(
|
||||
ChildProcessInfo::ProcessType type) {
|
||||
switch (type) {
|
||||
case BROWSER_PROCESS:
|
||||
return L"Browser";
|
||||
case RENDER_PROCESS:
|
||||
return L"Tab";
|
||||
case PLUGIN_PROCESS:
|
||||
return L"Plug-in";
|
||||
case WORKER_PROCESS:
|
||||
return L"Web Worker";
|
||||
case UNKNOWN_PROCESS:
|
||||
default:
|
||||
DCHECK(false) << "Unknown child process type!";
|
||||
return L"Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring ChildProcessInfo::GetLocalizedTitle() const {
|
||||
return name_;
|
||||
}
|
||||
|
||||
ChildProcessInfo::ChildProcessInfo(ProcessType type) {
|
||||
// This constructor is only used by objects which derive from this class,
|
||||
// which means *this* is a real object that refers to a child process, and not
|
||||
// just a simple object that contains information about it. So add it to our
|
||||
// list of running processes.
|
||||
type_ = type;
|
||||
pid_ = -1;
|
||||
}
|
||||
|
||||
|
||||
ChildProcessInfo::~ChildProcessInfo() {
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_COMMON_CHILD_PROCESS_INFO_H_
|
||||
#define CHROME_COMMON_CHILD_PROCESS_INFO_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/process.h"
|
||||
|
||||
// Holds information about a child process.
|
||||
class ChildProcessInfo {
|
||||
public:
|
||||
enum ProcessType {
|
||||
BROWSER_PROCESS,
|
||||
RENDER_PROCESS,
|
||||
PLUGIN_PROCESS,
|
||||
WORKER_PROCESS,
|
||||
UNKNOWN_PROCESS
|
||||
};
|
||||
|
||||
// Returns the type of the process.
|
||||
ProcessType type() const { return type_; }
|
||||
|
||||
// Returns the name of the process. i.e. for plugins it might be Flash, while
|
||||
// for workers it might be the domain that it's from.
|
||||
std::wstring name() const { return name_; }
|
||||
|
||||
// Getter to the process handle.
|
||||
base::ProcessHandle handle() const { return process_.handle(); }
|
||||
|
||||
virtual int GetProcessId() const {
|
||||
if (pid_ != -1)
|
||||
return pid_;
|
||||
|
||||
pid_ = process_.pid();
|
||||
return pid_;
|
||||
}
|
||||
void SetProcessBackgrounded() const { process_.SetProcessBackgrounded(true); }
|
||||
|
||||
// Returns an English name of the process type, should only be used for non
|
||||
// user-visible strings, or debugging pages like about:memory.
|
||||
static std::wstring GetTypeNameInEnglish(ProcessType type);
|
||||
|
||||
// Returns a localized title for the child process. For example, a plugin
|
||||
// process would be "Plug-in: Flash" when name is "Flash".
|
||||
std::wstring GetLocalizedTitle() const;
|
||||
|
||||
ChildProcessInfo(const ChildProcessInfo& original) {
|
||||
type_ = original.type_;
|
||||
name_ = original.name_;
|
||||
process_ = original.process_;
|
||||
pid_ = original.pid_;
|
||||
}
|
||||
|
||||
ChildProcessInfo& operator=(const ChildProcessInfo& original) {
|
||||
if (&original != this) {
|
||||
type_ = original.type_;
|
||||
name_ = original.name_;
|
||||
process_ = original.process_;
|
||||
pid_ = original.pid_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual ~ChildProcessInfo();
|
||||
|
||||
// We define the < operator so that the ChildProcessInfo can be used as a key
|
||||
// in a std::map.
|
||||
bool operator <(const ChildProcessInfo& rhs) const {
|
||||
if (process_.handle() != rhs.process_.handle())
|
||||
return process_ .handle() < rhs.process_.handle();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator ==(const ChildProcessInfo& rhs) const {
|
||||
return process_.handle() == rhs.process_.handle();
|
||||
}
|
||||
|
||||
protected:
|
||||
void set_type(ProcessType aType) { type_ = aType; }
|
||||
void set_name(const std::wstring& aName) { name_ = aName; }
|
||||
void set_handle(base::ProcessHandle aHandle) {
|
||||
process_.set_handle(aHandle);
|
||||
pid_ = -1;
|
||||
}
|
||||
|
||||
// Derived objects need to use this constructor so we know what type we are.
|
||||
explicit ChildProcessInfo(ProcessType type);
|
||||
|
||||
private:
|
||||
ProcessType type_;
|
||||
std::wstring name_;
|
||||
mutable int pid_; // Cache of the process id.
|
||||
|
||||
// The handle to the process.
|
||||
mutable base::Process process_;
|
||||
};
|
||||
|
||||
#endif // CHROME_COMMON_CHILD_PROCESS_INFO_H_
|
|
@ -11,14 +11,10 @@
|
|||
#include "chrome/common/child_process.h"
|
||||
#include "chrome/common/chrome_switches.h"
|
||||
|
||||
// V8 needs a 1MB stack size.
|
||||
const size_t ChildThread::kV8StackSize = 1024 * 1024;
|
||||
|
||||
ChildThread::ChildThread(Thread::Options options)
|
||||
: Thread("Chrome_ChildThread"),
|
||||
owner_loop_(MessageLoop::current()),
|
||||
options_(options),
|
||||
check_with_browser_before_shutdown_(false) {
|
||||
options_(options) {
|
||||
DCHECK(owner_loop_);
|
||||
channel_name_ = CommandLine::ForCurrentProcess()->GetSwitchValue(
|
||||
switches::kProcessChannelID);
|
||||
|
@ -55,19 +51,7 @@ void ChildThread::MarkThread() {
|
|||
}
|
||||
#endif
|
||||
|
||||
bool ChildThread::Send(IPC::Message* msg) {
|
||||
if (!channel_.get()) {
|
||||
delete msg;
|
||||
return false;
|
||||
}
|
||||
|
||||
return channel_->Send(msg);
|
||||
}
|
||||
|
||||
void ChildThread::OnMessageReceived(IPC::Message&& msg) {
|
||||
if (msg.routing_id() == MSG_ROUTING_CONTROL) {
|
||||
OnControlMessageReceived(msg);
|
||||
}
|
||||
}
|
||||
|
||||
ChildThread* ChildThread::current() {
|
||||
|
@ -86,11 +70,3 @@ void ChildThread::CleanUp() {
|
|||
// it caches a pointer to this thread.
|
||||
channel_ = nullptr;
|
||||
}
|
||||
|
||||
void ChildThread::OnProcessFinalRelease() {
|
||||
if (!check_with_browser_before_shutdown_) {
|
||||
RefPtr<mozilla::Runnable> task = new MessageLoop::QuitTask();
|
||||
owner_loop_->PostTask(task.forget());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,40 +15,19 @@ class ResourceDispatcher;
|
|||
|
||||
// Child processes's background thread should derive from this class.
|
||||
class ChildThread : public IPC::Channel::Listener,
|
||||
public IPC::Message::Sender,
|
||||
public base::Thread {
|
||||
public:
|
||||
// Creates the thread.
|
||||
explicit ChildThread(Thread::Options options);
|
||||
virtual ~ChildThread();
|
||||
|
||||
// IPC::Message::Sender implementation:
|
||||
virtual bool Send(IPC::Message* msg);
|
||||
|
||||
// See documentation on MessageRouter for AddRoute and RemoveRoute
|
||||
void AddRoute(int32_t routing_id, IPC::Channel::Listener* listener);
|
||||
void RemoveRoute(int32_t routing_id);
|
||||
|
||||
MessageLoop* owner_loop() { return owner_loop_; }
|
||||
|
||||
protected:
|
||||
friend class ChildProcess;
|
||||
|
||||
// Starts the thread.
|
||||
bool Run();
|
||||
|
||||
// Overrides the channel name. Used for --single-process mode.
|
||||
void SetChannelName(const std::wstring& name) { channel_name_ = name; }
|
||||
|
||||
// Called when the process refcount is 0.
|
||||
void OnProcessFinalRelease();
|
||||
|
||||
protected:
|
||||
// The required stack size if V8 runs on a thread.
|
||||
static const size_t kV8StackSize;
|
||||
|
||||
virtual void OnControlMessageReceived(const IPC::Message& msg) { }
|
||||
|
||||
// Returns the one child thread.
|
||||
static ChildThread* current();
|
||||
|
||||
|
@ -75,11 +54,6 @@ class ChildThread : public IPC::Channel::Listener,
|
|||
|
||||
Thread::Options options_;
|
||||
|
||||
// If true, checks with the browser process before shutdown. This avoids race
|
||||
// conditions if the process refcount is 0 but there's an IPC message inflight
|
||||
// that would addref it.
|
||||
bool check_with_browser_before_shutdown_;
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(ChildThread);
|
||||
};
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace IPC {
|
|||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class Channel : public Message::Sender {
|
||||
class Channel {
|
||||
// Security tests need access to the pipe handle.
|
||||
friend class ChannelTest;
|
||||
|
||||
|
@ -105,7 +105,7 @@ class Channel : public Message::Sender {
|
|||
//
|
||||
// If you Send() a message on a Close()'d channel, we delete the message
|
||||
// immediately.
|
||||
virtual bool Send(Message* message) override;
|
||||
bool Send(Message* message);
|
||||
|
||||
// Unsound_IsClosed() and Unsound_NumQueuedMessages() are safe to call from
|
||||
// any thread, but the value returned may be out of date, because we don't
|
||||
|
|
|
@ -38,18 +38,6 @@ class Message : public Pickle {
|
|||
public:
|
||||
typedef uint32_t msgid_t;
|
||||
|
||||
// Implemented by objects that can send IPC messages across a channel.
|
||||
class Sender {
|
||||
public:
|
||||
virtual ~Sender() {}
|
||||
|
||||
// Sends the given IPC message. The implementor takes ownership of the
|
||||
// given Message regardless of whether or not this method succeeds. This
|
||||
// is done to make this method easier to use. Returns true on success and
|
||||
// false otherwise.
|
||||
virtual bool Send(Message* msg) = 0;
|
||||
};
|
||||
|
||||
enum PriorityValue {
|
||||
PRIORITY_NORMAL = 1,
|
||||
PRIORITY_HIGH = 2,
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This file defines the type used to provide details for NotificationService
|
||||
// notifications.
|
||||
|
||||
#ifndef CHROME_COMMON_NOTIFICATION_DETAILS_H__
|
||||
#define CHROME_COMMON_NOTIFICATION_DETAILS_H__
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
// Do not declare a NotificationDetails directly--use either
|
||||
// "Details<detailsclassname>(detailsclasspointer)" or
|
||||
// NotificationService::NoDetails().
|
||||
class NotificationDetails {
|
||||
public:
|
||||
NotificationDetails() : ptr_(NULL) {}
|
||||
NotificationDetails(const NotificationDetails& other) : ptr_(other.ptr_) {}
|
||||
~NotificationDetails() {}
|
||||
|
||||
// NotificationDetails can be used as the index for a map; this method
|
||||
// returns the pointer to the current details as an identifier, for use as a
|
||||
// map index.
|
||||
uintptr_t map_key() const { return reinterpret_cast<uintptr_t>(ptr_); }
|
||||
|
||||
bool operator!=(const NotificationDetails& other) const {
|
||||
return ptr_ != other.ptr_;
|
||||
}
|
||||
|
||||
bool operator==(const NotificationDetails& other) const {
|
||||
return ptr_ == other.ptr_;
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit NotificationDetails(void* ptr) : ptr_(ptr) {}
|
||||
|
||||
void* ptr_;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class Details : public NotificationDetails {
|
||||
public:
|
||||
explicit Details(T* ptr) : NotificationDetails(ptr) {}
|
||||
explicit Details(const NotificationDetails& other)
|
||||
: NotificationDetails(other) {}
|
||||
|
||||
T* operator->() const { return ptr(); }
|
||||
T* ptr() const { return static_cast<T*>(ptr_); }
|
||||
};
|
||||
|
||||
#endif // CHROME_COMMON_NOTIFICATION_DETAILS_H__
|
|
@ -1,25 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_COMMON_NOTIFICATION_OBSERVER_H_
|
||||
#define CHROME_COMMON_NOTIFICATION_OBSERVER_H_
|
||||
|
||||
class NotificationDetails;
|
||||
class NotificationSource;
|
||||
class NotificationType;
|
||||
|
||||
// This is the base class for notification observers. When a matching
|
||||
// notification is posted to the notification service, Observe is called.
|
||||
class NotificationObserver {
|
||||
public:
|
||||
virtual ~NotificationObserver();
|
||||
|
||||
virtual void Observe(NotificationType type,
|
||||
const NotificationSource& source,
|
||||
const NotificationDetails& details) = 0;
|
||||
};
|
||||
|
||||
#endif // CHROME_COMMON_NOTIFICATION_OBSERVER_H_
|
|
@ -1,55 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_COMMON_NOTIFICATION_REGISTRAR_H_
|
||||
#define CHROME_COMMON_NOTIFICATION_REGISTRAR_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "chrome/common/notification_observer.h"
|
||||
|
||||
// Aids in registering for notifications and ensures that all registered
|
||||
// notifications are unregistered when the class is destroyed.
|
||||
//
|
||||
// The intended use is that you make a NotificationRegistrar member in your
|
||||
// class and use it to register your notifications instead of going through the
|
||||
// notification service directly. It will automatically unregister them for
|
||||
// you.
|
||||
class NotificationRegistrar {
|
||||
public:
|
||||
// This class must not be derived from (we don't have a virtual destructor so
|
||||
// it won't work). Instead, use it as a member in your class.
|
||||
NotificationRegistrar();
|
||||
~NotificationRegistrar();
|
||||
|
||||
// Wrappers around NotificationService::[Add|Remove]Observer.
|
||||
void Add(NotificationObserver* observer,
|
||||
NotificationType type,
|
||||
const NotificationSource& source);
|
||||
void Remove(NotificationObserver* observer,
|
||||
NotificationType type,
|
||||
const NotificationSource& source);
|
||||
|
||||
// Unregisters all notifications.
|
||||
void RemoveAll();
|
||||
|
||||
private:
|
||||
struct Record;
|
||||
|
||||
// We keep registered notifications in a simple vector. This means we'll do
|
||||
// brute-force searches when removing them individually, but individual
|
||||
// removal is uncommon, and there will typically only be a couple of
|
||||
// notifications anyway.
|
||||
typedef std::vector<Record> RecordVector;
|
||||
|
||||
// Lists all notifications we're currently registered for.
|
||||
RecordVector registered_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NotificationRegistrar);
|
||||
};
|
||||
|
||||
#endif // CHROME_COMMON_NOTIFICATION_REGISTRAR_H_
|
|
@ -1,145 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/common/notification_service.h"
|
||||
#include "base/thread_local.h"
|
||||
|
||||
static base::ThreadLocalPointer<NotificationService>& get_tls_ptr() {
|
||||
static base::ThreadLocalPointer<NotificationService> tls_ptr;
|
||||
return tls_ptr;
|
||||
}
|
||||
|
||||
// static
|
||||
NotificationService* NotificationService::current() {
|
||||
return get_tls_ptr().Get();
|
||||
}
|
||||
|
||||
// static
|
||||
bool NotificationService::HasKey(const NotificationSourceMap& map,
|
||||
const NotificationSource& source) {
|
||||
return map.find(source.map_key()) != map.end();
|
||||
}
|
||||
|
||||
NotificationService::NotificationService() {
|
||||
DCHECK(current() == NULL);
|
||||
#ifndef NDEBUG
|
||||
memset(observer_counts_, 0, sizeof(observer_counts_));
|
||||
#endif
|
||||
|
||||
get_tls_ptr().Set(this);
|
||||
}
|
||||
|
||||
void NotificationService::AddObserver(NotificationObserver* observer,
|
||||
NotificationType type,
|
||||
const NotificationSource& source) {
|
||||
DCHECK(type.value < NotificationType::NOTIFICATION_TYPE_COUNT);
|
||||
|
||||
// We have gotten some crashes where the observer pointer is NULL. The problem
|
||||
// is that this happens when we actually execute a notification, so have no
|
||||
// way of knowing who the bad observer was. We want to know when this happens
|
||||
// in release mode so we know what code to blame the crash on (since this is
|
||||
// guaranteed to crash later).
|
||||
CHECK(observer);
|
||||
|
||||
NotificationObserverList* observer_list;
|
||||
if (HasKey(observers_[type.value], source)) {
|
||||
observer_list = observers_[type.value][source.map_key()];
|
||||
} else {
|
||||
observer_list = new NotificationObserverList;
|
||||
observers_[type.value][source.map_key()] = observer_list;
|
||||
}
|
||||
|
||||
observer_list->AddObserver(observer);
|
||||
#ifndef NDEBUG
|
||||
++observer_counts_[type.value];
|
||||
#endif
|
||||
}
|
||||
|
||||
void NotificationService::RemoveObserver(NotificationObserver* observer,
|
||||
NotificationType type,
|
||||
const NotificationSource& source) {
|
||||
DCHECK(type.value < NotificationType::NOTIFICATION_TYPE_COUNT);
|
||||
DCHECK(HasKey(observers_[type.value], source));
|
||||
|
||||
NotificationObserverList* observer_list =
|
||||
observers_[type.value][source.map_key()];
|
||||
if (observer_list) {
|
||||
observer_list->RemoveObserver(observer);
|
||||
#ifndef NDEBUG
|
||||
--observer_counts_[type.value];
|
||||
#endif
|
||||
}
|
||||
|
||||
// TODO(jhughes): Remove observer list from map if empty?
|
||||
}
|
||||
|
||||
void NotificationService::Notify(NotificationType type,
|
||||
const NotificationSource& source,
|
||||
const NotificationDetails& details) {
|
||||
DCHECK(type.value > NotificationType::ALL) <<
|
||||
"Allowed for observing, but not posting.";
|
||||
DCHECK(type.value < NotificationType::NOTIFICATION_TYPE_COUNT);
|
||||
|
||||
// There's no particular reason for the order in which the different
|
||||
// classes of observers get notified here.
|
||||
|
||||
// Notify observers of all types and all sources
|
||||
if (HasKey(observers_[NotificationType::ALL], AllSources()) &&
|
||||
source != AllSources()) {
|
||||
FOR_EACH_OBSERVER(NotificationObserver,
|
||||
*observers_[NotificationType::ALL][AllSources().map_key()],
|
||||
Observe(type, source, details));
|
||||
}
|
||||
|
||||
// Notify observers of all types and the given source
|
||||
if (HasKey(observers_[NotificationType::ALL], source)) {
|
||||
FOR_EACH_OBSERVER(NotificationObserver,
|
||||
*observers_[NotificationType::ALL][source.map_key()],
|
||||
Observe(type, source, details));
|
||||
}
|
||||
|
||||
// Notify observers of the given type and all sources
|
||||
if (HasKey(observers_[type.value], AllSources()) &&
|
||||
source != AllSources()) {
|
||||
FOR_EACH_OBSERVER(NotificationObserver,
|
||||
*observers_[type.value][AllSources().map_key()],
|
||||
Observe(type, source, details));
|
||||
}
|
||||
|
||||
// Notify observers of the given type and the given source
|
||||
if (HasKey(observers_[type.value], source)) {
|
||||
FOR_EACH_OBSERVER(NotificationObserver,
|
||||
*observers_[type.value][source.map_key()],
|
||||
Observe(type, source, details));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NotificationService::~NotificationService() {
|
||||
get_tls_ptr().Set(NULL);
|
||||
|
||||
#ifndef NDEBUG
|
||||
for (int i = 0; i < NotificationType::NOTIFICATION_TYPE_COUNT; i++) {
|
||||
if (observer_counts_[i] > 0) {
|
||||
// This may not be completely fixable -- see
|
||||
// http://code.google.com/p/chromium/issues/detail?id=11010 .
|
||||
// But any new leaks should be fixed.
|
||||
CHROMIUM_LOG(WARNING) << observer_counts_[i] << " notification observer(s) leaked"
|
||||
<< " of notification type " << i;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < NotificationType::NOTIFICATION_TYPE_COUNT; i++) {
|
||||
NotificationSourceMap omap = observers_[i];
|
||||
for (NotificationSourceMap::iterator it = omap.begin();
|
||||
it != omap.end(); ++it) {
|
||||
delete it->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NotificationObserver::~NotificationObserver() {}
|
|
@ -1,102 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This file describes a central switchboard for notifications that might
|
||||
// happen in various parts of the application, and allows users to register
|
||||
// observers for various classes of events that they're interested in.
|
||||
|
||||
#ifndef CHROME_COMMON_NOTIFICATION_SERVICE_H_
|
||||
#define CHROME_COMMON_NOTIFICATION_SERVICE_H_
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "base/observer_list.h"
|
||||
#include "chrome/common/notification_details.h"
|
||||
#include "chrome/common/notification_observer.h"
|
||||
#include "chrome/common/notification_source.h"
|
||||
#include "chrome/common/notification_type.h"
|
||||
|
||||
class NotificationObserver;
|
||||
|
||||
class NotificationService {
|
||||
public:
|
||||
// Returns the NotificationService object for the current thread, or NULL if
|
||||
// none.
|
||||
static NotificationService* current();
|
||||
|
||||
// Normally instantiated when the thread is created. Not all threads have
|
||||
// a NotificationService. Only one instance should be created per thread.
|
||||
NotificationService();
|
||||
~NotificationService();
|
||||
|
||||
// Registers a NotificationObserver to be called whenever a matching
|
||||
// notification is posted. Observer is a pointer to an object subclassing
|
||||
// NotificationObserver to be notified when an event matching the other two
|
||||
// parameters is posted to this service. Type is the type of events to
|
||||
// be notified about (or NOTIFY_ALL to receive events of all types).
|
||||
// Source is a NotificationSource object (created using
|
||||
// "Source<classname>(pointer)"), if this observer only wants to
|
||||
// receive events from that object, or NotificationService::AllSources()
|
||||
// to receive events from all sources.
|
||||
//
|
||||
// A given observer can be registered only once for each combination of
|
||||
// type and source. If the same object is registered more than once,
|
||||
// it must be removed for each of those combinations of type and source later.
|
||||
//
|
||||
// The caller retains ownership of the object pointed to by observer.
|
||||
void AddObserver(NotificationObserver* observer,
|
||||
NotificationType type, const NotificationSource& source);
|
||||
|
||||
// Removes the object pointed to by observer from receiving notifications
|
||||
// that match type and source. If no object matching the parameters is
|
||||
// currently registered, this method is a no-op.
|
||||
void RemoveObserver(NotificationObserver* observer,
|
||||
NotificationType type, const NotificationSource& source);
|
||||
|
||||
// Synchronously posts a notification to all interested observers.
|
||||
// Source is a reference to a NotificationSource object representing
|
||||
// the object originating the notification (can be
|
||||
// NotificationService::AllSources(), in which case
|
||||
// only observers interested in all sources will be notified).
|
||||
// Details is a reference to an object containing additional data about
|
||||
// the notification. If no additional data is needed, NoDetails() is used.
|
||||
// There is no particular order in which the observers will be notified.
|
||||
void Notify(NotificationType type,
|
||||
const NotificationSource& source,
|
||||
const NotificationDetails& details);
|
||||
|
||||
// Returns a NotificationSource that represents all notification sources
|
||||
// (for the purpose of registering an observer for events from all sources).
|
||||
static Source<void> AllSources() { return Source<void>(NULL); }
|
||||
|
||||
// Returns a NotificationDetails object that represents a lack of details
|
||||
// associated with a notification. (This is effectively a null pointer.)
|
||||
static Details<void> NoDetails() { return Details<void>(NULL); }
|
||||
|
||||
private:
|
||||
typedef base::ObserverList<NotificationObserver> NotificationObserverList;
|
||||
typedef std::map<uintptr_t, NotificationObserverList*> NotificationSourceMap;
|
||||
|
||||
// Convenience function to determine whether a source has a
|
||||
// NotificationObserverList in the given map;
|
||||
static bool HasKey(const NotificationSourceMap& map,
|
||||
const NotificationSource& source);
|
||||
|
||||
// Keeps track of the observers for each type of notification.
|
||||
// Until we get a prohibitively large number of notification types,
|
||||
// a simple array is probably the fastest way to dispatch.
|
||||
NotificationSourceMap observers_[NotificationType::NOTIFICATION_TYPE_COUNT];
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Used to check to see that AddObserver and RemoveObserver calls are
|
||||
// balanced.
|
||||
int observer_counts_[NotificationType::NOTIFICATION_TYPE_COUNT];
|
||||
#endif
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NotificationService);
|
||||
};
|
||||
|
||||
#endif // CHROME_COMMON_NOTIFICATION_SERVICE_H_
|
|
@ -1,53 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This file defines the type used to provide sources for NotificationService
|
||||
// notifications.
|
||||
|
||||
#ifndef CHROME_COMMON_NOTIFICATION_SOURCE_H__
|
||||
#define CHROME_COMMON_NOTIFICATION_SOURCE_H__
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
// Do not declare a NotificationSource directly--use either
|
||||
// "Source<sourceclassname>(sourceclasspointer)" or
|
||||
// NotificationService::AllSources().
|
||||
class NotificationSource {
|
||||
public:
|
||||
NotificationSource(const NotificationSource& other) : ptr_(other.ptr_) { }
|
||||
~NotificationSource() {}
|
||||
|
||||
// NotificationSource can be used as the index for a map; this method
|
||||
// returns the pointer to the current source as an identifier, for use as a
|
||||
// map index.
|
||||
uintptr_t map_key() const { return reinterpret_cast<uintptr_t>(ptr_); }
|
||||
|
||||
bool operator!=(const NotificationSource& other) const {
|
||||
return ptr_ != other.ptr_;
|
||||
}
|
||||
bool operator==(const NotificationSource& other) const {
|
||||
return ptr_ == other.ptr_;
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit NotificationSource(void* ptr) : ptr_(ptr) {}
|
||||
|
||||
void* ptr_;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class Source : public NotificationSource {
|
||||
public:
|
||||
explicit Source(T* ptr) : NotificationSource(ptr) {}
|
||||
|
||||
explicit Source(const NotificationSource& other)
|
||||
: NotificationSource(other) {}
|
||||
|
||||
T* operator->() const { return ptr(); }
|
||||
T* ptr() const { return static_cast<T*>(ptr_); }
|
||||
};
|
||||
|
||||
#endif // CHROME_COMMON_NOTIFICATION_SOURCE_H__
|
|
@ -1,576 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_COMMON_NOTIFICATION_TYPE_H_
|
||||
#define CHROME_COMMON_NOTIFICATION_TYPE_H_
|
||||
|
||||
// This file describes various types used to describe and filter notifications
|
||||
// that pass through the NotificationService.
|
||||
//
|
||||
// It is written as an enum inside a class so that it can be forward declared.
|
||||
// You're not allowed to forward declare an enum, and we want to forward
|
||||
// declare this since it's required by NotificationObserver which is included
|
||||
// by a lot of header files.
|
||||
//
|
||||
// Since this class encapsulates an integral value, it should be passed by
|
||||
// value.
|
||||
class NotificationType {
|
||||
public:
|
||||
enum Type {
|
||||
// General -----------------------------------------------------------------
|
||||
|
||||
// Special signal value to represent an interest in all notifications.
|
||||
// Not valid when posting a notification.
|
||||
ALL = 0,
|
||||
|
||||
// The app is done processing user actions, now is a good time to do
|
||||
// some background work.
|
||||
IDLE,
|
||||
|
||||
// Means that the app has just started doing something in response to a
|
||||
// user action, and that background processes shouldn't run if avoidable.
|
||||
BUSY,
|
||||
|
||||
// This is sent when the user does a gesture resulting in a noteworthy
|
||||
// action taking place. This is typically used for logging. The source is
|
||||
// the profile, and the details is a wstring identifying the action.
|
||||
USER_ACTION,
|
||||
|
||||
// NavigationController ----------------------------------------------------
|
||||
|
||||
// A new pending navigation has been created. Pending entries are created
|
||||
// when the user requests the navigation. We don't know if it will actually
|
||||
// happen until it does (at this point, it will be "committed." Note that
|
||||
// renderer- initiated navigations such as link clicks will never be
|
||||
// pending.
|
||||
//
|
||||
// This notification is called after the pending entry is created, but
|
||||
// before we actually try to navigate. The source will be the
|
||||
// NavigationController that owns the pending entry, and there are no
|
||||
// details.
|
||||
NAV_ENTRY_PENDING,
|
||||
|
||||
// A new non-pending navigation entry has been created. This will
|
||||
// correspond to one NavigationController entry being created (in the case
|
||||
// of new navigations) or renavigated to (for back/forward navigations).
|
||||
//
|
||||
// The source will be the navigation controller doing the commit. The
|
||||
// details will be NavigationController::LoadCommittedDetails.
|
||||
NAV_ENTRY_COMMITTED,
|
||||
|
||||
// Indicates that the NavigationController given in the Source has
|
||||
// decreased its back/forward list count by removing entries from either
|
||||
// the front or back of its list. This is usually the result of going back
|
||||
// and then doing a new navigation, meaning all the "forward" items are
|
||||
// deleted.
|
||||
//
|
||||
// This normally happens as a result of a new navigation. It will be
|
||||
// followed by a NAV_ENTRY_COMMITTED message for the new page that
|
||||
// caused the pruning. It could also be a result of removing an item from
|
||||
// the list to fix up after interstitials.
|
||||
//
|
||||
// The details are NavigationController::PrunedDetails.
|
||||
NAV_LIST_PRUNED,
|
||||
|
||||
// Indicates that a NavigationEntry has changed. The source will be the
|
||||
// NavigationController that owns the NavigationEntry. The details will be
|
||||
// a NavigationController::EntryChangedDetails struct.
|
||||
//
|
||||
// This will NOT be sent on navigation, interested parties should also
|
||||
// listen for NAV_ENTRY_COMMITTED to handle that case. This will be
|
||||
// sent when the entry is updated outside of navigation (like when a new
|
||||
// title comes).
|
||||
NAV_ENTRY_CHANGED,
|
||||
|
||||
// Other load-related (not from NavigationController) ----------------------
|
||||
|
||||
// A content load is starting. The source will be a
|
||||
// Source<NavigationController> corresponding to the tab in which the load
|
||||
// is occurring. No details are expected for this notification.
|
||||
LOAD_START,
|
||||
|
||||
// A content load has stopped. The source will be a
|
||||
// Source<NavigationController> corresponding to the tab in which the load
|
||||
// is occurring. Details in the form of a LoadNotificationDetails object
|
||||
// are optional.
|
||||
LOAD_STOP,
|
||||
|
||||
// A frame is staring a provisional load. The source is a
|
||||
// Source<NavigationController> corresponding to the tab in which the load
|
||||
// occurs. Details is a bool specifying if the load occurs in the main
|
||||
// frame (or a sub-frame if false).
|
||||
FRAME_PROVISIONAL_LOAD_START,
|
||||
|
||||
// Content was loaded from an in-memory cache. The source will be a
|
||||
// Source<NavigationController> corresponding to the tab in which the load
|
||||
// occurred. Details in the form of a LoadFromMemoryCacheDetails object
|
||||
// are provided.
|
||||
LOAD_FROM_MEMORY_CACHE,
|
||||
|
||||
// A provisional content load has failed with an error. The source will be
|
||||
// a Source<NavigationController> corresponding to the tab in which the
|
||||
// load occurred. Details in the form of a ProvisionalLoadDetails object
|
||||
// are provided.
|
||||
FAIL_PROVISIONAL_LOAD_WITH_ERROR,
|
||||
|
||||
// A response has been received for a resource request. The source will be
|
||||
// a Source<NavigationController> corresponding to the tab in which the
|
||||
// request was issued. Details in the form of a ResourceRequestDetails
|
||||
// object are provided.
|
||||
RESOURCE_RESPONSE_STARTED,
|
||||
|
||||
// The response to a resource request has completed. The source will be a
|
||||
// Source<NavigationController> corresponding to the tab in which the
|
||||
// request was issued. Details in the form of a ResourceRequestDetails
|
||||
// object are provided.
|
||||
RESOURCE_RESPONSE_COMPLETED,
|
||||
|
||||
// A redirect was received while requesting a resource. The source will be
|
||||
// a Source<NavigationController> corresponding to the tab in which the
|
||||
// request was issued. Details in the form of a ResourceRedirectDetails
|
||||
// are provided.
|
||||
RESOURCE_RECEIVED_REDIRECT,
|
||||
|
||||
// The SSL state of a page has changed in some visible way. For example,
|
||||
// if an insecure resource is loaded on a secure page. Note that a
|
||||
// toplevel load commit will also update the SSL state (since the
|
||||
// NavigationEntry is new) and this message won't always be sent in that
|
||||
// case. Listen to this notification if you need to refresh SSL-related UI
|
||||
// elements.
|
||||
//
|
||||
// The source will be the navigation controller associated with the load.
|
||||
// There are no details. The entry changed will be the active entry of the
|
||||
// controller.
|
||||
SSL_VISIBLE_STATE_CHANGED,
|
||||
|
||||
// The SSL state of the browser has changed in some internal way. For
|
||||
// example, the user might have explicitly allowed some broken certificate
|
||||
// or a secure origin might have included some insecure content. Listen to
|
||||
// this notifiation if you need to keep track of our internal SSL state.
|
||||
//
|
||||
// The source will be the navigation controller associated with the state
|
||||
// change. There are no details.
|
||||
SSL_INTERNAL_STATE_CHANGED,
|
||||
|
||||
// Lets resource handlers and other interested observers know when the
|
||||
// message filter is being deleted and can no longer be used.
|
||||
RESOURCE_MESSAGE_FILTER_SHUTDOWN,
|
||||
|
||||
// Views -------------------------------------------------------------------
|
||||
|
||||
// Notification that a view was removed from a view hierarchy. The source
|
||||
// is the view, the details is the parent view.
|
||||
VIEW_REMOVED,
|
||||
|
||||
// Browser-window ----------------------------------------------------------
|
||||
|
||||
// This message is sent after a window has been opened. The source is a
|
||||
// Source<Browser> with a pointer to the new window. No details are
|
||||
// expected.
|
||||
BROWSER_OPENED,
|
||||
|
||||
// This message is sent after a window has been closed. The source is a
|
||||
// Source<Browser> with a pointer to the closed window. Details is a
|
||||
// boolean that if true indicates that the application will be closed as a
|
||||
// result of this browser window closure (i.e. this was the last opened
|
||||
// browser window). Note that the boolean pointed to by Details is only
|
||||
// valid for the duration of this call.
|
||||
BROWSER_CLOSED,
|
||||
|
||||
// This message is sent when the last window considered to be an
|
||||
// "application window" has been closed. Dependent/dialog/utility windows
|
||||
// can use this as a way to know that they should also close. No source or
|
||||
// details are passed.
|
||||
ALL_APPWINDOWS_CLOSED,
|
||||
|
||||
// Indicates a new top window has been created. The source is the
|
||||
// WindowWin.
|
||||
WINDOW_CREATED,
|
||||
|
||||
// Indicates that a top window has been closed. The source is the HWND
|
||||
// that was closed, no details are expected.
|
||||
WINDOW_CLOSED,
|
||||
|
||||
// Sent when an info bubble has been created but not yet shown. The source
|
||||
// is the InfoBubble.
|
||||
INFO_BUBBLE_CREATED,
|
||||
|
||||
// Tabs --------------------------------------------------------------------
|
||||
|
||||
// This notification is sent after a tab has been appended to the
|
||||
// tab_strip. The source is a Source<NavigationController> with a pointer
|
||||
// to controller for the added tab. There are no details.
|
||||
TAB_PARENTED,
|
||||
|
||||
// This message is sent before a tab has been closed. The source is a
|
||||
// Source<NavigationController> with a pointer to the controller for the
|
||||
// closed tab. No details are expected.
|
||||
//
|
||||
// See also TAB_CLOSED.
|
||||
TAB_CLOSING,
|
||||
|
||||
// Notification that a tab has been closed. The source is the
|
||||
// NavigationController with no details.
|
||||
TAB_CLOSED,
|
||||
|
||||
// This notification is sent when a render view host has connected to a
|
||||
// renderer process. The source is a Source<TabContents> with a pointer to
|
||||
// the TabContents. A TAB_CONTENTS_DISCONNECTED notification is
|
||||
// guaranteed before the source pointer becomes junk. No details are
|
||||
// expected.
|
||||
TAB_CONTENTS_CONNECTED,
|
||||
|
||||
// This notification is sent when a TabContents swaps its render view host
|
||||
// with another one, possibly changing processes. The source is a
|
||||
// Source<TabContents> with a pointer to the TabContents. A
|
||||
// TAB_CONTENTS_DISCONNECTED notification is guaranteed before the
|
||||
// source pointer becomes junk. No details are expected.
|
||||
TAB_CONTENTS_SWAPPED,
|
||||
|
||||
// This message is sent after a TabContents is disconnected from the
|
||||
// renderer process. The source is a Source<TabContents> with a pointer to
|
||||
// the TabContents (the pointer is usable). No details are expected.
|
||||
TAB_CONTENTS_DISCONNECTED,
|
||||
|
||||
// This message is sent when a new InfoBar has been added to a TabContents.
|
||||
// The source is a Source<TabContents> with a pointer to the TabContents
|
||||
// the InfoBar was added to. The details is a Details<InfoBarDelegate> with
|
||||
// a pointer to an object implementing the InfoBarDelegate interface for
|
||||
// the InfoBar that was added.
|
||||
TAB_CONTENTS_INFOBAR_ADDED,
|
||||
|
||||
// This message is sent when an InfoBar is about to be removed from a
|
||||
// TabContents. The source is a Source<TabContents> with a pointer to the
|
||||
// TabContents the InfoBar was removed from. The details is a
|
||||
// Details<InfoBarDelegate> with a pointer to an object implementing the
|
||||
// InfoBarDelegate interface for the InfoBar that was removed.
|
||||
TAB_CONTENTS_INFOBAR_REMOVED,
|
||||
|
||||
// This is sent when an externally hosted tab is created. The details
|
||||
// contain the ExternalTabContainer that contains the tab
|
||||
EXTERNAL_TAB_CREATED,
|
||||
|
||||
// This is sent when an externally hosted tab is closed. No details are
|
||||
// expected.
|
||||
EXTERNAL_TAB_CLOSED,
|
||||
|
||||
// Indicates that the new page tab has finished loading. This is used for
|
||||
// performance testing to see how fast we can load it after startup, and is
|
||||
// only called once for the lifetime of the browser. The source is unused.
|
||||
// Details is an integer: the number of milliseconds elapsed between
|
||||
// starting and finishing all painting.
|
||||
INITIAL_NEW_TAB_UI_LOAD,
|
||||
|
||||
// This notification is sent when a TabContents is being hidden, e.g. due
|
||||
// to switching away from this tab. The source is a Source<TabContents>.
|
||||
TAB_CONTENTS_HIDDEN,
|
||||
|
||||
// This notification is sent when a TabContents is being destroyed. Any
|
||||
// object holding a reference to a TabContents can listen to that
|
||||
// notification to properly reset the reference. The source is a
|
||||
// Source<TabContents>.
|
||||
TAB_CONTENTS_DESTROYED,
|
||||
|
||||
// Stuff inside the tabs ---------------------------------------------------
|
||||
|
||||
// This message is sent after a constrained window has been closed. The
|
||||
// source is a Source<ConstrainedWindow> with a pointer to the closed child
|
||||
// window. (The pointer isn't usable, except for identification.) No
|
||||
// details are expected.
|
||||
CWINDOW_CLOSED,
|
||||
|
||||
// Indicates that a RenderProcessHost is destructing. The source will be the
|
||||
// RenderProcessHost that corresponds to the process.
|
||||
RENDERER_PROCESS_TERMINATED,
|
||||
|
||||
// Indicates that a render process was closed (meaning it exited, but the
|
||||
// RenderProcessHost might be reused). The source will be the corresponding
|
||||
// RenderProcessHost. The details will be a bool which is true if the
|
||||
// process crashed. This may get sent along with
|
||||
// RENDERER_PROCESS_TERMINATED.
|
||||
RENDERER_PROCESS_CLOSED,
|
||||
|
||||
// Indicates that a render process has become unresponsive for a period of
|
||||
// time. The source will be the RenderWidgetHost that corresponds to the
|
||||
// hung view, and no details are expected.
|
||||
RENDERER_PROCESS_HANG,
|
||||
|
||||
// Indicates that a render process is created in the sandbox. The source
|
||||
// will be the RenderProcessHost that corresponds to the created process
|
||||
// and the detail is a bool telling us if the process got created on the
|
||||
// sandbox desktop or not.
|
||||
RENDERER_PROCESS_IN_SBOX,
|
||||
|
||||
// This is sent to notify that the RenderViewHost displayed in a
|
||||
// TabContents has changed. Source is the TabContents for which the change
|
||||
// happened, details is the previous RenderViewHost (can be NULL when the
|
||||
// first RenderViewHost is set).
|
||||
RENDER_VIEW_HOST_CHANGED,
|
||||
|
||||
// This is sent when a RenderWidgetHost is being destroyed. The source is
|
||||
// the RenderWidgetHost, the details are not used.
|
||||
RENDER_WIDGET_HOST_DESTROYED,
|
||||
|
||||
// Notification from TabContents that we have received a response from the
|
||||
// renderer after using the dom inspector.
|
||||
DOM_INSPECT_ELEMENT_RESPONSE,
|
||||
|
||||
// Notification from TabContents that we have received a response from the
|
||||
// renderer in response to a dom automation controller action.
|
||||
DOM_OPERATION_RESPONSE,
|
||||
|
||||
// Sent when the bookmark bubble hides. The source is the profile, the
|
||||
// details unused.
|
||||
BOOKMARK_BUBBLE_HIDDEN,
|
||||
|
||||
// This notification is sent when the result of a find-in-page search is
|
||||
// available with the browser process. The source is a Source<TabContents>
|
||||
// with a pointer to the TabContents. Details encompass a
|
||||
// FindNotificationDetail object that tells whether the match was found or
|
||||
// not found.
|
||||
FIND_RESULT_AVAILABLE,
|
||||
|
||||
// This is sent when the users preference for when the bookmark bar should
|
||||
// be shown changes. The source is the profile, and the details are
|
||||
// NoDetails.
|
||||
BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
|
||||
|
||||
// Used to monitor web cache usage by notifying whenever the
|
||||
// CacheManagerHost observes new UsageStats. The source will be the
|
||||
// RenderProcessHost that corresponds to the new statistics. Details are a
|
||||
// UsageStats object sent by the renderer, and should be copied - ptr not
|
||||
// guaranteed to be valid after the notification.
|
||||
WEB_CACHE_STATS_OBSERVED,
|
||||
|
||||
// Child Processes ---------------------------------------------------------
|
||||
|
||||
// This notification is sent when a child process host has connected to a
|
||||
// child process. There is no usable source, since it is sent from an
|
||||
// ephemeral task; register for AllSources() to receive this notification.
|
||||
// The details are in a Details<ChildProcessInfo>.
|
||||
CHILD_PROCESS_HOST_CONNECTED,
|
||||
|
||||
// This message is sent after a ChildProcessHost is disconnected from the
|
||||
// child process. There is no usable source, since it is sent from an
|
||||
// ephemeral task; register for AllSources() to receive this notification.
|
||||
// The details are in a Details<ChildProcessInfo>.
|
||||
CHILD_PROCESS_HOST_DISCONNECTED,
|
||||
|
||||
// This message is sent when a child process disappears unexpectedly.
|
||||
// There is no usable source, since it is sent from an ephemeral task;
|
||||
// register for AllSources() to receive this notification. The details are
|
||||
// in a Details<ChildProcessInfo>.
|
||||
CHILD_PROCESS_CRASHED,
|
||||
|
||||
// This message indicates that an instance of a particular child was
|
||||
// created in a page. (If one page contains several regions rendered by
|
||||
// the same child, this notification will occur once for each region
|
||||
// during the page load.)
|
||||
//
|
||||
// There is no usable source, since it is sent from an ephemeral task;
|
||||
// register for AllSources() to receive this notification. The details are
|
||||
// in a Details<ChildProcessInfo>.
|
||||
CHILD_INSTANCE_CREATED,
|
||||
|
||||
// This is sent when network interception is disabled for a plugin, or the
|
||||
// plugin is unloaded. This should only be sent/received on the browser IO
|
||||
// thread or the plugin thread. The source is the plugin that is disabling
|
||||
// interception. No details are expected.
|
||||
CHROME_PLUGIN_UNLOADED,
|
||||
|
||||
// This is sent when a login prompt is shown. The source is the
|
||||
// Source<NavigationController> for the tab in which the prompt is shown.
|
||||
// Details are a LoginNotificationDetails which provide the LoginHandler
|
||||
// that should be given authentication.
|
||||
AUTH_NEEDED,
|
||||
|
||||
// This is sent when authentication credentials have been supplied (either
|
||||
// by the user or by an automation service), but before we've actually
|
||||
// received another response from the server. The source is the
|
||||
// Source<NavigationController> for the tab in which the prompt was shown.
|
||||
// No details are expected.
|
||||
AUTH_SUPPLIED,
|
||||
|
||||
// History -----------------------------------------------------------------
|
||||
|
||||
// Sent when a history service is created on the main thread. This is sent
|
||||
// after history is created, but before it has finished loading. Use
|
||||
// HISTORY_LOADED is you need to know when loading has completed.
|
||||
// The source is the profile that the history service belongs to, and the
|
||||
// details is the pointer to the newly created HistoryService object.
|
||||
HISTORY_CREATED,
|
||||
|
||||
// Sent when a history service has finished loading. The source is the
|
||||
// profile that the history service belongs to, and the details is the
|
||||
// HistoryService.
|
||||
HISTORY_LOADED,
|
||||
|
||||
// Sent when a URL that has been typed has been added or modified. This is
|
||||
// used by the in-memory URL database (used by autocomplete) to track
|
||||
// changes to the main history system.
|
||||
//
|
||||
// The source is the profile owning the history service that changed, and
|
||||
// the details is history::URLsModifiedDetails that lists the modified or
|
||||
// added URLs.
|
||||
HISTORY_TYPED_URLS_MODIFIED,
|
||||
|
||||
// Sent when the user visits a URL.
|
||||
//
|
||||
// The source is the profile owning the history service that changed, and
|
||||
// the details is history::URLVisitedDetails.
|
||||
HISTORY_URL_VISITED,
|
||||
|
||||
// Sent when one or more URLs are deleted.
|
||||
//
|
||||
// The source is the profile owning the history service that changed, and
|
||||
// the details is history::URLsDeletedDetails that lists the deleted URLs.
|
||||
HISTORY_URLS_DELETED,
|
||||
|
||||
// Sent by history when the favicon of a URL changes. The source is the
|
||||
// profile, and the details is history::FavIconChangeDetails (see
|
||||
// history_notifications.h).
|
||||
FAVICON_CHANGED,
|
||||
|
||||
// Bookmarks ---------------------------------------------------------------
|
||||
|
||||
// Sent when the starred state of a URL changes. A URL is starred if there
|
||||
// is at least one bookmark for it. The source is a Profile and the details
|
||||
// is history::URLsStarredDetails that contains the list of URLs and
|
||||
// whether they were starred or unstarred.
|
||||
URLS_STARRED,
|
||||
|
||||
// Sent when the bookmark bar model finishes loading. This source is the
|
||||
// Profile, and the details aren't used.
|
||||
BOOKMARK_MODEL_LOADED,
|
||||
|
||||
// Sent when the spellchecker object changes. Note that this is not sent
|
||||
// the first time the spellchecker gets initialized. The source is the
|
||||
// profile, the details is SpellcheckerReinitializedDetails defined in
|
||||
// profile.
|
||||
SPELLCHECKER_REINITIALIZED,
|
||||
|
||||
// Sent when the bookmark bubble is shown for a particular URL. The source
|
||||
// is the profile, the details the URL.
|
||||
BOOKMARK_BUBBLE_SHOWN,
|
||||
|
||||
// Non-history storage services --------------------------------------------
|
||||
|
||||
// Notification that the TemplateURLModel has finished loading from the
|
||||
// database. The source is the TemplateURLModel, and the details are
|
||||
// NoDetails.
|
||||
TEMPLATE_URL_MODEL_LOADED,
|
||||
|
||||
// Notification triggered when a web application has been installed or
|
||||
// uninstalled. Any application view should reload its data. The source is
|
||||
// the profile. No details are provided.
|
||||
WEB_APP_INSTALL_CHANGED,
|
||||
|
||||
// This is sent to a pref observer when a pref is changed.
|
||||
PREF_CHANGED,
|
||||
|
||||
// Sent when a default request context has been created, so calling
|
||||
// Profile::GetDefaultRequestContext() will not return NULL. This is sent
|
||||
// on the thread where Profile::GetRequestContext() is first called, which
|
||||
// should be the UI thread.
|
||||
DEFAULT_REQUEST_CONTEXT_AVAILABLE,
|
||||
|
||||
// Autocomplete ------------------------------------------------------------
|
||||
|
||||
// Sent by the autocomplete controller at least once per query, each time
|
||||
// new matches are available, subject to rate-limiting/coalescing to reduce
|
||||
// the number of updates. There are no details.
|
||||
AUTOCOMPLETE_CONTROLLER_RESULT_UPDATED,
|
||||
|
||||
// Sent by the autocomplete controller once per query, immediately after
|
||||
// synchronous matches become available. There are no details.
|
||||
AUTOCOMPLETE_CONTROLLER_SYNCHRONOUS_MATCHES_AVAILABLE,
|
||||
|
||||
// This is sent when an item of the Omnibox popup is selected. The source
|
||||
// is the profile.
|
||||
OMNIBOX_OPENED_URL,
|
||||
|
||||
// Sent by the autocomplete edit when it is destroyed.
|
||||
AUTOCOMPLETE_EDIT_DESTROYED,
|
||||
|
||||
// Sent when the main Google URL has been updated. Some services cache
|
||||
// this value and need to update themselves when it changes. See
|
||||
// google_util::GetGoogleURLAndUpdateIfNecessary().
|
||||
GOOGLE_URL_UPDATED,
|
||||
|
||||
// Printing ----------------------------------------------------------------
|
||||
|
||||
// Notification from a PrintedDocument that it has been updated. It may be
|
||||
// that a printed page has just been generated or that the document's
|
||||
// number of pages has been calculated. Details is the new page or NULL if
|
||||
// only the number of pages in the document has been updated.
|
||||
PRINTED_DOCUMENT_UPDATED,
|
||||
|
||||
// Notification from PrintJob that an event occured. It can be that a page
|
||||
// finished printing or that the print job failed. Details is
|
||||
// PrintJob::EventDetails.
|
||||
PRINT_JOB_EVENT,
|
||||
|
||||
// Shutdown ----------------------------------------------------------------
|
||||
|
||||
// Sent on the browser IO thread when an URLRequestContext is released by
|
||||
// its owning Profile. The source is a pointer to the URLRequestContext.
|
||||
URL_REQUEST_CONTEXT_RELEASED,
|
||||
|
||||
// Sent when WM_ENDSESSION has been received, after the browsers have been
|
||||
// closed but before browser process has been shutdown. The source/details
|
||||
// are all source and no details.
|
||||
SESSION_END,
|
||||
|
||||
// Personalization ---------------------------------------------------------
|
||||
|
||||
PERSONALIZATION,
|
||||
PERSONALIZATION_CREATED,
|
||||
|
||||
// User Scripts ------------------------------------------------------------
|
||||
|
||||
// Sent when there are new user scripts available. The details are a
|
||||
// pointer to SharedMemory containing the new scripts.
|
||||
USER_SCRIPTS_LOADED,
|
||||
|
||||
// Extensions --------------------------------------------------------------
|
||||
|
||||
// Sent when new extensions are loaded. The details are an ExtensionList*.
|
||||
EXTENSIONS_LOADED,
|
||||
|
||||
// Sent when new extensions are installed. The details are a FilePath.
|
||||
EXTENSION_INSTALLED,
|
||||
|
||||
// Debugging ---------------------------------------------------------------
|
||||
|
||||
// Sent from ~RenderViewHost. The source is the RenderViewHost.
|
||||
RENDER_VIEW_HOST_DELETED,
|
||||
|
||||
// Count (must be last) ----------------------------------------------------
|
||||
// Used to determine the number of notification types. Not valid as
|
||||
// a type parameter when registering for or posting notifications.
|
||||
NOTIFICATION_TYPE_COUNT
|
||||
};
|
||||
|
||||
explicit NotificationType(Type v) : value(v) {}
|
||||
|
||||
bool operator==(NotificationType t) const { return value == t.value; }
|
||||
bool operator!=(NotificationType t) const { return value != t.value; }
|
||||
|
||||
// Comparison to explicit enum values.
|
||||
bool operator==(Type v) const { return value == v; }
|
||||
bool operator!=(Type v) const { return value != v; }
|
||||
|
||||
Type value;
|
||||
};
|
||||
|
||||
inline bool operator==(NotificationType::Type a, NotificationType b) {
|
||||
return a == b.value;
|
||||
}
|
||||
inline bool operator!=(NotificationType::Type a, NotificationType b) {
|
||||
return a != b.value;
|
||||
}
|
||||
|
||||
#endif // CHROME_COMMON_NOTIFICATION_TYPE_H_
|
|
@ -9,32 +9,50 @@
|
|||
#include "base/message_loop.h"
|
||||
#include "base/object_watcher.h"
|
||||
#include "base/sys_info.h"
|
||||
#include "chrome/common/result_codes.h"
|
||||
|
||||
// Maximum amount of time (in milliseconds) to wait for the process to exit.
|
||||
static const int kWaitInterval = 2000;
|
||||
|
||||
namespace {
|
||||
|
||||
class TimerExpiredTask : public mozilla::Runnable,
|
||||
public base::ObjectWatcher::Delegate {
|
||||
class ChildReaper : public mozilla::Runnable,
|
||||
public base::ObjectWatcher::Delegate,
|
||||
public MessageLoop::DestructionObserver {
|
||||
public:
|
||||
explicit TimerExpiredTask(base::ProcessHandle process) : process_(process) {
|
||||
explicit ChildReaper(base::ProcessHandle process, bool force)
|
||||
: process_(process), force_(force) {
|
||||
watcher_.StartWatching(process_, this);
|
||||
}
|
||||
|
||||
virtual ~TimerExpiredTask() {
|
||||
virtual ~ChildReaper() {
|
||||
if (process_) {
|
||||
KillProcess();
|
||||
DCHECK(!process_) << "Make sure to close the handle.";
|
||||
}
|
||||
}
|
||||
|
||||
// MessageLoop::DestructionObserver -----------------------------------------
|
||||
|
||||
virtual void WillDestroyCurrentMessageLoop()
|
||||
{
|
||||
MOZ_ASSERT(!force_);
|
||||
if (process_) {
|
||||
WaitForSingleObject(process_, INFINITE);
|
||||
base::CloseProcessHandle(process_);
|
||||
process_ = 0;
|
||||
|
||||
MessageLoop::current()->RemoveDestructionObserver(this);
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
// Task ---------------------------------------------------------------------
|
||||
|
||||
NS_IMETHOD Run() override {
|
||||
if (process_)
|
||||
MOZ_ASSERT(force_);
|
||||
if (process_) {
|
||||
KillProcess();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -46,16 +64,23 @@ class TimerExpiredTask : public mozilla::Runnable,
|
|||
watcher_.StopWatching();
|
||||
|
||||
base::CloseProcessHandle(process_);
|
||||
process_ = NULL;
|
||||
process_ = 0;
|
||||
|
||||
if (!force_) {
|
||||
MessageLoop::current()->RemoveDestructionObserver(this);
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void KillProcess() {
|
||||
MOZ_ASSERT(force_);
|
||||
|
||||
// OK, time to get frisky. We don't actually care when the process
|
||||
// terminates. We just care that it eventually terminates, and that's what
|
||||
// TerminateProcess should do for us. Don't check for the result code since
|
||||
// it fails quite often. This should be investigated eventually.
|
||||
TerminateProcess(process_, ResultCodes::HUNG);
|
||||
TerminateProcess(process_, base::PROCESS_END_PROCESS_WAS_HUNG);
|
||||
|
||||
// Now, just cleanup as if the process exited normally.
|
||||
OnObjectSignaled(process_);
|
||||
|
@ -66,31 +91,28 @@ class TimerExpiredTask : public mozilla::Runnable,
|
|||
|
||||
base::ObjectWatcher watcher_;
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(TimerExpiredTask);
|
||||
bool force_;
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(ChildReaper);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
void ProcessWatcher::EnsureProcessTerminated(base::ProcessHandle process
|
||||
, bool force
|
||||
) {
|
||||
void ProcessWatcher::EnsureProcessTerminated(base::ProcessHandle process, bool force) {
|
||||
DCHECK(process != GetCurrentProcess());
|
||||
|
||||
if (!force) {
|
||||
WaitForSingleObject(process, INFINITE);
|
||||
base::CloseProcessHandle(process);
|
||||
return;
|
||||
}
|
||||
|
||||
// If already signaled, then we are done!
|
||||
if (WaitForSingleObject(process, 0) == WAIT_OBJECT_0) {
|
||||
base::CloseProcessHandle(process);
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<mozilla::Runnable> task = new TimerExpiredTask(process);
|
||||
|
||||
MessageLoop::current()->PostDelayedTask(task.forget(),
|
||||
kWaitInterval);
|
||||
MessageLoopForIO* loop = MessageLoopForIO::current();
|
||||
if (force) {
|
||||
RefPtr<mozilla::Runnable> task = new ChildReaper(process, force);
|
||||
loop->PostDelayedTask(task.forget(), kWaitInterval);
|
||||
} else {
|
||||
loop->AddDestructionObserver(new ChildReaper(process, force));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_COMMON_RESULT_CODES_H_
|
||||
#define CHROME_COMMON_RESULT_CODES_H_
|
||||
|
||||
#include "base/process_util.h"
|
||||
|
||||
// This file consolidates all the return codes for the browser and renderer
|
||||
// process. The return code is the value that:
|
||||
// a) is returned by main() or winmain(), or
|
||||
// b) specified in the call for ExitProcess() or TerminateProcess(), or
|
||||
// c) the exception value that causes a process to terminate.
|
||||
//
|
||||
// It is advisable to not use negative numbers because the Windows API returns
|
||||
// it as an unsigned long and the exception values have high numbers. For
|
||||
// example EXCEPTION_ACCESS_VIOLATION value is 0xC0000005.
|
||||
|
||||
class ResultCodes {
|
||||
public:
|
||||
enum ExitCode {
|
||||
NORMAL_EXIT = base::PROCESS_END_NORMAL_TERMINATON,
|
||||
TASKMAN_KILL = base::PROCESS_END_KILLED_BY_USER,
|
||||
HUNG = base::PROCESS_END_PROCESS_WAS_HUNG,
|
||||
INVALID_CMDLINE_URL, // An invalid command line url was given.
|
||||
SBOX_INIT_FAILED, // The sandbox could not be initialized.
|
||||
GOOGLE_UPDATE_INIT_FAILED, // The Google Update client stub init failed.
|
||||
GOOGLE_UPDATE_LAUNCH_FAILED,// Google Update could not launch chrome DLL.
|
||||
BAD_PROCESS_TYPE, // The process is of an unknown type.
|
||||
MISSING_PATH, // An critical chrome path is missing.
|
||||
MISSING_DATA, // A critical chrome file is missing.
|
||||
SHELL_INTEGRATION_FAILED, // Failed to make Chrome default browser.
|
||||
MACHINE_LEVEL_INSTALL_EXISTS, // Machine level install exists
|
||||
UNINSTALL_DELETE_FILE_ERROR,// Error while deleting shortcuts.
|
||||
UNINSTALL_CHROME_ALIVE, // Uninstall detected another chrome instance.
|
||||
UNINSTALL_NO_SURVEY, // Do not launch survey after uninstall.
|
||||
UNINSTALL_USER_CANCEL, // The user changed her mind.
|
||||
UNINSTALL_DELETE_PROFILE, // Delete profile as well during uninstall.
|
||||
UNSUPPORTED_PARAM, // Command line parameter is not supported.
|
||||
KILLED_BAD_MESSAGE, // A bad message caused the process termination.
|
||||
IMPORTER_CANCEL, // The user canceled the browser import.
|
||||
IMPORTER_HUNG, // Browser import hung and was killed.
|
||||
EXIT_LAST_CODE // Last return code (keep it last).
|
||||
};
|
||||
};
|
||||
|
||||
#endif // CHROME_COMMON_RESULT_CODES_H_
|
|
@ -5,7 +5,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/ipc/BrowserProcessSubThread.h"
|
||||
#include "chrome/common/notification_service.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <objbase.h>
|
||||
|
@ -42,8 +41,7 @@ BrowserProcessSubThread* BrowserProcessSubThread::sBrowserThreads[ID_COUNT] = {
|
|||
|
||||
BrowserProcessSubThread::BrowserProcessSubThread(ID aId) :
|
||||
base::Thread(kBrowserThreadNames[aId]),
|
||||
mIdentifier(aId),
|
||||
mNotificationService(nullptr)
|
||||
mIdentifier(aId)
|
||||
{
|
||||
StaticMutexAutoLock lock(sLock);
|
||||
DCHECK(aId >= 0 && aId < ID_COUNT);
|
||||
|
@ -68,15 +66,11 @@ BrowserProcessSubThread::Init()
|
|||
// Initializes the COM library on the current thread.
|
||||
CoInitialize(nullptr);
|
||||
#endif
|
||||
mNotificationService = new NotificationService();
|
||||
}
|
||||
|
||||
void
|
||||
BrowserProcessSubThread::CleanUp()
|
||||
{
|
||||
delete mNotificationService;
|
||||
mNotificationService = nullptr;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Closes the COM library on the current thread. CoInitialize must
|
||||
// be balanced by a corresponding call to CoUninitialize.
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
|
||||
#include "nsDebug.h"
|
||||
|
||||
class NotificationService;
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
|
@ -54,8 +52,6 @@ private:
|
|||
// identifier at a given time.
|
||||
ID mIdentifier;
|
||||
|
||||
NotificationService* mNotificationService;
|
||||
|
||||
// This lock protects |browser_threads_|. Do not read or modify that array
|
||||
// without holding this lock. Do not block while holding this lock.
|
||||
|
||||
|
|
|
@ -93,8 +93,7 @@ GeckoChildProcessHost::DefaultChildPrivileges()
|
|||
|
||||
GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
|
||||
ChildPrivileges aPrivileges)
|
||||
: ChildProcessHost(RENDER_PROCESS), // FIXME/cjones: we should own this enum
|
||||
mProcessType(aProcessType),
|
||||
: mProcessType(aProcessType),
|
||||
mPrivileges(aPrivileges),
|
||||
mMonitor("mozilla.ipc.GeckChildProcessHost.mMonitor"),
|
||||
mProcessState(CREATING_CHANNEL),
|
||||
|
@ -102,12 +101,10 @@ GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
|
|||
mEnableSandboxLogging(false),
|
||||
mSandboxLevel(0),
|
||||
#endif
|
||||
mDelegate(nullptr),
|
||||
mChildProcessHandle(0)
|
||||
#if defined(MOZ_WIDGET_COCOA)
|
||||
, mChildTask(MACH_PORT_NULL)
|
||||
#endif
|
||||
, mAssociatedActors(1)
|
||||
{
|
||||
MOZ_COUNT_CTOR(GeckoChildProcessHost);
|
||||
}
|
||||
|
@ -487,26 +484,6 @@ GeckoChildProcessHost::SetAlreadyDead()
|
|||
mChildProcessHandle = 0;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void
|
||||
DelayedDeleteSubprocess(GeckoChildProcessHost* aSubprocess)
|
||||
{
|
||||
XRE_GetIOMessageLoop()
|
||||
->PostTask(mozilla::MakeAndAddRef<DeleteTask<GeckoChildProcessHost>>(aSubprocess));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
GeckoChildProcessHost::DissociateActor()
|
||||
{
|
||||
if (!--mAssociatedActors) {
|
||||
MessageLoop::current()->
|
||||
PostTask(NewRunnableFunction(DelayedDeleteSubprocess, this));
|
||||
}
|
||||
}
|
||||
|
||||
int32_t GeckoChildProcessHost::mChildCounter = 0;
|
||||
|
||||
void
|
||||
|
@ -1160,7 +1137,6 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExt
|
|||
// NB: on OS X, we block much longer than we need to in order to
|
||||
// reach this call, waiting for the child process's task_t. The
|
||||
// best way to fix that is to refactor this file, hard.
|
||||
SetHandle(process);
|
||||
#if defined(MOZ_WIDGET_COCOA)
|
||||
mChildTask = child_task;
|
||||
#endif
|
||||
|
@ -1236,15 +1212,6 @@ GeckoChildProcessHost::GetQueuedMessages(std::queue<IPC::Message>& queue)
|
|||
// We expect the next listener to take over processing of our queue.
|
||||
}
|
||||
|
||||
void
|
||||
GeckoChildProcessHost::OnWaitableEventSignaled(base::WaitableEvent *event)
|
||||
{
|
||||
if (mDelegate) {
|
||||
mDelegate->OnWaitableEventSignaled(event);
|
||||
}
|
||||
ChildProcessHost::OnWaitableEventSignaled(event);
|
||||
}
|
||||
|
||||
bool GeckoChildProcessHost::sRunSelfAsContentProc(false);
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include "base/waitable_event.h"
|
||||
#include "chrome/common/child_process_host.h"
|
||||
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/ipc/FileDescriptor.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
|
@ -93,16 +92,10 @@ public:
|
|||
|
||||
virtual bool CanShutdown() { return true; }
|
||||
|
||||
virtual void OnWaitableEventSignaled(base::WaitableEvent *event);
|
||||
|
||||
IPC::Channel* GetChannel() {
|
||||
return channelp();
|
||||
}
|
||||
|
||||
base::WaitableEvent* GetShutDownEvent() {
|
||||
return GetProcessEvent();
|
||||
}
|
||||
|
||||
// Returns a "borrowed" handle to the child process - the handle returned
|
||||
// by this function must not be closed by the caller.
|
||||
ProcessHandle GetChildProcessHandle() {
|
||||
|
@ -128,14 +121,6 @@ public:
|
|||
// For bug 943174: Skip the EnsureProcessTerminated call in the destructor.
|
||||
void SetAlreadyDead();
|
||||
|
||||
// This associates an actor telling the process host to stay alive at least
|
||||
// until DissociateActor has been called.
|
||||
void AssociateActor() { mAssociatedActors++; }
|
||||
|
||||
// This gets called when actors get destroyed and will schedule the object
|
||||
// for deletion when all actors have cleared their associations.
|
||||
void DissociateActor();
|
||||
|
||||
static void EnableSameExecutableForContentProc() { sRunSelfAsContentProc = true; }
|
||||
|
||||
protected:
|
||||
|
@ -183,8 +168,6 @@ protected:
|
|||
base::file_handle_mapping_vector mFileMap;
|
||||
#endif
|
||||
|
||||
base::WaitableEventWatcher::Delegate* mDelegate;
|
||||
|
||||
ProcessHandle mChildProcessHandle;
|
||||
#if defined(OS_MACOSX)
|
||||
task_t mChildTask;
|
||||
|
@ -218,10 +201,6 @@ private:
|
|||
// FIXME/cjones: this strongly indicates bad design. Shame on us.
|
||||
std::queue<IPC::Message> mQueue;
|
||||
|
||||
// This tracks how many actors are associated with this process that require
|
||||
// it to stay alive and have not yet been destroyed.
|
||||
Atomic<int32_t> mAssociatedActors;
|
||||
|
||||
// Remember original env values so we can restore it (there is no other
|
||||
// simple way how to change environment of a child process than to modify
|
||||
// the current environment).
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
|
||||
#include "base/eintr_wrapper.h"
|
||||
|
||||
#include "chrome/common/child_process_info.h"
|
||||
|
||||
#include "mozilla/ipc/Transport.h"
|
||||
#include "mozilla/ipc/FileDescriptor.h"
|
||||
#include "ProtocolUtils.h"
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "base/message_loop.h"
|
||||
#include "chrome/common/child_process_info.h"
|
||||
|
||||
#include "mozilla/ipc/Transport.h"
|
||||
#include "mozilla/ipc/ProtocolUtils.h"
|
||||
|
|
|
@ -494,8 +494,6 @@ XPCShellEnvironment::Init()
|
|||
|
||||
AutoSafeJSContext cx;
|
||||
|
||||
JS_SetContextPrivate(cx, this);
|
||||
|
||||
nsCOMPtr<nsIXPConnect> xpc =
|
||||
do_GetService(nsIXPConnect::GetCID());
|
||||
if (!xpc) {
|
||||
|
|
|
@ -400,9 +400,9 @@ ToIntWidth(double d)
|
|||
inline int32_t
|
||||
ToInt32(double d)
|
||||
{
|
||||
// clang crashes compiling this when targeting arm-darwin:
|
||||
// clang crashes compiling this when targeting arm:
|
||||
// https://llvm.org/bugs/show_bug.cgi?id=22974
|
||||
#if defined (__arm__) && defined (__GNUC__) && !defined(__APPLE__)
|
||||
#if defined (__arm__) && defined (__GNUC__) && !defined(__clang__)
|
||||
int32_t i;
|
||||
uint32_t tmp0;
|
||||
uint32_t tmp1;
|
||||
|
|
|
@ -2111,10 +2111,25 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
|
|||
case PNK_TYPEOFEXPR:
|
||||
case PNK_VOID:
|
||||
case PNK_NOT:
|
||||
case PNK_COMPUTED_NAME:
|
||||
MOZ_ASSERT(pn->isArity(PN_UNARY));
|
||||
return checkSideEffects(pn->pn_kid, answer);
|
||||
|
||||
// Even if the name expression is effect-free, performing ToPropertyKey on
|
||||
// it might not be effect-free:
|
||||
//
|
||||
// RegExp.prototype.toString = () => { throw 42; };
|
||||
// ({ [/regex/]: 0 }); // ToPropertyKey(/regex/) throws 42
|
||||
//
|
||||
// function Q() {
|
||||
// ({ [new.target]: 0 });
|
||||
// }
|
||||
// Q.toString = () => { throw 17; };
|
||||
// new Q; // new.target will be Q, ToPropertyKey(Q) throws 17
|
||||
case PNK_COMPUTED_NAME:
|
||||
MOZ_ASSERT(pn->isArity(PN_UNARY));
|
||||
*answer = true;
|
||||
return true;
|
||||
|
||||
// Looking up or evaluating the associated name could throw.
|
||||
case PNK_TYPEOFNAME:
|
||||
MOZ_ASSERT(pn->isArity(PN_UNARY));
|
||||
|
|
|
@ -223,16 +223,13 @@ AutoGCRooter::trace(JSTracer* trc)
|
|||
/* static */ void
|
||||
AutoGCRooter::traceAll(JSTracer* trc)
|
||||
{
|
||||
if (JSContext* cx = trc->runtime()->maybeContextFromMainThread())
|
||||
traceAllInContext(cx, trc);
|
||||
traceAllInContext(trc->runtime()->contextFromMainThread(), trc);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
AutoGCRooter::traceAllWrappers(JSTracer* trc)
|
||||
{
|
||||
JSContext* cx = trc->runtime()->maybeContextFromMainThread();
|
||||
if (!cx)
|
||||
return;
|
||||
JSContext* cx = trc->runtime()->contextFromMainThread();
|
||||
|
||||
for (AutoGCRooter* gcr = cx->roots.autoGCRooters_; gcr; gcr = gcr->down) {
|
||||
if (gcr->tag_ == WRAPVECTOR || gcr->tag_ == WRAPPER)
|
||||
|
@ -320,8 +317,7 @@ js::gc::GCRuntime::markRuntime(JSTracer* trc, TraceOrMarkRuntime traceOrMark,
|
|||
if (rt->isHeapMinorCollecting())
|
||||
jit::JitRuntime::MarkJitcodeGlobalTableUnconditionally(trc);
|
||||
|
||||
if (JSContext* cx = rt->maybeContextFromMainThread())
|
||||
cx->mark(trc);
|
||||
rt->contextFromMainThread()->mark(trc);
|
||||
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
|
||||
c->traceRoots(trc, traceOrMark);
|
||||
|
|
|
@ -93,10 +93,10 @@ static const int kWordAndSurrogateRanges[] = {
|
|||
static const int kWordAndSurrogateRangeCount = ArrayLength(kWordAndSurrogateRanges);
|
||||
static const int kNegatedIgnoreCaseWordAndSurrogateRanges[] = {
|
||||
0, '0', '9' + 1, 'A',
|
||||
'K', 'K' + 1, 'S', 'S' + 1,
|
||||
'Z' + 1, '_', '_' + 1, 'a',
|
||||
'k', 'k' + 1, 's', 's' + 1,
|
||||
'z' + 1, unicode::LeadSurrogateMin,
|
||||
'z' + 1, 0x017F,
|
||||
0x017F + 1, 0x212A,
|
||||
0x212A + 1, unicode::LeadSurrogateMin,
|
||||
unicode::TrailSurrogateMax + 1, 0x10000,
|
||||
0x10000 };
|
||||
static const int kNegatedIgnoreCaseWordAndSurrogateRangeCount =
|
||||
|
|
|
@ -32,7 +32,6 @@ function getTestCaseResult(expected, actual)
|
|||
function getFailedCases() {
|
||||
for ( var i = 0; i < gTestcases.length; i++ ) {}
|
||||
};
|
||||
function jit(on) {}
|
||||
var lfcode = new Array();
|
||||
lfcode.push("\
|
||||
var summary = 'decompilation of \"let with with\" ';\
|
||||
|
@ -47,7 +46,6 @@ function test() {\
|
|||
var w = 'r'.match(/r/);\
|
||||
new Function('for (var j = 0; j < 1; ++j) { } ')();\
|
||||
}\
|
||||
jit(('Math.log'));\
|
||||
reportCompare(expect, actual, summary);\
|
||||
}\
|
||||
");
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
|
||||
function jit(on)
|
||||
function Q(on)
|
||||
{
|
||||
options().match
|
||||
}
|
||||
function options() { return "methodjit"; }
|
||||
gczeal(2);
|
||||
for (i = 0; i < 100 ; ++i) { jit(jit(42, [])); }
|
||||
for (i = 0; i < 100 ; ++i) { Q(Q(42, [])); }
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "jit/arm/MacroAssembler-arm.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Casting.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
|
@ -4906,14 +4907,14 @@ MacroAssembler::callWithABIPost(uint32_t stackAdjust, MoveOp::Type result)
|
|||
if (!UseHardFpABI()) {
|
||||
// Move double from r0/r1 to ReturnFloatReg.
|
||||
ma_vxfer(r0, r1, ReturnDoubleReg);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MoveOp::FLOAT32:
|
||||
if (!UseHardFpABI()) {
|
||||
// Move float32 from r0 to ReturnFloatReg.
|
||||
ma_vxfer(r0, ReturnFloat32Reg.singleOverlay());
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MoveOp::GENERAL:
|
||||
break;
|
||||
|
||||
|
|
|
@ -1903,7 +1903,7 @@ Decoder::DecodeSpecialCondition(Instruction* instr)
|
|||
}
|
||||
break;
|
||||
}
|
||||
// else fall through
|
||||
MOZ_FALLTHROUGH;
|
||||
case 0xB:
|
||||
if ((instr->Bits(22, 20) == 5) && (instr->Bits(15, 12) == 0xf)) {
|
||||
int Rn = instr->Bits(19, 16);
|
||||
|
|
|
@ -466,22 +466,14 @@ JS_NewRuntime(uint32_t maxbytes, uint32_t maxNurseryBytes, JSRuntime* parentRunt
|
|||
while (parentRuntime && parentRuntime->parentRuntime)
|
||||
parentRuntime = parentRuntime->parentRuntime;
|
||||
|
||||
JSRuntime* rt = js_new<JSRuntime>(parentRuntime);
|
||||
if (!rt)
|
||||
return nullptr;
|
||||
|
||||
if (!rt->init(maxbytes, maxNurseryBytes)) {
|
||||
JS_DestroyRuntime(rt);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return rt;
|
||||
return NewContext(maxbytes, maxNurseryBytes, parentRuntime);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_DestroyRuntime(JSRuntime* rt)
|
||||
{
|
||||
js_delete(rt);
|
||||
JSContext* cx = rt->contextFromMainThread();
|
||||
DestroyContext(cx);
|
||||
}
|
||||
|
||||
static JS_CurrentEmbedderTimeFunction currentEmbedderTimeFunction;
|
||||
|
@ -563,30 +555,6 @@ JS_EndRequest(JSContext* cx)
|
|||
StopRequest(cx);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void*)
|
||||
JS_GetContextPrivate(JSContext* cx)
|
||||
{
|
||||
return cx->data;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_SetContextPrivate(JSContext* cx, void* data)
|
||||
{
|
||||
cx->data = data;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void*)
|
||||
JS_GetSecondContextPrivate(JSContext* cx)
|
||||
{
|
||||
return cx->data2;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_SetSecondContextPrivate(JSContext* cx, void* data)
|
||||
{
|
||||
cx->data2 = data;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSRuntime*)
|
||||
JS_GetRuntime(JSContext* cx)
|
||||
{
|
||||
|
|
|
@ -1041,18 +1041,6 @@ class MOZ_RAII JSAutoRequest
|
|||
#endif
|
||||
};
|
||||
|
||||
extern JS_PUBLIC_API(void*)
|
||||
JS_GetContextPrivate(JSContext* cx);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_SetContextPrivate(JSContext* cx, void* data);
|
||||
|
||||
extern JS_PUBLIC_API(void*)
|
||||
JS_GetSecondContextPrivate(JSContext* cx);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_SetSecondContextPrivate(JSContext* cx, void* data);
|
||||
|
||||
extern JS_PUBLIC_API(JSRuntime*)
|
||||
JS_GetRuntime(JSContext* cx);
|
||||
|
||||
|
|
|
@ -209,12 +209,6 @@ ClassName(JSProtoKey key, JSAtomState& atomState)
|
|||
return (&atomState.Null)[key];
|
||||
}
|
||||
|
||||
inline Handle<PropertyName*>
|
||||
ClassName(JSProtoKey key, JSRuntime* rt)
|
||||
{
|
||||
return ClassName(key, *rt->commonNames);
|
||||
}
|
||||
|
||||
inline Handle<PropertyName*>
|
||||
ClassName(JSProtoKey key, ExclusiveContext* cx)
|
||||
{
|
||||
|
|
|
@ -87,17 +87,27 @@ js::TraceCycleDetectionSet(JSTracer* trc, AutoCycleDetector::Set& set)
|
|||
TraceRoot(trc, &e.mutableFront(), "cycle detector table entry");
|
||||
}
|
||||
|
||||
JSContext*
|
||||
js::NewContext(JSRuntime* rt)
|
||||
bool
|
||||
JSContext::init(uint32_t maxBytes, uint32_t maxNurseryBytes)
|
||||
{
|
||||
MOZ_ASSERT(!rt->maybeContextFromMainThread());
|
||||
if (!JSRuntime::init(maxBytes, maxNurseryBytes))
|
||||
return false;
|
||||
|
||||
JS_AbortIfWrongThread(rt);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSContext* cx = js_new<JSContext>(rt);
|
||||
JSContext*
|
||||
js::NewContext(uint32_t maxBytes, uint32_t maxNurseryBytes, JSRuntime* parentRuntime)
|
||||
{
|
||||
JSContext* cx = js_new<JSContext>(parentRuntime);
|
||||
if (!cx)
|
||||
return nullptr;
|
||||
|
||||
if (!cx->init(maxBytes, maxNurseryBytes)) {
|
||||
js_delete(cx);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return cx;
|
||||
}
|
||||
|
||||
|
@ -858,8 +868,9 @@ ExclusiveContext::recoverFromOutOfMemory()
|
|||
task->outOfMemory = false;
|
||||
}
|
||||
|
||||
JSContext::JSContext(JSRuntime* rt)
|
||||
: ExclusiveContext(rt, &rt->mainThread, Context_JS),
|
||||
JSContext::JSContext(JSRuntime* parentRuntime)
|
||||
: ExclusiveContext(this, &this->JSRuntime::mainThread, Context_JS),
|
||||
JSRuntime(this, parentRuntime),
|
||||
throwing(false),
|
||||
unwrappedException_(this),
|
||||
overRecursed_(false),
|
||||
|
@ -869,8 +880,6 @@ JSContext::JSContext(JSRuntime* rt)
|
|||
resolvingList(nullptr),
|
||||
generatingError(false),
|
||||
cycleDetectorSet(this),
|
||||
data(nullptr),
|
||||
data2(nullptr),
|
||||
outstandingRequests(0),
|
||||
jitIsBroken(false)
|
||||
{
|
||||
|
@ -880,6 +889,8 @@ JSContext::JSContext(JSRuntime* rt)
|
|||
|
||||
JSContext::~JSContext()
|
||||
{
|
||||
destroyRuntime();
|
||||
|
||||
/* Free the stuff hanging off of cx. */
|
||||
MOZ_ASSERT(!resolvingList);
|
||||
}
|
||||
|
@ -1011,22 +1022,21 @@ JSContext::updateJITEnabled()
|
|||
}
|
||||
|
||||
size_t
|
||||
JSContext::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
|
||||
JSContext::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
|
||||
{
|
||||
/*
|
||||
* There are other JSContext members that could be measured; the following
|
||||
* ones have been found by DMD to be worth measuring. More stuff may be
|
||||
* added later.
|
||||
*/
|
||||
return mallocSizeOf(this) + cycleDetectorSet.sizeOfExcludingThis(mallocSizeOf);
|
||||
return cycleDetectorSet.sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
void
|
||||
JSContext::mark(JSTracer* trc)
|
||||
{
|
||||
/* Stack frames and slots are traced by StackSpace::mark. */
|
||||
|
||||
TraceCycleDetectionSet(trc, cycleDetectorSet);
|
||||
if (cycleDetectorSet.initialized())
|
||||
TraceCycleDetectionSet(trc, cycleDetectorSet);
|
||||
|
||||
if (compartment_)
|
||||
compartment_->mark();
|
||||
|
|
|
@ -295,11 +295,29 @@ void ReportOverRecursed(JSContext* cx, unsigned errorNumber);
|
|||
|
||||
} /* namespace js */
|
||||
|
||||
struct JSContext : public js::ExclusiveContext
|
||||
struct JSContext : public js::ExclusiveContext,
|
||||
public JSRuntime
|
||||
{
|
||||
explicit JSContext(JSRuntime* rt);
|
||||
explicit JSContext(JSRuntime* parentRuntime);
|
||||
~JSContext();
|
||||
|
||||
bool init(uint32_t maxBytes, uint32_t maxNurseryBytes);
|
||||
|
||||
// For names that exist in both ExclusiveContext and JSRuntime, pick the
|
||||
// ExclusiveContext version.
|
||||
using ExclusiveContext::atomsCompartment;
|
||||
using ExclusiveContext::buildIdOp;
|
||||
using ExclusiveContext::emptyString;
|
||||
using ExclusiveContext::jitSupportsSimd;
|
||||
using ExclusiveContext::make_pod_array;
|
||||
using ExclusiveContext::make_unique;
|
||||
using ExclusiveContext::new_;
|
||||
using ExclusiveContext::permanentAtoms;
|
||||
using ExclusiveContext::pod_calloc;
|
||||
using ExclusiveContext::pod_malloc;
|
||||
using ExclusiveContext::staticStrings;
|
||||
using ExclusiveContext::wellKnownSymbols;
|
||||
|
||||
JSRuntime* runtime() const { return runtime_; }
|
||||
js::PerThreadData& mainThread() const { return runtime()->mainThread; }
|
||||
|
||||
|
@ -343,10 +361,6 @@ struct JSContext : public js::ExclusiveContext
|
|||
/* State for object and array toSource conversion. */
|
||||
js::AutoCycleDetector::Set cycleDetectorSet;
|
||||
|
||||
/* Client opaque pointers. */
|
||||
void* data;
|
||||
void* data2;
|
||||
|
||||
public:
|
||||
|
||||
/*
|
||||
|
@ -438,7 +452,7 @@ struct JSContext : public js::ExclusiveContext
|
|||
*/
|
||||
inline bool runningWithTrustedPrincipals() const;
|
||||
|
||||
JS_FRIEND_API(size_t) sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
JS_FRIEND_API(size_t) sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
|
||||
void mark(JSTracer* trc);
|
||||
|
||||
|
@ -495,7 +509,7 @@ struct MOZ_RAII AutoResolving {
|
|||
* and exclusively owned.
|
||||
*/
|
||||
extern JSContext*
|
||||
NewContext(JSRuntime* rt);
|
||||
NewContext(uint32_t maxBytes, uint32_t maxNurseryBytes, JSRuntime* parentRuntime);
|
||||
|
||||
extern void
|
||||
DestroyContext(JSContext* cx);
|
||||
|
@ -721,6 +735,10 @@ class MOZ_RAII AutoLockForExclusiveAccess
|
|||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
init(rt);
|
||||
}
|
||||
explicit AutoLockForExclusiveAccess(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
init(cx->runtime());
|
||||
}
|
||||
~AutoLockForExclusiveAccess() {
|
||||
if (runtime->numExclusiveThreads) {
|
||||
#ifdef DEBUG
|
||||
|
|
|
@ -30,14 +30,6 @@ class CompartmentChecker
|
|||
explicit CompartmentChecker(ExclusiveContext* cx)
|
||||
: compartment(cx->compartment())
|
||||
{
|
||||
#ifdef DEBUG
|
||||
// In debug builds, make sure the embedder passed the cx it claimed it
|
||||
// was going to use.
|
||||
JSContext* activeContext = nullptr;
|
||||
if (cx->isJSContext())
|
||||
activeContext = cx->asJSContext()->runtime()->activeContext;
|
||||
MOZ_ASSERT_IF(activeContext, cx == activeContext);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -522,7 +522,7 @@ js::GetErrorTypeName(JSRuntime* rt, int16_t exnType)
|
|||
return nullptr;
|
||||
}
|
||||
JSProtoKey key = GetExceptionProtoKey(JSExnType(exnType));
|
||||
return ClassName(key, rt);
|
||||
return ClassName(key, rt->contextFromMainThread());
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -1256,14 +1256,6 @@ js::SetScriptEnvironmentPreparer(JSRuntime* rt, ScriptEnvironmentPreparer* prepa
|
|||
rt->scriptEnvironmentPreparer = preparer;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
JS_FRIEND_API(void)
|
||||
js::Debug_SetActiveJSContext(JSRuntime* rt, JSContext* cx)
|
||||
{
|
||||
rt->activeContext = cx;
|
||||
}
|
||||
#endif
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
js::SetCTypesActivityCallback(JSRuntime* rt, CTypesActivityCallback cb)
|
||||
{
|
||||
|
|
|
@ -2691,20 +2691,6 @@ JS_FRIEND_API(void)
|
|||
SetScriptEnvironmentPreparer(JSRuntime* rt, ScriptEnvironmentPreparer*
|
||||
preparer);
|
||||
|
||||
/**
|
||||
* To help embedders enforce their invariants, we allow them to specify in
|
||||
* advance which JSContext should be passed to JSAPI calls. If this is set
|
||||
* to a non-null value, the assertSameCompartment machinery does double-
|
||||
* duty (in debug builds) to verify that it matches the cx being used.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
JS_FRIEND_API(void)
|
||||
Debug_SetActiveJSContext(JSRuntime* rt, JSContext* cx);
|
||||
#else
|
||||
inline void
|
||||
Debug_SetActiveJSContext(JSRuntime* rt, JSContext* cx) {}
|
||||
#endif
|
||||
|
||||
enum CTypesActivityType {
|
||||
CTYPES_CALL_BEGIN,
|
||||
CTYPES_CALL_END,
|
||||
|
|
|
@ -6996,8 +6996,8 @@ AutoSuppressGC::AutoSuppressGC(JSCompartment* comp)
|
|||
suppressGC_++;
|
||||
}
|
||||
|
||||
AutoSuppressGC::AutoSuppressGC(JSRuntime* rt)
|
||||
: suppressGC_(rt->mainThread.suppressGC)
|
||||
AutoSuppressGC::AutoSuppressGC(JSContext* cx)
|
||||
: suppressGC_(cx->mainThread().suppressGC)
|
||||
{
|
||||
suppressGC_++;
|
||||
}
|
||||
|
|
|
@ -1276,7 +1276,7 @@ class MOZ_RAII JS_HAZ_GC_SUPPRESSED AutoSuppressGC
|
|||
public:
|
||||
explicit AutoSuppressGC(ExclusiveContext* cx);
|
||||
explicit AutoSuppressGC(JSCompartment* comp);
|
||||
explicit AutoSuppressGC(JSRuntime* rt);
|
||||
explicit AutoSuppressGC(JSContext* cx);
|
||||
|
||||
~AutoSuppressGC()
|
||||
{
|
||||
|
|
|
@ -3,6 +3,51 @@
|
|||
* 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/. */
|
||||
|
||||
// NOTE: If you're adding new test harness functionality to this file -- first,
|
||||
// should you at all? Most stuff is better in specific tests, or in
|
||||
// nested shell.js/browser.js. Second, can you instead add it to
|
||||
// shell.js? Our goal is to unify these two files for readability, and
|
||||
// the plan is to empty out this file into that one over time. Third,
|
||||
// supposing you must add to this file, please add it to this IIFE for
|
||||
// better modularity/resilience against tests that must do particularly
|
||||
// bizarre things that might break the harness.
|
||||
|
||||
(function(global) {
|
||||
/****************************
|
||||
* UTILITY FUNCTION EXPORTS *
|
||||
****************************/
|
||||
|
||||
var newGlobal = global.newGlobal;
|
||||
if (typeof newGlobal !== "function") {
|
||||
newGlobal = function newGlobal() {
|
||||
var iframe = global.document.createElement("iframe");
|
||||
global.document.documentElement.appendChild(iframe);
|
||||
var win = iframe.contentWindow;
|
||||
iframe.remove();
|
||||
// Shim in "evaluate"
|
||||
win.evaluate = win.eval;
|
||||
return win;
|
||||
};
|
||||
global.newGlobal = newGlobal;
|
||||
}
|
||||
|
||||
// This function is *only* used in this file! Ultimately it should only be
|
||||
// used by other exports in this IIFE, but for now just export it so that
|
||||
// functions not exported within this IIFE (but still in this file) can use
|
||||
// it.
|
||||
function DocumentWrite(s) {
|
||||
try {
|
||||
var msgDiv = global.document.createElement('div');
|
||||
msgDiv.innerHTML = s;
|
||||
global.document.body.appendChild(msgDiv);
|
||||
} catch (e) {
|
||||
global.document.write(s + '<br>\n');
|
||||
}
|
||||
}
|
||||
global.DocumentWrite = DocumentWrite;
|
||||
})(this);
|
||||
|
||||
|
||||
var gPageCompleted;
|
||||
var GLOBAL = this + '';
|
||||
|
||||
|
@ -48,21 +93,6 @@ function htmlesc(str) {
|
|||
return str;
|
||||
}
|
||||
|
||||
function DocumentWrite(s)
|
||||
{
|
||||
try
|
||||
{
|
||||
var msgDiv = document.createElement('div');
|
||||
msgDiv.innerHTML = s;
|
||||
document.body.appendChild(msgDiv);
|
||||
msgDiv = null;
|
||||
}
|
||||
catch(excp)
|
||||
{
|
||||
document.write(s + '<br>\n');
|
||||
}
|
||||
}
|
||||
|
||||
function print() {
|
||||
var s = 'TEST-INFO | ';
|
||||
var a;
|
||||
|
@ -251,10 +281,6 @@ function gczeal(z)
|
|||
SpecialPowers.setGCZeal(z);
|
||||
}
|
||||
|
||||
function jit(on)
|
||||
{
|
||||
}
|
||||
|
||||
function jsTestDriverBrowserInit()
|
||||
{
|
||||
|
||||
|
@ -357,18 +383,6 @@ function jsTestDriverBrowserInit()
|
|||
gczeal(Number(properties.gczeal));
|
||||
}
|
||||
|
||||
/*
|
||||
* since the default setting of jit changed from false to true
|
||||
* in http://hg.mozilla.org/tracemonkey/rev/685e00e68be9
|
||||
* bisections which depend upon jit settings can be thrown off.
|
||||
* default jit(false) when not running jsreftests to make bisections
|
||||
* depending upon jit settings consistent over time. This is not needed
|
||||
* in shell tests as the default jit setting has not changed there.
|
||||
*/
|
||||
|
||||
if (properties.jit || !document.location.href.match(/jsreftest.html/))
|
||||
jit(properties.jit);
|
||||
|
||||
var testpathparts = properties.test.split(/\//);
|
||||
|
||||
if (testpathparts.length < 2)
|
||||
|
@ -560,16 +574,6 @@ function closeDialog()
|
|||
}
|
||||
}
|
||||
|
||||
function newGlobal() {
|
||||
var iframe = document.createElement("iframe");
|
||||
document.documentElement.appendChild(iframe);
|
||||
var win = iframe.contentWindow;
|
||||
iframe.remove();
|
||||
// Shim in "evaluate"
|
||||
win.evaluate = win.eval;
|
||||
return win;
|
||||
}
|
||||
|
||||
registerDialogCloser();
|
||||
window.addEventListener('unload', unregisterDialogCloser, true);
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ var expectedmatches = new Array();
|
|||
// time, they will not be compiled to native code and we will not
|
||||
// actually be testing jitted regexps.
|
||||
|
||||
jit(true);
|
||||
|
||||
status = inSection(1);
|
||||
string = '@';
|
||||
|
@ -57,7 +56,6 @@ print('`'.match(/@/i));
|
|||
expectedmatch = null;
|
||||
addThis();
|
||||
|
||||
jit(false);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
test();
|
||||
|
|
|
@ -38,10 +38,8 @@ var expect = is_space.join(',');
|
|||
var actual = chars.map(function(ch) { return /\s/.test(ch); }).join(',');
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
jit(true);
|
||||
var actual = chars.map(function(ch) { return /\s/.test(ch); }).join(',');
|
||||
reportCompare(expect, actual, summary);
|
||||
jit(false);
|
||||
|
||||
exitFunc ('test');
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
var BUGNUMBER = 1199695;
|
||||
var summary =
|
||||
"Computed property names must be considered as always effectful even when " +
|
||||
"the name expression isn't effectful, because calling ToPropertyKey on " +
|
||||
"some non-effectful expressions has user-modifiable behavior";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
RegExp.prototype.toString = () => { throw 42; };
|
||||
assertThrowsValue(function() {
|
||||
({ [/regex/]: 0 }); // ToPropertyKey(/regex/) throws 42
|
||||
}, 42);
|
||||
|
||||
function Q() {
|
||||
({ [new.target]: 0 }); // new.target will be Q, ToPropertyKey(Q) throws 17
|
||||
}
|
||||
Q.toString = () => { throw 17; };
|
||||
assertThrowsValue(function() {
|
||||
new Q;
|
||||
}, 17);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("Tests complete");
|
|
@ -1,6 +1,10 @@
|
|||
var BUGNUMBER = 1135377;
|
||||
var summary = "Implement RegExp unicode flag -- ignoreCase flag with character class escape.";
|
||||
|
||||
// \W doesn't match S or K from the change in
|
||||
// https://github.com/tc39/ecma262/pull/525
|
||||
// (bug 1281739)
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
// LATIN SMALL LETTER LONG S
|
||||
|
@ -12,13 +16,27 @@ assertEqArray(/\w/iu.exec("s"),
|
|||
assertEqArray(/\w/iu.exec("\u017F"),
|
||||
["\u017F"]);
|
||||
|
||||
assertEqArray(/\W/iu.exec("S"),
|
||||
assertEqArray(/[^\W]/iu.exec("S"),
|
||||
["S"]);
|
||||
assertEqArray(/\W/iu.exec("s"),
|
||||
assertEqArray(/[^\W]/iu.exec("s"),
|
||||
["s"]);
|
||||
assertEqArray(/\W/iu.exec("\u017F"),
|
||||
assertEqArray(/[^\W]/iu.exec("\u017F"),
|
||||
["\u017F"]);
|
||||
|
||||
assertEq(/\W/iu.exec("S"),
|
||||
null);
|
||||
assertEq(/\W/iu.exec("s"),
|
||||
null);
|
||||
assertEq(/\W/iu.exec("\u017F"),
|
||||
null);
|
||||
|
||||
assertEq(/[^\w]/iu.exec("S"),
|
||||
null);
|
||||
assertEq(/[^\w]/iu.exec("s"),
|
||||
null);
|
||||
assertEq(/[^\w]/iu.exec("\u017F"),
|
||||
null);
|
||||
|
||||
// KELVIN SIGN
|
||||
|
||||
assertEqArray(/\w/iu.exec("k"),
|
||||
|
@ -28,12 +46,26 @@ assertEqArray(/\w/iu.exec("k"),
|
|||
assertEqArray(/\w/iu.exec("\u212A"),
|
||||
["\u212A"]);
|
||||
|
||||
assertEqArray(/\W/iu.exec("k"),
|
||||
assertEqArray(/[^\W]/iu.exec("k"),
|
||||
["k"]);
|
||||
assertEqArray(/\W/iu.exec("k"),
|
||||
assertEqArray(/[^\W]/iu.exec("k"),
|
||||
["k"]);
|
||||
assertEqArray(/\W/iu.exec("\u212A"),
|
||||
assertEqArray(/[^\W]/iu.exec("\u212A"),
|
||||
["\u212A"]);
|
||||
|
||||
assertEq(/\W/iu.exec("k"),
|
||||
null);
|
||||
assertEq(/\W/iu.exec("k"),
|
||||
null);
|
||||
assertEq(/\W/iu.exec("\u212A"),
|
||||
null);
|
||||
|
||||
assertEq(/[^\w]/iu.exec("k"),
|
||||
null);
|
||||
assertEq(/[^\w]/iu.exec("k"),
|
||||
null);
|
||||
assertEq(/[^\w]/iu.exec("\u212A"),
|
||||
null);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
|
|
@ -20,7 +20,6 @@ function test()
|
|||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
jit(true);
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -40,11 +39,9 @@ function test()
|
|||
var x; while (x = popArrs[a].pop()) { }
|
||||
}
|
||||
|
||||
jit(false);
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
jit(false);
|
||||
actual = ex + '';
|
||||
}
|
||||
|
||||
|
|
|
@ -44,12 +44,10 @@ function test()
|
|||
}
|
||||
}
|
||||
|
||||
jit(true);
|
||||
gc();
|
||||
print("Size\t\Rep.\t\Literal\tnew Arr\tArray()");
|
||||
print("====\t=====\t=======\t=======\t=======");
|
||||
main();
|
||||
jit(false);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
|
|
|
@ -22,10 +22,8 @@ function test()
|
|||
actual += 'iI\u0130'.replace(/[\u0130]/gi, '#');
|
||||
actual += ',' + 'iI\u0130'.replace(/\u0130/gi, '#');
|
||||
|
||||
jit(true);
|
||||
actual += ';' + 'iI\u0130'.replace(/[\u0130]/gi, '#');
|
||||
actual += ',' + 'iI\u0130'.replace(/\u0130/gi, '#');
|
||||
jit(false);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ var expect = 'No Crash';
|
|||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
jit(true);
|
||||
|
||||
/************************ BROWSER DETECT (http://www.quirksmode.org/js/detect.html) ************************/
|
||||
|
||||
|
@ -111,6 +110,5 @@ var BrowserDetect = {
|
|||
|
||||
BrowserDetect.init();
|
||||
|
||||
jit(false);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
|
|
@ -24,7 +24,6 @@ function test()
|
|||
|
||||
var global;
|
||||
|
||||
jit(true);
|
||||
|
||||
if (typeof window == 'undefined') {
|
||||
global = this;
|
||||
|
@ -59,7 +58,6 @@ function test()
|
|||
|
||||
}
|
||||
|
||||
jit(false);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ var summary = 'Crash with JIT and json2.js';
|
|||
var actual = 'No Crash';
|
||||
var expect = 'No Crash';
|
||||
|
||||
jit(true);
|
||||
|
||||
/*
|
||||
json2.js
|
||||
|
@ -280,7 +279,6 @@ replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
|
|||
test();
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
jit(false);
|
||||
|
||||
function test()
|
||||
{
|
||||
|
|
|
@ -22,7 +22,6 @@ function test()
|
|||
|
||||
expect = 100;
|
||||
|
||||
jit(true);
|
||||
|
||||
function f(i) {
|
||||
for (var m = 0; m < 20; ++m)
|
||||
|
@ -33,15 +32,12 @@ function test()
|
|||
|
||||
print(actual = f(1));
|
||||
|
||||
jit(false);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
jit(true);
|
||||
|
||||
print(actual = f(.5));
|
||||
|
||||
jit(false);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ function test()
|
|||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
jit(true);
|
||||
|
||||
function f() {
|
||||
for (var i = 0; i < 200000; i++) {
|
||||
|
@ -31,7 +30,6 @@ function test()
|
|||
}
|
||||
f();
|
||||
|
||||
jit(false);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
|
|
|
@ -22,11 +22,9 @@ function test()
|
|||
|
||||
print('This test is only valid with SELinux targetted policy with exeheap protection');
|
||||
|
||||
jit(true);
|
||||
|
||||
var i; for (i = 0; i < 2000000; i++) {;}
|
||||
|
||||
jit(false);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ function test()
|
|||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
jit(true);
|
||||
|
||||
// regression test for Bug 452008 - TM: SRP in Clipperz crypto library fails when JIT (TraceMonkey) is enabled.
|
||||
|
||||
|
@ -142,7 +141,6 @@ function test()
|
|||
}
|
||||
print(passed);
|
||||
|
||||
jit(false);
|
||||
|
||||
expect = true;
|
||||
actual = passed;
|
||||
|
|
|
@ -19,11 +19,9 @@ function test()
|
|||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
jit(true);
|
||||
|
||||
for (var j = 0; j < 4; ++j) { (-0).toString(); }
|
||||
|
||||
jit(false);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
|
|
|
@ -19,11 +19,9 @@ function test()
|
|||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
jit(true);
|
||||
|
||||
(function() { for (var j = 0; j < 5; ++j) { (typeof 3/0); } })();
|
||||
|
||||
jit(false);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
|
|
|
@ -19,11 +19,9 @@ function test()
|
|||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
jit(true);
|
||||
|
||||
for (var j = 0; j < 4; ++j) { [1].x++; }
|
||||
|
||||
jit(false);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
|
|
|
@ -12,10 +12,8 @@ var expect = 'No Crash';
|
|||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
jit(true);
|
||||
|
||||
for (var j = 0; j < 4; ++j) { try { new 1(this); } catch(e) { } }
|
||||
|
||||
jit(false);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
|
|
@ -19,11 +19,9 @@ function test()
|
|||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
jit(true);
|
||||
|
||||
for(var j=0;j<5;++j) typeof void /x/;
|
||||
|
||||
jit(false);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
|
|
|
@ -19,11 +19,9 @@ function test()
|
|||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
jit(true);
|
||||
|
||||
for(var j=0;j<5;++j) typeof void 1;
|
||||
|
||||
jit(false);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
|
|
|
@ -19,11 +19,9 @@ function test()
|
|||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
jit(true);
|
||||
|
||||
for (var j = 0; j < 5; ++j) { if (''[-1]) { } }
|
||||
|
||||
jit(false);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
|
|
|
@ -19,11 +19,9 @@ function test()
|
|||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
jit(true);
|
||||
|
||||
(function() { for (var j=0;j<5;++j) { (0/0) in this; } })()
|
||||
|
||||
jit(false);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
|
|
|
@ -19,11 +19,9 @@ function test()
|
|||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
jit(true);
|
||||
|
||||
for (var j=0;j<5;++j) { (0/0) in this; }
|
||||
|
||||
jit(false);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
|
|
|
@ -19,11 +19,9 @@ function test()
|
|||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
jit(true);
|
||||
|
||||
for (var j=0; j<4; ++j) { var a = ["", ""]; a[0] * a[1]; }
|
||||
|
||||
jit(false);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
|
|
|
@ -19,11 +19,9 @@ function test()
|
|||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
jit(true);
|
||||
|
||||
for (var j=0;j<5;++j) { switch(1.1) { case NaN: case 2: } }
|
||||
|
||||
jit(false);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
|
|
|
@ -19,11 +19,9 @@ function test()
|
|||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
jit(true);
|
||||
|
||||
for (var j=0;j<5;++j) { switch(1.1) { case 2: case NaN: } }
|
||||
|
||||
jit(false);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
|
|
|
@ -21,11 +21,9 @@ function test()
|
|||
|
||||
var i;
|
||||
|
||||
jit(true);
|
||||
|
||||
for(i=0;i<4;++i) [,];
|
||||
|
||||
jit(false);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ function test()
|
|||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
jit(true);
|
||||
|
||||
function computeEscapeSpeed(real) {
|
||||
for (var j = 1; j < 4; ++j) {
|
||||
|
@ -40,7 +39,6 @@ function test()
|
|||
}
|
||||
}
|
||||
|
||||
jit(false);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
|
|
|
@ -19,11 +19,9 @@ function test()
|
|||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
jit(true);
|
||||
|
||||
(function() { for (var j = 0; j < 5; ++j) { (1).hasOwnProperty(""); } })();
|
||||
|
||||
jit(false);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче