mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 958011: Fix worker object cycle collection to not rely on the JSObject being finalized, which is a bogus assumption. r=bent,mccr8
This commit is contained in:
parent
505293a09f
commit
10bd0f9941
@ -27,11 +27,6 @@
|
|||||||
# * workers - Indicates whether the descriptor is intended to be used solely
|
# * workers - Indicates whether the descriptor is intended to be used solely
|
||||||
# for worker threads (defaults to false). If true the interface
|
# for worker threads (defaults to false). If true the interface
|
||||||
# will not be made available on the main thread.
|
# will not be made available on the main thread.
|
||||||
# * customFinalize - The native class will use a custom finalize hook
|
|
||||||
# (defaults to true for workers, false otherwise).
|
|
||||||
# * customWrapperManagement - The native class will be responsible for
|
|
||||||
# preserving its own wrapper (no AddProperty
|
|
||||||
# hook will be generated, defaults to false).
|
|
||||||
# * notflattened - The native type does not have nsIClassInfo, so when
|
# * notflattened - The native type does not have nsIClassInfo, so when
|
||||||
# wrapping it the right IID needs to be passed in.
|
# wrapping it the right IID needs to be passed in.
|
||||||
# * register - True if this binding should be registered. Defaults to true.
|
# * register - True if this binding should be registered. Defaults to true.
|
||||||
@ -221,8 +216,6 @@ DOMInterfaces = {
|
|||||||
'ChromeWorker': {
|
'ChromeWorker': {
|
||||||
'headerFile': 'mozilla/dom/WorkerPrivate.h',
|
'headerFile': 'mozilla/dom/WorkerPrivate.h',
|
||||||
'nativeType': 'mozilla::dom::workers::ChromeWorkerPrivate',
|
'nativeType': 'mozilla::dom::workers::ChromeWorkerPrivate',
|
||||||
'customFinalize': True,
|
|
||||||
'customWrapperManagement': True,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
'DOMRectList': {
|
'DOMRectList': {
|
||||||
@ -1526,8 +1519,6 @@ DOMInterfaces = {
|
|||||||
'implicitJSContext': [
|
'implicitJSContext': [
|
||||||
'terminate',
|
'terminate',
|
||||||
],
|
],
|
||||||
'customFinalize': True,
|
|
||||||
'customWrapperManagement': True,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
'WorkerGlobalScope': {
|
'WorkerGlobalScope': {
|
||||||
|
@ -45,7 +45,7 @@ def isTypeCopyConstructible(type):
|
|||||||
|
|
||||||
def wantsAddProperty(desc):
|
def wantsAddProperty(desc):
|
||||||
return desc.concrete and \
|
return desc.concrete and \
|
||||||
desc.wrapperCache and not desc.customWrapperManagement and \
|
desc.wrapperCache and \
|
||||||
not desc.interface.getExtendedAttribute("Global")
|
not desc.interface.getExtendedAttribute("Global")
|
||||||
|
|
||||||
class CGThing():
|
class CGThing():
|
||||||
@ -1078,18 +1078,15 @@ def DeferredFinalizeSmartPtr(descriptor):
|
|||||||
return smartPtr
|
return smartPtr
|
||||||
|
|
||||||
def finalizeHook(descriptor, hookName, freeOp):
|
def finalizeHook(descriptor, hookName, freeOp):
|
||||||
if descriptor.customFinalize:
|
finalize = "JSBindingFinalized<%s>::Finalized(self);\n" % descriptor.nativeType
|
||||||
finalize = "self->%s(CastToJSFreeOp(%s));" % (hookName, freeOp)
|
if descriptor.wrapperCache:
|
||||||
else:
|
finalize += "ClearWrapper(self, self);\n"
|
||||||
finalize = "JSBindingFinalized<%s>::Finalized(self);\n" % descriptor.nativeType
|
if descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
|
||||||
if descriptor.wrapperCache:
|
finalize += "self->mExpandoAndGeneration.expando = JS::UndefinedValue();\n"
|
||||||
finalize += "ClearWrapper(self, self);\n"
|
if descriptor.interface.getExtendedAttribute("Global"):
|
||||||
if descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
|
finalize += "mozilla::dom::FinalizeGlobal(CastToJSFreeOp(%s), obj);\n" % freeOp
|
||||||
finalize += "self->mExpandoAndGeneration.expando = JS::UndefinedValue();\n"
|
finalize += ("AddForDeferredFinalization<%s, %s >(self);" %
|
||||||
if descriptor.interface.getExtendedAttribute("Global"):
|
(descriptor.nativeType, DeferredFinalizeSmartPtr(descriptor)))
|
||||||
finalize += "mozilla::dom::FinalizeGlobal(CastToJSFreeOp(%s), obj);\n" % freeOp
|
|
||||||
finalize += ("AddForDeferredFinalization<%s, %s >(self);" %
|
|
||||||
(descriptor.nativeType, DeferredFinalizeSmartPtr(descriptor)))
|
|
||||||
return CGIfWrapper(CGGeneric(finalize), "self")
|
return CGIfWrapper(CGGeneric(finalize), "self")
|
||||||
|
|
||||||
class CGClassFinalizeHook(CGAbstractClassHook):
|
class CGClassFinalizeHook(CGAbstractClassHook):
|
||||||
|
@ -368,17 +368,11 @@ class Descriptor(DescriptorProvider):
|
|||||||
raise TypeError("Descriptor for %s has unrecognized value (%s) "
|
raise TypeError("Descriptor for %s has unrecognized value (%s) "
|
||||||
"for nativeOwnership" %
|
"for nativeOwnership" %
|
||||||
(self.interface.identifier.name, self.nativeOwnership))
|
(self.interface.identifier.name, self.nativeOwnership))
|
||||||
self.customFinalize = desc.get('customFinalize', False)
|
|
||||||
self.customWrapperManagement = desc.get('customWrapperManagement', False)
|
|
||||||
if desc.get('wantsQI', None) != None:
|
if desc.get('wantsQI', None) != None:
|
||||||
self._wantsQI = desc.get('wantsQI', None)
|
self._wantsQI = desc.get('wantsQI', None)
|
||||||
self.wrapperCache = (not self.interface.isCallback() and
|
self.wrapperCache = (not self.interface.isCallback() and
|
||||||
(self.nativeOwnership != 'owned' and
|
(self.nativeOwnership != 'owned' and
|
||||||
desc.get('wrapperCache', True)))
|
desc.get('wrapperCache', True)))
|
||||||
if self.customWrapperManagement and not self.wrapperCache:
|
|
||||||
raise TypeError("Descriptor for %s has customWrapperManagement "
|
|
||||||
"but is not wrapperCached." %
|
|
||||||
(self.interface.identifier.name))
|
|
||||||
|
|
||||||
def make_name(name):
|
def make_name(name):
|
||||||
return name + "_workers" if self.workers else name
|
return name + "_workers" if self.workers else name
|
||||||
|
@ -769,14 +769,12 @@ private:
|
|||||||
NS_WARNING("Failed to dispatch, going to leak!");
|
NS_WARNING("Failed to dispatch, going to leak!");
|
||||||
}
|
}
|
||||||
|
|
||||||
mFinishedWorker->Finish(aCx);
|
|
||||||
|
|
||||||
RuntimeService* runtime = RuntimeService::GetService();
|
RuntimeService* runtime = RuntimeService::GetService();
|
||||||
NS_ASSERTION(runtime, "This should never be null!");
|
NS_ASSERTION(runtime, "This should never be null!");
|
||||||
|
|
||||||
runtime->UnregisterWorker(aCx, mFinishedWorker);
|
runtime->UnregisterWorker(aCx, mFinishedWorker);
|
||||||
|
|
||||||
mFinishedWorker->Release();
|
mFinishedWorker->ClearSelfRef();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -800,14 +798,12 @@ private:
|
|||||||
{
|
{
|
||||||
AssertIsOnMainThread();
|
AssertIsOnMainThread();
|
||||||
|
|
||||||
|
RuntimeService* runtime = RuntimeService::GetService();
|
||||||
|
MOZ_ASSERT(runtime);
|
||||||
|
|
||||||
AutoSafeJSContext cx;
|
AutoSafeJSContext cx;
|
||||||
JSAutoRequest ar(cx);
|
JSAutoRequest ar(cx);
|
||||||
|
|
||||||
mFinishedWorker->Finish(cx);
|
|
||||||
|
|
||||||
RuntimeService* runtime = RuntimeService::GetService();
|
|
||||||
NS_ASSERTION(runtime, "This should never be null!");
|
|
||||||
|
|
||||||
runtime->UnregisterWorker(cx, mFinishedWorker);
|
runtime->UnregisterWorker(cx, mFinishedWorker);
|
||||||
|
|
||||||
nsTArray<nsCOMPtr<nsISupports> > doomed;
|
nsTArray<nsCOMPtr<nsISupports> > doomed;
|
||||||
@ -822,8 +818,7 @@ private:
|
|||||||
NS_WARNING("Failed to dispatch, going to leak!");
|
NS_WARNING("Failed to dispatch, going to leak!");
|
||||||
}
|
}
|
||||||
|
|
||||||
mFinishedWorker->Release();
|
mFinishedWorker->ClearSelfRef();
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -2109,7 +2104,7 @@ WorkerPrivateParent<Derived>::WorkerPrivateParent(
|
|||||||
mMemoryReportCondVar(mMutex, "WorkerPrivateParent Memory Report CondVar"),
|
mMemoryReportCondVar(mMutex, "WorkerPrivateParent Memory Report CondVar"),
|
||||||
mParent(aParent), mScriptURL(aScriptURL),
|
mParent(aParent), mScriptURL(aScriptURL),
|
||||||
mSharedWorkerName(aSharedWorkerName), mBusyCount(0), mMessagePortSerial(0),
|
mSharedWorkerName(aSharedWorkerName), mBusyCount(0), mMessagePortSerial(0),
|
||||||
mParentStatus(Pending), mRooted(false), mParentSuspended(false),
|
mParentStatus(Pending), mParentSuspended(false),
|
||||||
mIsChromeWorker(aIsChromeWorker), mMainThreadObjectsForgotten(false),
|
mIsChromeWorker(aIsChromeWorker), mMainThreadObjectsForgotten(false),
|
||||||
mWorkerType(aWorkerType)
|
mWorkerType(aWorkerType)
|
||||||
{
|
{
|
||||||
@ -2143,8 +2138,6 @@ WorkerPrivateParent<Derived>::WorkerPrivateParent(
|
|||||||
template <class Derived>
|
template <class Derived>
|
||||||
WorkerPrivateParent<Derived>::~WorkerPrivateParent()
|
WorkerPrivateParent<Derived>::~WorkerPrivateParent()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!mRooted);
|
|
||||||
|
|
||||||
DropJSObjects(this);
|
DropJSObjects(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2158,13 +2151,7 @@ WorkerPrivateParent<Derived>::WrapObject(JSContext* aCx,
|
|||||||
|
|
||||||
AssertIsOnParentThread();
|
AssertIsOnParentThread();
|
||||||
|
|
||||||
JS::Rooted<JSObject*> obj(aCx, WorkerBinding::Wrap(aCx, aScope, ParentAsWorkerPrivate()));
|
return WorkerBinding::Wrap(aCx, aScope, ParentAsWorkerPrivate());
|
||||||
|
|
||||||
if (mRooted) {
|
|
||||||
PreserveWrapper(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Derived>
|
template <class Derived>
|
||||||
@ -2606,25 +2593,6 @@ WorkerPrivateParent<Derived>::SynchronizeAndResume(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Derived>
|
|
||||||
void
|
|
||||||
WorkerPrivateParent<Derived>::_finalize(JSFreeOp* aFop)
|
|
||||||
{
|
|
||||||
AssertIsOnParentThread();
|
|
||||||
|
|
||||||
MOZ_ASSERT(!mRooted);
|
|
||||||
|
|
||||||
ClearWrapper();
|
|
||||||
|
|
||||||
// Ensure that we're held alive across the TerminatePrivate call, and then
|
|
||||||
// release the reference our wrapper held to us.
|
|
||||||
nsRefPtr<WorkerPrivateParent<Derived> > kungFuDeathGrip = dont_AddRef(this);
|
|
||||||
|
|
||||||
if (!TerminatePrivate(nullptr)) {
|
|
||||||
NS_WARNING("Failed to terminate!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Derived>
|
template <class Derived>
|
||||||
bool
|
bool
|
||||||
WorkerPrivateParent<Derived>::Close(JSContext* aCx)
|
WorkerPrivateParent<Derived>::Close(JSContext* aCx)
|
||||||
@ -2651,14 +2619,11 @@ WorkerPrivateParent<Derived>::ModifyBusyCount(JSContext* aCx, bool aIncrease)
|
|||||||
NS_ASSERTION(aIncrease || mBusyCount, "Mismatched busy count mods!");
|
NS_ASSERTION(aIncrease || mBusyCount, "Mismatched busy count mods!");
|
||||||
|
|
||||||
if (aIncrease) {
|
if (aIncrease) {
|
||||||
if (mBusyCount++ == 0) {
|
mBusyCount++;
|
||||||
Root(true);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (--mBusyCount == 0) {
|
if (--mBusyCount == 0) {
|
||||||
Root(false);
|
|
||||||
|
|
||||||
bool shouldCancel;
|
bool shouldCancel;
|
||||||
{
|
{
|
||||||
@ -2674,32 +2639,6 @@ WorkerPrivateParent<Derived>::ModifyBusyCount(JSContext* aCx, bool aIncrease)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Derived>
|
|
||||||
void
|
|
||||||
WorkerPrivateParent<Derived>::Root(bool aRoot)
|
|
||||||
{
|
|
||||||
AssertIsOnParentThread();
|
|
||||||
|
|
||||||
if (aRoot == mRooted) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aRoot) {
|
|
||||||
NS_ADDREF_THIS();
|
|
||||||
if (GetWrapperPreserveColor()) {
|
|
||||||
PreserveWrapper(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (GetWrapperPreserveColor()) {
|
|
||||||
ReleaseWrapper(this);
|
|
||||||
}
|
|
||||||
NS_RELEASE_THIS();
|
|
||||||
}
|
|
||||||
|
|
||||||
mRooted = aRoot;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Derived>
|
template <class Derived>
|
||||||
void
|
void
|
||||||
WorkerPrivateParent<Derived>::ForgetMainThreadObjects(
|
WorkerPrivateParent<Derived>::ForgetMainThreadObjects(
|
||||||
@ -3512,16 +3451,28 @@ NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
|
|||||||
template <class Derived>
|
template <class Derived>
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerPrivateParent<Derived>,
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerPrivateParent<Derived>,
|
||||||
nsDOMEventTargetHelper)
|
nsDOMEventTargetHelper)
|
||||||
// Nothing else to traverse
|
tmp->AssertIsOnParentThread();
|
||||||
|
|
||||||
|
// The WorkerPrivate::mSelfRef has a reference to itself, which is really
|
||||||
|
// held by the worker thread. We traverse this reference if and only if our
|
||||||
|
// busy count is zero and we have not released the main thread reference.
|
||||||
|
// We do not unlink it. This allows the CC to break cycles involving the
|
||||||
|
// WorkerPrivate and begin shutting it down (which does happen in unlink) but
|
||||||
|
// ensures that the WorkerPrivate won't be deleted before we're done shutting
|
||||||
|
// down the thread.
|
||||||
|
|
||||||
|
if (!tmp->mBusyCount && !tmp->mMainThreadObjectsForgotten) {
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelfRef)
|
||||||
|
}
|
||||||
|
|
||||||
// The various strong references in LoadInfo are managed manually and cannot
|
// The various strong references in LoadInfo are managed manually and cannot
|
||||||
// be cycle collected.
|
// be cycle collected.
|
||||||
tmp->AssertIsOnParentThread();
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
template <class Derived>
|
template <class Derived>
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerPrivateParent<Derived>,
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerPrivateParent<Derived>,
|
||||||
nsDOMEventTargetHelper)
|
nsDOMEventTargetHelper)
|
||||||
tmp->AssertIsOnParentThread();
|
tmp->Terminate(nullptr);
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
|
|
||||||
template <class Derived>
|
template <class Derived>
|
||||||
@ -3721,10 +3672,7 @@ WorkerPrivate::Constructor(const GlobalObject& aGlobal,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The worker will be owned by its JSObject (via the reference we return from
|
worker->mSelfRef = worker;
|
||||||
// this function), but it also needs to be owned by its thread, so AddRef it
|
|
||||||
// again.
|
|
||||||
NS_ADDREF(worker.get());
|
|
||||||
|
|
||||||
return worker.forget();
|
return worker.forget();
|
||||||
}
|
}
|
||||||
|
@ -232,13 +232,17 @@ private:
|
|||||||
uint64_t mBusyCount;
|
uint64_t mBusyCount;
|
||||||
uint64_t mMessagePortSerial;
|
uint64_t mMessagePortSerial;
|
||||||
Status mParentStatus;
|
Status mParentStatus;
|
||||||
bool mRooted;
|
|
||||||
bool mParentSuspended;
|
bool mParentSuspended;
|
||||||
bool mIsChromeWorker;
|
bool mIsChromeWorker;
|
||||||
bool mMainThreadObjectsForgotten;
|
bool mMainThreadObjectsForgotten;
|
||||||
WorkerType mWorkerType;
|
WorkerType mWorkerType;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
// The worker is owned by its thread, which is represented here. This is set
|
||||||
|
// in Construct() and emptied by WorkerFinishedRunnable, and conditionally
|
||||||
|
// traversed by the cycle collector if the busy count is zero.
|
||||||
|
nsRefPtr<WorkerPrivate> mSelfRef;
|
||||||
|
|
||||||
WorkerPrivateParent(JSContext* aCx, WorkerPrivate* aParent,
|
WorkerPrivateParent(JSContext* aCx, WorkerPrivate* aParent,
|
||||||
const nsAString& aScriptURL, bool aIsChromeWorker,
|
const nsAString& aScriptURL, bool aIsChromeWorker,
|
||||||
WorkerType aWorkerType,
|
WorkerType aWorkerType,
|
||||||
@ -281,6 +285,14 @@ public:
|
|||||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WorkerPrivateParent,
|
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WorkerPrivateParent,
|
||||||
nsDOMEventTargetHelper)
|
nsDOMEventTargetHelper)
|
||||||
|
|
||||||
|
void
|
||||||
|
ClearSelfRef()
|
||||||
|
{
|
||||||
|
AssertIsOnParentThread();
|
||||||
|
MOZ_ASSERT(mSelfRef);
|
||||||
|
mSelfRef = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
Dispatch(WorkerRunnable* aRunnable)
|
Dispatch(WorkerRunnable* aRunnable)
|
||||||
{
|
{
|
||||||
@ -329,20 +341,10 @@ public:
|
|||||||
SynchronizeAndResume(JSContext* aCx, nsPIDOMWindow* aWindow,
|
SynchronizeAndResume(JSContext* aCx, nsPIDOMWindow* aWindow,
|
||||||
nsIScriptContext* aScriptContext);
|
nsIScriptContext* aScriptContext);
|
||||||
|
|
||||||
void
|
|
||||||
_finalize(JSFreeOp* aFop);
|
|
||||||
|
|
||||||
void
|
|
||||||
Finish(JSContext* aCx)
|
|
||||||
{
|
|
||||||
Root(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Terminate(JSContext* aCx)
|
Terminate(JSContext* aCx)
|
||||||
{
|
{
|
||||||
AssertIsOnParentThread();
|
AssertIsOnParentThread();
|
||||||
Root(false);
|
|
||||||
return TerminatePrivate(aCx);
|
return TerminatePrivate(aCx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,9 +354,6 @@ public:
|
|||||||
bool
|
bool
|
||||||
ModifyBusyCount(JSContext* aCx, bool aIncrease);
|
ModifyBusyCount(JSContext* aCx, bool aIncrease);
|
||||||
|
|
||||||
void
|
|
||||||
Root(bool aRoot);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ForgetMainThreadObjects(nsTArray<nsCOMPtr<nsISupports> >& aDoomed);
|
ForgetMainThreadObjects(nsTArray<nsCOMPtr<nsISupports> >& aDoomed);
|
||||||
|
|
||||||
|
@ -8,12 +8,12 @@ function handleRequest(request, response)
|
|||||||
response.setHeader("Cache-Control", "no-cache", false);
|
response.setHeader("Cache-Control", "no-cache", false);
|
||||||
|
|
||||||
if (request.method == "POST") {
|
if (request.method == "POST") {
|
||||||
setState("seenPost", "1");
|
setState("seenPost" + request.queryString, "1");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.method == "GET") {
|
if (request.method == "GET") {
|
||||||
if (getState("seenPost") == "1") {
|
if (getState("seenPost" + request.queryString) == "1") {
|
||||||
response.write("closed");
|
response.write("closed");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
onclose = function() {
|
onclose = function() {
|
||||||
var xhr = new XMLHttpRequest();
|
var xhr = new XMLHttpRequest();
|
||||||
xhr.open("POST", "closeOnGC_server.sjs", false);
|
xhr.open("POST", "closeOnGC_server.sjs" + location.search, false);
|
||||||
xhr.send();
|
xhr.send();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -15,24 +15,39 @@
|
|||||||
<pre id="test">
|
<pre id="test">
|
||||||
<script class="testbody" type="text/javascript">
|
<script class="testbody" type="text/javascript">
|
||||||
|
|
||||||
var worker = new Worker("closeOnGC_worker.js");
|
var count = 0;
|
||||||
worker.onmessage = function(event) {
|
|
||||||
is(event.data, "ready");
|
function testWorker(queryString) {
|
||||||
worker = null;
|
++count;
|
||||||
|
var worker = new Worker("closeOnGC_worker.js?" + queryString);
|
||||||
|
worker.onmessage = function(event) {
|
||||||
|
is(event.data, "ready");
|
||||||
|
worker = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var interval = setInterval(function() {
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.open("GET", "closeOnGC_server.sjs?" + queryString, false);
|
||||||
|
xhr.send();
|
||||||
|
if (xhr.responseText != "closed") {
|
||||||
|
SpecialPowers.gc();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
clearInterval(interval);
|
||||||
|
ok(true, "xhr correctly closed");
|
||||||
|
if (--count == 0) {
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
return worker;
|
||||||
}
|
}
|
||||||
|
|
||||||
var interval = setInterval(function() {
|
testWorker("white");
|
||||||
var xhr = new XMLHttpRequest();
|
var worker = testWorker("gray");
|
||||||
xhr.open("GET", "closeOnGC_server.sjs", false);
|
worker.onerror = function() {};
|
||||||
xhr.send();
|
worker.onerror.foo = worker;
|
||||||
if (xhr.responseText != "closed") {
|
worker = null;
|
||||||
SpecialPowers.gc();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
clearInterval(interval);
|
|
||||||
ok(true, "xhr correctly closed");
|
|
||||||
SimpleTest.finish();
|
|
||||||
}, 500);
|
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user