зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1092102 - Implement WorkerDebugger.initialize;r=khuey
This commit is contained in:
Родитель
d087d1ddf6
Коммит
2d0841a4c7
|
@ -60,6 +60,7 @@
|
|||
|
||||
#include "Principal.h"
|
||||
#include "SharedWorker.h"
|
||||
#include "WorkerDebuggerManager.h"
|
||||
#include "WorkerPrivate.h"
|
||||
#include "WorkerRunnable.h"
|
||||
#include "WorkerThread.h"
|
||||
|
@ -1918,6 +1919,12 @@ RuntimeService::Shutdown()
|
|||
// That's it, no more workers.
|
||||
mShuttingDown = true;
|
||||
|
||||
// Remove all listeners from the worker debugger manager to ensure that it
|
||||
// gets properly destroyed.
|
||||
if (NS_FAILED(ClearWorkerDebuggerManagerListeners())) {
|
||||
NS_WARNING("Failed to clear worker debugger manager listeners!");
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
NS_WARN_IF_FALSE(obs, "Failed to get observer service?!");
|
||||
|
||||
|
|
|
@ -53,7 +53,8 @@ ChannelFromScriptURL(nsIPrincipal* principal,
|
|||
nsIIOService* ios,
|
||||
nsIScriptSecurityManager* secMan,
|
||||
const nsAString& aScriptURL,
|
||||
bool aIsWorkerScript,
|
||||
bool aIsMainScript,
|
||||
WorkerScriptType aWorkerScriptType,
|
||||
nsIChannel** aChannel)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
@ -84,10 +85,22 @@ ChannelFromScriptURL(nsIPrincipal* principal,
|
|||
}
|
||||
}
|
||||
|
||||
// If this script loader is being used to make a new worker then we need
|
||||
// to do a same-origin check. Otherwise we need to clear the load with the
|
||||
// security manager.
|
||||
if (aIsWorkerScript) {
|
||||
if (aWorkerScriptType == DebuggerScript) {
|
||||
bool isChrome = false;
|
||||
NS_ENSURE_SUCCESS(uri->SchemeIs("chrome", &isChrome),
|
||||
NS_ERROR_DOM_SECURITY_ERR);
|
||||
|
||||
bool isResource = false;
|
||||
NS_ENSURE_SUCCESS(uri->SchemeIs("resource", &isResource),
|
||||
NS_ERROR_DOM_SECURITY_ERR);
|
||||
|
||||
if (!isChrome && !isResource) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
} else if (aIsMainScript) {
|
||||
// If this script loader is being used to make a new worker then we need
|
||||
// to do a same-origin check. Otherwise we need to clear the load with the
|
||||
// security manager.
|
||||
nsCString scheme;
|
||||
rv = uri->GetScheme(scheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -190,6 +203,9 @@ private:
|
|||
~ScriptExecutorRunnable()
|
||||
{ }
|
||||
|
||||
virtual bool
|
||||
IsDebuggerRunnable() const MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE;
|
||||
|
||||
|
@ -214,7 +230,8 @@ class ScriptLoaderRunnable MOZ_FINAL : public WorkerFeature,
|
|||
WorkerPrivate* mWorkerPrivate;
|
||||
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
|
||||
nsTArray<ScriptLoadInfo> mLoadInfos;
|
||||
bool mIsWorkerScript;
|
||||
bool mIsMainScript;
|
||||
WorkerScriptType mWorkerScriptType;
|
||||
bool mCanceled;
|
||||
bool mCanceledMainThread;
|
||||
|
||||
|
@ -224,14 +241,15 @@ public:
|
|||
ScriptLoaderRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
nsIEventTarget* aSyncLoopTarget,
|
||||
nsTArray<ScriptLoadInfo>& aLoadInfos,
|
||||
bool aIsWorkerScript)
|
||||
bool aIsMainScript,
|
||||
WorkerScriptType aWorkerScriptType)
|
||||
: mWorkerPrivate(aWorkerPrivate), mSyncLoopTarget(aSyncLoopTarget),
|
||||
mIsWorkerScript(aIsWorkerScript), mCanceled(false),
|
||||
mCanceledMainThread(false)
|
||||
mIsMainScript(aIsMainScript), mWorkerScriptType(aWorkerScriptType),
|
||||
mCanceled(false), mCanceledMainThread(false)
|
||||
{
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(aSyncLoopTarget);
|
||||
MOZ_ASSERT_IF(aIsWorkerScript, aLoadInfos.Length() == 1);
|
||||
MOZ_ASSERT_IF(aIsMainScript, aLoadInfos.Length() == 1);
|
||||
|
||||
mLoadInfos.SwapElements(aLoadInfos);
|
||||
}
|
||||
|
@ -300,6 +318,12 @@ private:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IsMainWorkerScript() const
|
||||
{
|
||||
return mIsMainScript && mWorkerScriptType == WorkerScript;
|
||||
}
|
||||
|
||||
void
|
||||
CancelMainThread()
|
||||
{
|
||||
|
@ -338,7 +362,7 @@ private:
|
|||
nsCOMPtr<nsILoadGroup> loadGroup = mWorkerPrivate->GetLoadGroup();
|
||||
if (!principal) {
|
||||
NS_ASSERTION(parentWorker, "Must have a principal!");
|
||||
NS_ASSERTION(mIsWorkerScript, "Must have a principal for importScripts!");
|
||||
NS_ASSERTION(mIsMainScript, "Must have a principal for importScripts!");
|
||||
|
||||
principal = parentWorker->GetPrincipal();
|
||||
loadGroup = parentWorker->GetLoadGroup();
|
||||
|
@ -348,7 +372,7 @@ private:
|
|||
|
||||
// Figure out our base URI.
|
||||
nsCOMPtr<nsIURI> baseURI;
|
||||
if (mIsWorkerScript) {
|
||||
if (mIsMainScript) {
|
||||
if (parentWorker) {
|
||||
baseURI = parentWorker->GetBaseURI();
|
||||
NS_ASSERTION(baseURI, "Should have been set already!");
|
||||
|
@ -367,7 +391,7 @@ private:
|
|||
nsCOMPtr<nsIDocument> parentDoc = mWorkerPrivate->GetDocument();
|
||||
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
if (mIsWorkerScript) {
|
||||
if (IsMainWorkerScript()) {
|
||||
// May be null.
|
||||
channel = mWorkerPrivate->ForgetWorkerChannel();
|
||||
}
|
||||
|
@ -383,8 +407,8 @@ private:
|
|||
|
||||
if (!channel) {
|
||||
rv = ChannelFromScriptURL(principal, baseURI, parentDoc, loadGroup, ios,
|
||||
secMan, loadInfo.mURL, mIsWorkerScript,
|
||||
getter_AddRefs(channel));
|
||||
secMan, loadInfo.mURL, mIsMainScript,
|
||||
mWorkerScriptType, getter_AddRefs(channel));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -489,7 +513,7 @@ private:
|
|||
|
||||
// Update the principal of the worker and its base URI if we just loaded the
|
||||
// worker's primary script.
|
||||
if (mIsWorkerScript) {
|
||||
if (IsMainWorkerScript()) {
|
||||
// Take care of the base URI first.
|
||||
mWorkerPrivate->SetBaseURI(finalURI);
|
||||
|
||||
|
@ -577,7 +601,7 @@ private:
|
|||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
if (mIsWorkerScript) {
|
||||
if (IsMainWorkerScript()) {
|
||||
mWorkerPrivate->WorkerScriptLoaded();
|
||||
}
|
||||
|
||||
|
@ -704,6 +728,15 @@ ScriptExecutorRunnable::ScriptExecutorRunnable(
|
|||
MOZ_ASSERT(aLastIndex < aScriptLoader.mLoadInfos.Length());
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptExecutorRunnable::IsDebuggerRunnable() const
|
||||
{
|
||||
// ScriptExecutorRunnable is used to execute both worker and debugger scripts.
|
||||
// In the latter case, the runnable needs to be dispatched to the debugger
|
||||
// queue.
|
||||
return mScriptLoader.mWorkerScriptType == DebuggerScript;
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptExecutorRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
|
@ -762,6 +795,10 @@ ScriptExecutorRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
|||
options.setFileAndLine(filename.get(), 1)
|
||||
.setNoScriptRval(true);
|
||||
|
||||
if (mScriptLoader.mWorkerScriptType == DebuggerScript) {
|
||||
options.setVersion(JSVERSION_LATEST);
|
||||
}
|
||||
|
||||
JS::SourceBufferHolder srcBuf(loadInfo.mScriptTextBuf,
|
||||
loadInfo.mScriptTextLength,
|
||||
JS::SourceBufferHolder::GiveOwnership);
|
||||
|
@ -819,7 +856,8 @@ ScriptExecutorRunnable::ShutdownScriptLoader(JSContext* aCx,
|
|||
|
||||
bool
|
||||
LoadAllScripts(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
||||
nsTArray<ScriptLoadInfo>& aLoadInfos, bool aIsWorkerScript)
|
||||
nsTArray<ScriptLoadInfo>& aLoadInfos, bool aIsMainScript,
|
||||
WorkerScriptType aWorkerScriptType)
|
||||
{
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
NS_ASSERTION(!aLoadInfos.IsEmpty(), "Bad arguments!");
|
||||
|
@ -828,7 +866,7 @@ LoadAllScripts(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
|||
|
||||
nsRefPtr<ScriptLoaderRunnable> loader =
|
||||
new ScriptLoaderRunnable(aWorkerPrivate, syncLoop.EventTarget(),
|
||||
aLoadInfos, aIsWorkerScript);
|
||||
aLoadInfos, aIsMainScript, aWorkerScriptType);
|
||||
|
||||
NS_ASSERTION(aLoadInfos.IsEmpty(), "Should have swapped!");
|
||||
|
||||
|
@ -868,7 +906,7 @@ ChannelFromScriptURLMainThread(nsIPrincipal* aPrincipal,
|
|||
NS_ASSERTION(secMan, "This should never be null!");
|
||||
|
||||
return ChannelFromScriptURL(aPrincipal, aBaseURI, aParentDoc, aLoadGroup,
|
||||
ios, secMan, aScriptURL, true, aChannel);
|
||||
ios, secMan, aScriptURL, true, WorkerScript, aChannel);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -927,7 +965,8 @@ void ReportLoadError(JSContext* aCx, const nsAString& aURL,
|
|||
}
|
||||
|
||||
bool
|
||||
LoadWorkerScript(JSContext* aCx)
|
||||
LoadMainScript(JSContext* aCx, const nsAString& aScriptURL,
|
||||
WorkerScriptType aWorkerScriptType)
|
||||
{
|
||||
WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
|
||||
NS_ASSERTION(worker, "This should never be null!");
|
||||
|
@ -935,9 +974,9 @@ LoadWorkerScript(JSContext* aCx)
|
|||
nsTArray<ScriptLoadInfo> loadInfos;
|
||||
|
||||
ScriptLoadInfo* info = loadInfos.AppendElement();
|
||||
info->mURL = worker->ScriptURL();
|
||||
info->mURL = aScriptURL;
|
||||
|
||||
return LoadAllScripts(aCx, worker, loadInfos, true);
|
||||
return LoadAllScripts(aCx, worker, loadInfos, true, aWorkerScriptType);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -962,7 +1001,7 @@ Load(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
|||
loadInfos[index].mURL = aScriptURLs[index];
|
||||
}
|
||||
|
||||
if (!LoadAllScripts(aCx, aWorkerPrivate, loadInfos, false)) {
|
||||
if (!LoadAllScripts(aCx, aWorkerPrivate, loadInfos, false, WorkerScript)) {
|
||||
// LoadAllScripts can fail if we're shutting down.
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,11 @@ class Sequence;
|
|||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
enum WorkerScriptType {
|
||||
WorkerScript,
|
||||
DebuggerScript
|
||||
};
|
||||
|
||||
namespace scriptloader {
|
||||
|
||||
nsresult
|
||||
|
@ -48,7 +53,8 @@ ChannelFromScriptURLWorkerThread(JSContext* aCx,
|
|||
void ReportLoadError(JSContext* aCx, const nsAString& aURL,
|
||||
nsresult aLoadResult, bool aIsMainThread);
|
||||
|
||||
bool LoadWorkerScript(JSContext* aCx);
|
||||
bool LoadMainScript(JSContext* aCx, const nsAString& aScriptURL,
|
||||
WorkerScriptType aWorkerScriptType);
|
||||
|
||||
void Load(JSContext* aCx,
|
||||
WorkerPrivate* aWorkerPrivate,
|
||||
|
|
|
@ -141,6 +141,16 @@ WorkerDebuggerManager::RemoveListener(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
WorkerDebuggerManager::ClearListeners()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
mListeners.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
WorkerDebuggerManager::RegisterDebugger(WorkerDebugger* aDebugger)
|
||||
{
|
||||
|
|
|
@ -41,9 +41,9 @@ public:
|
|||
static WorkerDebuggerManager*
|
||||
GetOrCreateService()
|
||||
{
|
||||
nsCOMPtr<nsIWorkerDebuggerManager> wdm =
|
||||
nsCOMPtr<nsIWorkerDebuggerManager> manager =
|
||||
do_GetService(WORKERDEBUGGERMANAGER_CONTRACTID);
|
||||
return static_cast<WorkerDebuggerManager*>(wdm.get());
|
||||
return static_cast<WorkerDebuggerManager*>(manager.get());
|
||||
}
|
||||
|
||||
WorkerDebuggerManager();
|
||||
|
@ -51,6 +51,8 @@ public:
|
|||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIWORKERDEBUGGERMANAGER
|
||||
|
||||
void ClearListeners();
|
||||
|
||||
void RegisterDebugger(WorkerDebugger* aDebugger);
|
||||
|
||||
void UnregisterDebugger(WorkerDebugger* aDebugger);
|
||||
|
@ -64,6 +66,19 @@ private:
|
|||
void UnregisterDebuggerOnMainThread(WorkerDebugger* aDebugger);
|
||||
};
|
||||
|
||||
inline nsresult
|
||||
ClearWorkerDebuggerManagerListeners()
|
||||
{
|
||||
nsRefPtr<WorkerDebuggerManager> manager =
|
||||
WorkerDebuggerManager::GetOrCreateService();
|
||||
if (!manager) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
manager->ClearListeners();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
inline nsresult
|
||||
RegisterWorkerDebugger(WorkerDebugger* aDebugger)
|
||||
{
|
||||
|
|
|
@ -1042,9 +1042,13 @@ private:
|
|||
|
||||
class CompileScriptRunnable MOZ_FINAL : public WorkerRunnable
|
||||
{
|
||||
nsString mScriptURL;
|
||||
|
||||
public:
|
||||
explicit CompileScriptRunnable(WorkerPrivate* aWorkerPrivate)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
|
||||
explicit CompileScriptRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
const nsAString& aScriptURL)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount),
|
||||
mScriptURL(aScriptURL)
|
||||
{ }
|
||||
|
||||
private:
|
||||
|
@ -1059,8 +1063,9 @@ private:
|
|||
}
|
||||
|
||||
JS::Rooted<JSObject*> global(aCx, globalScope->GetWrapper());
|
||||
|
||||
JSAutoCompartment ac(aCx, global);
|
||||
bool result = scriptloader::LoadWorkerScript(aCx);
|
||||
bool result = scriptloader::LoadMainScript(aCx, mScriptURL, WorkerScript);
|
||||
if (result) {
|
||||
aWorkerPrivate->SetWorkerScriptExecutedSuccessfully();
|
||||
}
|
||||
|
@ -1068,6 +1073,35 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
class CompileDebuggerScriptRunnable MOZ_FINAL : public WorkerDebuggerRunnable
|
||||
{
|
||||
nsString mScriptURL;
|
||||
|
||||
public:
|
||||
CompileDebuggerScriptRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
const nsAString& aScriptURL)
|
||||
: WorkerDebuggerRunnable(aWorkerPrivate),
|
||||
mScriptURL(aScriptURL)
|
||||
{ }
|
||||
|
||||
private:
|
||||
virtual bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
|
||||
{
|
||||
WorkerDebuggerGlobalScope* globalScope =
|
||||
aWorkerPrivate->CreateDebuggerGlobalScope(aCx);
|
||||
if (!globalScope) {
|
||||
NS_WARNING("Failed to make global!");
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> global(aCx, globalScope->GetWrapper());
|
||||
|
||||
JSAutoCompartment ac(aCx, global);
|
||||
return scriptloader::LoadMainScript(aCx, mScriptURL, DebuggerScript);
|
||||
}
|
||||
};
|
||||
|
||||
class CloseEventRunnable MOZ_FINAL : public WorkerRunnable
|
||||
{
|
||||
public:
|
||||
|
@ -4135,7 +4169,8 @@ WorkerDebugger::WorkerDebugger(WorkerPrivate* aWorkerPrivate)
|
|||
: mMutex("WorkerDebugger::mMutex"),
|
||||
mCondVar(mMutex, "WorkerDebugger::mCondVar"),
|
||||
mWorkerPrivate(aWorkerPrivate),
|
||||
mIsEnabled(false)
|
||||
mIsEnabled(false),
|
||||
mIsInitialized(false)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnParentThread();
|
||||
}
|
||||
|
@ -4264,6 +4299,28 @@ WorkerDebugger::GetWindow(nsIDOMWindow** aResult)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WorkerDebugger::Initialize(const nsAString& aURL, JSContext* aCx)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
if (!mWorkerPrivate || mIsInitialized) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsRefPtr<CompileDebuggerScriptRunnable> runnable =
|
||||
new CompileDebuggerScriptRunnable(mWorkerPrivate, aURL);
|
||||
if (!runnable->Dispatch(aCx)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mIsInitialized = true;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WorkerDebugger::AddListener(nsIWorkerDebuggerListener* aListener)
|
||||
{
|
||||
|
@ -4526,7 +4583,8 @@ WorkerPrivate::Constructor(JSContext* aCx,
|
|||
|
||||
worker->EnableDebugger();
|
||||
|
||||
nsRefPtr<CompileScriptRunnable> compiler = new CompileScriptRunnable(worker);
|
||||
nsRefPtr<CompileScriptRunnable> compiler =
|
||||
new CompileScriptRunnable(worker, aScriptURL);
|
||||
if (!compiler->Dispatch(aCx)) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
|
|
|
@ -729,6 +729,7 @@ class WorkerDebugger : public nsIWorkerDebugger {
|
|||
bool mIsEnabled;
|
||||
|
||||
// Only touched on the main thread.
|
||||
bool mIsInitialized;
|
||||
nsTArray<nsCOMPtr<nsIWorkerDebuggerListener>> mListeners;
|
||||
|
||||
public:
|
||||
|
|
|
@ -8,7 +8,7 @@ interface nsIWorkerDebuggerListener : nsISupports
|
|||
void onClose();
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(0833b363-bffe-4cdb-ad50-1c4563e0C8ff)]
|
||||
[scriptable, builtinclass, uuid(b0ea6da8-8bd9-446a-94e2-2ee979903205)]
|
||||
interface nsIWorkerDebugger : nsISupports
|
||||
{
|
||||
const unsigned long TYPE_DEDICATED = 0;
|
||||
|
@ -27,6 +27,9 @@ interface nsIWorkerDebugger : nsISupports
|
|||
|
||||
readonly attribute nsIDOMWindow window;
|
||||
|
||||
[implicit_jscontext]
|
||||
void initialize(in DOMString url);
|
||||
|
||||
void addListener(in nsIWorkerDebuggerListener listener);
|
||||
|
||||
void removeListener(in nsIWorkerDebuggerListener listener);
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
"use strict";
|
||||
|
||||
self.onmessage = function () {};
|
||||
|
||||
debugger;
|
||||
postMessage("worker");
|
|
@ -0,0 +1,6 @@
|
|||
"use strict";
|
||||
|
||||
var dbg = new Debugger(global);
|
||||
dbg.onDebuggerStatement = function (frame) {
|
||||
frame.eval("postMessage('debugger');");
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
"use strict";
|
||||
|
||||
var worker = new Worker("WorkerDebugger.initialize_childWorker.js");
|
||||
worker.onmessage = function (event) {
|
||||
postMessage("child:" + event.data);
|
||||
};
|
||||
|
||||
debugger;
|
||||
postMessage("worker");
|
|
@ -1,3 +1,3 @@
|
|||
"use strict";
|
||||
|
||||
onmessage = function () {};
|
||||
self.onmessage = function () {};
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
"use strict";
|
||||
|
||||
onmessage = function () {};
|
||||
self.onmessage = function () {};
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
var worker = new Worker("WorkerDebugger_childWorker.js");
|
|
@ -1,6 +1,6 @@
|
|||
"use strict";
|
||||
|
||||
onconnect = function (event) {
|
||||
self.onconnect = function (event) {
|
||||
event.ports[0].onmessage = function (event) {
|
||||
switch (event.data) {
|
||||
case "close":
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
"use strict";
|
||||
|
||||
var worker = new Worker("WorkerDebugger_childWorker.js");
|
||||
self.onmessage = function (event) {
|
||||
postMessage("child:" + event.data);
|
||||
};
|
||||
debugger;
|
||||
postMessage("worker");
|
|
@ -1,10 +1,13 @@
|
|||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
support-files =
|
||||
WorkerDebugger.initialize_childWorker.js
|
||||
WorkerDebugger.initialize_debugger.js
|
||||
WorkerDebugger.initialize_worker.js
|
||||
WorkerDebuggerManager_childWorker.js
|
||||
WorkerDebuggerManager_parentWorker.js
|
||||
WorkerDebuggerManager_worker.js
|
||||
WorkerDebugger_childWorker.js
|
||||
WorkerDebugger_parentWorker.js
|
||||
WorkerDebugger_worker.js
|
||||
WorkerDebugger_sharedWorker.js
|
||||
WorkerTest.jsm
|
||||
WorkerTest_subworker.js
|
||||
|
@ -29,6 +32,7 @@ support-files =
|
|||
bug1062920_worker.js
|
||||
|
||||
[test_WorkerDebugger.xul]
|
||||
[test_WorkerDebugger.initialize.xul]
|
||||
[test_WorkerDebuggerManager.xul]
|
||||
[test_bug883784.jsm]
|
||||
[test_bug883784.xul]
|
||||
|
|
|
@ -13,6 +13,8 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|||
const wdm = Cc["@mozilla.org/dom/workers/workerdebuggermanager;1"].
|
||||
getService(Ci.nsIWorkerDebuggerManager);
|
||||
|
||||
const BASE_URL = "chrome://mochitests/content/chrome/dom/workers/test/";
|
||||
|
||||
var gRemainingTests = 0;
|
||||
|
||||
function waitForWorkerFinish() {
|
||||
|
@ -47,50 +49,54 @@ function* generateDebuggers() {
|
|||
}
|
||||
}
|
||||
|
||||
function findDebugger(predicate) {
|
||||
function findDebugger(url) {
|
||||
for (let dbg of generateDebuggers()) {
|
||||
if (predicate(dbg)) {
|
||||
if (dbg.url === url) {
|
||||
return dbg;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function waitForRegister(predicate = () => true) {
|
||||
function waitForRegister(url, dbgUrl) {
|
||||
return new Promise(function (resolve) {
|
||||
wdm.addListener({
|
||||
onRegister: function (dbg) {
|
||||
if (!predicate(dbg)) {
|
||||
if (dbg.url !== url) {
|
||||
return;
|
||||
}
|
||||
ok(true, "Debugger with url " + url + " should be registered.");
|
||||
wdm.removeListener(this);
|
||||
if (dbgUrl) {
|
||||
info("Initializing worker debugger with url " + url + ".");
|
||||
dbg.initialize(dbgUrl);
|
||||
}
|
||||
resolve(dbg);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function waitForUnregister(predicate = () => true) {
|
||||
function waitForUnregister(url) {
|
||||
return new Promise(function (resolve) {
|
||||
wdm.addListener({
|
||||
onUnregister: function (dbg) {
|
||||
if (!predicate(dbg)) {
|
||||
if (dbg.url !== url) {
|
||||
return;
|
||||
}
|
||||
ok(true, "Debugger with url " + url + " should be unregistered.");
|
||||
wdm.removeListener(this);
|
||||
resolve(dbg);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function waitForDebuggerClose(dbg, predicate = () => true) {
|
||||
function waitForDebuggerClose(dbg) {
|
||||
return new Promise(function (resolve) {
|
||||
dbg.addListener({
|
||||
onClose: function () {
|
||||
if (!predicate()) {
|
||||
return;
|
||||
}
|
||||
ok(true, "Debugger should be closed.");
|
||||
dbg.removeListener(this);
|
||||
resolve();
|
||||
}
|
||||
|
@ -98,17 +104,31 @@ function waitForDebuggerClose(dbg, predicate = () => true) {
|
|||
});
|
||||
}
|
||||
|
||||
function waitForWorkerMessage(worker, message) {
|
||||
return new Promise(function (resolve) {
|
||||
worker.addEventListener("message", function onmessage(event) {
|
||||
if (event.data !== message) {
|
||||
return;
|
||||
}
|
||||
ok(true, "Should receive " + message + " message from worker.");
|
||||
worker.removeEventListener("message", onmessage);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function waitForMultiple(promises) {
|
||||
return new Promise(function (resolve) {
|
||||
let results = [];
|
||||
let values = [];
|
||||
for (let i = 0; i < promises.length; ++i) {
|
||||
let promise = promises[i];
|
||||
let index = i;
|
||||
promise.then(function (result) {
|
||||
is(results.length, index, "events should occur in the specified order");
|
||||
results.push(result);
|
||||
if (results.length === promises.length) {
|
||||
resolve(results);
|
||||
promises[i].then(function (value) {
|
||||
is(index + 1, values.length + 1,
|
||||
"Promise " + (values.length + 1) + " out of " + promises.length +
|
||||
" should be resolved.");
|
||||
values.push(value);
|
||||
if (values.length === promises.length) {
|
||||
resolve(values);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<window title="Test for WorkerDebugger.initialize"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="test();">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
<script type="application/javascript" src="dom_worker_helper.js"/>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
const WORKER_URL = "WorkerDebugger.initialize_worker.js";
|
||||
const CHILD_WORKER_URL = "WorkerDebugger.initialize_childWorker.js";
|
||||
const DEBUGGER_URL = BASE_URL + "WorkerDebugger.initialize_debugger.js";
|
||||
|
||||
function test() {
|
||||
Task.spawn(function* () {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
info("Create a worker that creates a child worker, wait for their " +
|
||||
"debuggers to be registered, and initialize them.");
|
||||
let promise = waitForMultiple([
|
||||
waitForRegister(WORKER_URL, DEBUGGER_URL),
|
||||
waitForRegister(CHILD_WORKER_URL, DEBUGGER_URL)
|
||||
]);
|
||||
let worker = new Worker(WORKER_URL);
|
||||
yield promise;
|
||||
|
||||
info("Check that the debuggers are initialized before the workers " +
|
||||
"start running.");
|
||||
yield waitForMultiple([
|
||||
waitForWorkerMessage(worker, "debugger"),
|
||||
waitForWorkerMessage(worker, "worker"),
|
||||
waitForWorkerMessage(worker, "child:debugger"),
|
||||
waitForWorkerMessage(worker, "child:worker")
|
||||
]);
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display:none;"></div>
|
||||
<pre id="test"></pre>
|
||||
</body>
|
||||
<label id="test-result"/>
|
||||
</window>
|
|
@ -16,7 +16,7 @@
|
|||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
const PARENT_WORKER_URL = "WorkerDebugger_parentWorker.js";
|
||||
const WORKER_URL = "WorkerDebugger_worker.js";
|
||||
const CHILD_WORKER_URL = "WorkerDebugger_childWorker.js";
|
||||
const SHARED_WORKER_URL = "WorkerDebugger_sharedWorker.js";
|
||||
|
||||
|
@ -24,65 +24,89 @@
|
|||
Task.spawn(function* () {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
info("Create a top-level chrome worker that creates a non-top-level " +
|
||||
"content worker and wait for their debuggers to be registered.");
|
||||
let promise = waitForMultiple([
|
||||
waitForRegister((dbg) => dbg.url === PARENT_WORKER_URL),
|
||||
waitForRegister((dbg) => dbg.url === CHILD_WORKER_URL),
|
||||
waitForRegister(WORKER_URL),
|
||||
waitForRegister(CHILD_WORKER_URL)
|
||||
]);
|
||||
worker = new ChromeWorker(PARENT_WORKER_URL);
|
||||
let dbgs = yield promise;
|
||||
is(dbgs[0].isChrome, true, "debugger should be for chrome worker");
|
||||
is(dbgs[0].parent, null,
|
||||
"debugger for a top-level worker should not have parent");
|
||||
is(dbgs[0].type, Ci.nsIWorkerDebugger.TYPE_DEDICATED,
|
||||
"debugger should be for dedicated worker");
|
||||
is(dbgs[0].window, window,
|
||||
"debugger for top-level dedicated worker should have window");
|
||||
is(dbgs[1].isChrome, false, "debugger should be for content worker");
|
||||
is(dbgs[1].parent, dbgs[0],
|
||||
"debugger for child worker should have parent");
|
||||
is(dbgs[1].type, Ci.nsIWorkerDebugger.TYPE_DEDICATED);
|
||||
is(dbgs[1].window, null,
|
||||
"debugger for non-top-level worker should not have window");
|
||||
worker = new ChromeWorker(WORKER_URL);
|
||||
let [dbg, childDbg] = yield promise;
|
||||
|
||||
info("Check that the top-level chrome worker debugger has the " +
|
||||
"correct properties.");
|
||||
is(dbg.isChrome, true,
|
||||
"Chrome worker debugger should be chrome.");
|
||||
is(dbg.parent, null,
|
||||
"Top-level debugger should not have parent.");
|
||||
is(dbg.type, Ci.nsIWorkerDebugger.TYPE_DEDICATED,
|
||||
"Chrome worker debugger should be dedicated.");
|
||||
is(dbg.window, window,
|
||||
"Top-level dedicated worker debugger should have window.");
|
||||
|
||||
info("Check that the non-top-level content worker debugger has the " +
|
||||
"correct properties.");
|
||||
is(childDbg.isChrome, false,
|
||||
"Content worker debugger should be content.");
|
||||
is(childDbg.parent, dbg,
|
||||
"Non-top-level worker debugger should have parent.");
|
||||
is(childDbg.type, Ci.nsIWorkerDebugger.TYPE_DEDICATED,
|
||||
"Content worker debugger should be dedicated.");
|
||||
is(childDbg.window, null,
|
||||
"Non-top-level worker debugger should not have window.");
|
||||
|
||||
info("Terminate the top-level chrome worker and the non-top-level " +
|
||||
"content worker, and wait for their debuggers to be " +
|
||||
"unregistered and closed.");
|
||||
promise = waitForMultiple([
|
||||
waitForUnregister((dbg) => dbg.url === CHILD_WORKER_URL),
|
||||
waitForDebuggerClose(dbgs[1]),
|
||||
waitForUnregister((dbg) => dbg.url === PARENT_WORKER_URL),
|
||||
waitForDebuggerClose(dbgs[0]),
|
||||
waitForUnregister(CHILD_WORKER_URL),
|
||||
waitForDebuggerClose(childDbg),
|
||||
waitForUnregister(WORKER_URL),
|
||||
waitForDebuggerClose(dbg),
|
||||
]);
|
||||
worker.terminate();
|
||||
yield promise;
|
||||
|
||||
promise = waitForRegister();
|
||||
info("Create a shared worker and wait for its debugger to be " +
|
||||
"registered");
|
||||
promise = waitForRegister(SHARED_WORKER_URL);
|
||||
worker = new SharedWorker(SHARED_WORKER_URL);
|
||||
let dbg = yield promise;
|
||||
is(dbg.isChrome, false, "debugger should be for content worker");
|
||||
is(dbg.parent, null,
|
||||
"debugger for top-level worker should not have parent");
|
||||
is(dbg.type, Ci.nsIWorkerDebugger.TYPE_SHARED,
|
||||
"debugger should be for shared worker");
|
||||
is(dbg.window, null,
|
||||
"debugger for non-dedicated worker should not have window");
|
||||
let sharedDbg = yield promise;
|
||||
|
||||
info("Check that the shared worker debugger has the correct " +
|
||||
"properties.");
|
||||
is(sharedDbg.isChrome, false,
|
||||
"Shared worker debugger should be content.");
|
||||
is(sharedDbg.parent, null,
|
||||
"Shared worker debugger should not have parent.");
|
||||
is(sharedDbg.type, Ci.nsIWorkerDebugger.TYPE_SHARED,
|
||||
"Shared worker debugger should be shared.");
|
||||
is(sharedDbg.window, null,
|
||||
"Shared worker debugger should not have window.");
|
||||
|
||||
info("Create a shared worker with the same URL and check that its " +
|
||||
"debugger is not registered again.");
|
||||
let listener = {
|
||||
onRegistered: function () {
|
||||
ok(false,
|
||||
"debugger for shared worker should not be registered twice");
|
||||
"Shared worker debugger should not be registered again.");
|
||||
},
|
||||
};
|
||||
wdm.addListener(listener);
|
||||
worker = new SharedWorker(SHARED_WORKER_URL);
|
||||
|
||||
dbg.addListener({
|
||||
onClose: function () {
|
||||
is(dbg.isClosed, true, "debugger should be closed");
|
||||
wdm.removeListener(listener);
|
||||
dbg.removeListener(this);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
});
|
||||
info("Send a message to the shared worker to tell it to close " +
|
||||
"itself, and wait for its debugger to be closed.");
|
||||
promise = waitForMultiple([
|
||||
waitForUnregister(SHARED_WORKER_URL),
|
||||
waitForDebuggerClose(sharedDbg)
|
||||
]);
|
||||
worker.port.start();
|
||||
worker.port.postMessage("close");
|
||||
yield promise;
|
||||
|
||||
wdm.removeListener(listener);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -16,65 +16,79 @@
|
|||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
const PARENT_WORKER_URL = "WorkerDebuggerManager_parentWorker.js";
|
||||
const WORKER_URL = "WorkerDebuggerManager_worker.js";
|
||||
const CHILD_WORKER_URL = "WorkerDebuggerManager_childWorker.js";
|
||||
|
||||
function test() {
|
||||
Task.spawn(function* () {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
ok(!findDebugger((dbg) => dbg.url === PARENT_WORKER_URL),
|
||||
"debugger for parent worker should not be enumerated before it is " +
|
||||
"registered");
|
||||
ok(!findDebugger((dbg) => dbg.url === CHILD_WORKER_URL),
|
||||
"debugger for child worker should not be enumerated before it is " +
|
||||
"registered");
|
||||
info("Check that worker debuggers are not enumerated before they are " +
|
||||
"registered.");
|
||||
ok(!findDebugger(WORKER_URL),
|
||||
"Worker debugger should not be enumerated before it is registered.");
|
||||
ok(!findDebugger(CHILD_WORKER_URL),
|
||||
"Child worker debugger should not be enumerated before it is " +
|
||||
"registered.");
|
||||
|
||||
info("Create a worker that creates a child worker, and wait for " +
|
||||
"their debuggers to be registered.");
|
||||
let promise = waitForMultiple([
|
||||
waitForRegister((dbg) => dbg.url === PARENT_WORKER_URL),
|
||||
waitForRegister((dbg) => dbg.url === CHILD_WORKER_URL),
|
||||
waitForRegister(WORKER_URL),
|
||||
waitForRegister(CHILD_WORKER_URL)
|
||||
]);
|
||||
let worker = new Worker(PARENT_WORKER_URL);
|
||||
let dbgs = yield promise;
|
||||
is(dbgs[0].isClosed, false,
|
||||
"debugger for parent worker should not be closed after it is " +
|
||||
"registered");
|
||||
is(dbgs[1].isClosed, false,
|
||||
"debugger for child worker should not be closed after it is " +
|
||||
"registered");
|
||||
let worker = new Worker(WORKER_URL);
|
||||
let [dbg, childDbg] = yield promise;
|
||||
|
||||
ok(findDebugger((dbg) => dbg.url === PARENT_WORKER_URL),
|
||||
"debugger for parent worker should be enumerated after it is " +
|
||||
"registered");
|
||||
ok(findDebugger((dbg) => dbg.url === CHILD_WORKER_URL),
|
||||
"debugger for child worker should be enumerated after it is " +
|
||||
"registered");
|
||||
info("Check that worker debuggers are enumerated after they are " +
|
||||
"registered.");
|
||||
ok(findDebugger(WORKER_URL),
|
||||
"Worker debugger should be enumerated after it is registered.");
|
||||
ok(findDebugger(CHILD_WORKER_URL),
|
||||
"Child worker debugger should be enumerated after it is " +
|
||||
"registered.");
|
||||
|
||||
info("Check that worker debuggers are not closed before they are " +
|
||||
"unregistered.");
|
||||
is(dbg.isClosed, false,
|
||||
"Worker debugger should not be closed before it is unregistered.");
|
||||
is(childDbg.isClosed, false,
|
||||
"Child worker debugger should not be closed before it is " +
|
||||
"unregistered");
|
||||
|
||||
info("Terminate the worker and the child worker, and wait for their " +
|
||||
"debuggers to be unregistered");
|
||||
promise = waitForMultiple([
|
||||
waitForUnregister((dbg) => dbg.url === CHILD_WORKER_URL),
|
||||
waitForUnregister((dbg) => dbg.url === PARENT_WORKER_URL),
|
||||
waitForUnregister(CHILD_WORKER_URL),
|
||||
waitForUnregister(WORKER_URL),
|
||||
]);
|
||||
worker.terminate();
|
||||
dbgs = yield promise;
|
||||
is(dbgs[0].isClosed, true,
|
||||
"debugger for parent worker should be closed after it is " +
|
||||
"unregistered");
|
||||
is(dbgs[1].isClosed, true,
|
||||
"debugger for child worker should be closed after it is " +
|
||||
"unregistered");
|
||||
assertThrows(() => dbgs[0].url,
|
||||
"accessing debugger for parent worker should throw " +
|
||||
"after it is closed");
|
||||
assertThrows(() => dbgs[0].url,
|
||||
"accessing debugger for child worker should throw after " +
|
||||
"it is closed");
|
||||
yield promise;
|
||||
|
||||
ok(!findDebugger((dbg) => dbg.url === PARENT_WORKER_URL),
|
||||
"debugger for parent worker should not be enumerated after it is " +
|
||||
"unregistered");
|
||||
ok(!findDebugger((dbg) => dbg.url === CHILD_WORKER_URL),
|
||||
"debugger for child worker should not be enumerated after it is " +
|
||||
"unregistered");
|
||||
info("Check that worker debuggers are not enumerated after they are " +
|
||||
"unregistered.");
|
||||
ok(!findDebugger(WORKER_URL),
|
||||
"Worker debugger should not be enumerated after it is " +
|
||||
"unregistered.");
|
||||
ok(!findDebugger(CHILD_WORKER_URL),
|
||||
"Child worker debugger should not be enumerated after it is " +
|
||||
"unregistered.");
|
||||
|
||||
info("Check that worker debuggers are closed after they are " +
|
||||
"unregistered.");
|
||||
is(dbg.isClosed, true,
|
||||
"Worker debugger should be closed after it is unregistered.");
|
||||
is(childDbg.isClosed, true,
|
||||
"Child worker debugger should be closed after it is unregistered.");
|
||||
|
||||
info("Check that property accesses on worker debuggers throws " +
|
||||
"after they are closed.");
|
||||
assertThrows(() => dbg.url,
|
||||
"Property accesses on worker debugger should throw " +
|
||||
"after it is closed.");
|
||||
assertThrows(() => childDbg.url,
|
||||
"Property accesses on child worker debugger should " +
|
||||
"throw after it is closed.");
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче