mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1107775 - Make deferred finalization more re-entrant safe, r=mccr8
This commit is contained in:
parent
11a9491dc2
commit
428fcb7c71
@ -57,6 +57,7 @@
|
|||||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "mozilla/ArrayUtils.h"
|
#include "mozilla/ArrayUtils.h"
|
||||||
|
#include "mozilla/AutoRestore.h"
|
||||||
#include "mozilla/MemoryReporting.h"
|
#include "mozilla/MemoryReporting.h"
|
||||||
#include "mozilla/dom/BindingUtils.h"
|
#include "mozilla/dom/BindingUtils.h"
|
||||||
#include "mozilla/dom/DOMJSClass.h"
|
#include "mozilla/dom/DOMJSClass.h"
|
||||||
@ -96,6 +97,7 @@ class IncrementalFinalizeRunnable : public nsRunnable
|
|||||||
nsTArray<nsISupports*> mSupports;
|
nsTArray<nsISupports*> mSupports;
|
||||||
DeferredFinalizeArray mDeferredFinalizeFunctions;
|
DeferredFinalizeArray mDeferredFinalizeFunctions;
|
||||||
uint32_t mFinalizeFunctionToRun;
|
uint32_t mFinalizeFunctionToRun;
|
||||||
|
bool mReleasing;
|
||||||
|
|
||||||
static const PRTime SliceMillis = 10; /* ms */
|
static const PRTime SliceMillis = 10; /* ms */
|
||||||
|
|
||||||
@ -1124,6 +1126,7 @@ IncrementalFinalizeRunnable::IncrementalFinalizeRunnable(CycleCollectedJSRuntime
|
|||||||
DeferredFinalizerTable& aFinalizers)
|
DeferredFinalizerTable& aFinalizers)
|
||||||
: mRuntime(aRt)
|
: mRuntime(aRt)
|
||||||
, mFinalizeFunctionToRun(0)
|
, mFinalizeFunctionToRun(0)
|
||||||
|
, mReleasing(false)
|
||||||
{
|
{
|
||||||
this->mSupports.SwapElements(aSupports);
|
this->mSupports.SwapElements(aSupports);
|
||||||
DeferredFinalizeFunctionHolder* function =
|
DeferredFinalizeFunctionHolder* function =
|
||||||
@ -1143,39 +1146,46 @@ IncrementalFinalizeRunnable::~IncrementalFinalizeRunnable()
|
|||||||
void
|
void
|
||||||
IncrementalFinalizeRunnable::ReleaseNow(bool aLimited)
|
IncrementalFinalizeRunnable::ReleaseNow(bool aLimited)
|
||||||
{
|
{
|
||||||
//MOZ_ASSERT(NS_IsMainThread());
|
if (mReleasing) {
|
||||||
MOZ_ASSERT(mDeferredFinalizeFunctions.Length() != 0,
|
MOZ_ASSERT(false, "Try to avoid re-entering ReleaseNow!");
|
||||||
"We should have at least ReleaseSliceNow to run");
|
return;
|
||||||
MOZ_ASSERT(mFinalizeFunctionToRun < mDeferredFinalizeFunctions.Length(),
|
}
|
||||||
"No more finalizers to run?");
|
{
|
||||||
|
mozilla::AutoRestore<bool> ar(mReleasing);
|
||||||
|
mReleasing = true;
|
||||||
|
MOZ_ASSERT(mDeferredFinalizeFunctions.Length() != 0,
|
||||||
|
"We should have at least ReleaseSliceNow to run");
|
||||||
|
MOZ_ASSERT(mFinalizeFunctionToRun < mDeferredFinalizeFunctions.Length(),
|
||||||
|
"No more finalizers to run?");
|
||||||
|
|
||||||
TimeDuration sliceTime = TimeDuration::FromMilliseconds(SliceMillis);
|
TimeDuration sliceTime = TimeDuration::FromMilliseconds(SliceMillis);
|
||||||
TimeStamp started = TimeStamp::Now();
|
TimeStamp started = TimeStamp::Now();
|
||||||
bool timeout = false;
|
bool timeout = false;
|
||||||
do {
|
do {
|
||||||
const DeferredFinalizeFunctionHolder& function =
|
const DeferredFinalizeFunctionHolder& function =
|
||||||
mDeferredFinalizeFunctions[mFinalizeFunctionToRun];
|
mDeferredFinalizeFunctions[mFinalizeFunctionToRun];
|
||||||
if (aLimited) {
|
if (aLimited) {
|
||||||
bool done = false;
|
bool done = false;
|
||||||
while (!timeout && !done) {
|
while (!timeout && !done) {
|
||||||
/*
|
/*
|
||||||
* We don't want to read the clock too often, so we try to
|
* We don't want to read the clock too often, so we try to
|
||||||
* release slices of 100 items.
|
* release slices of 100 items.
|
||||||
*/
|
*/
|
||||||
done = function.run(100, function.data);
|
done = function.run(100, function.data);
|
||||||
timeout = TimeStamp::Now() - started >= sliceTime;
|
timeout = TimeStamp::Now() - started >= sliceTime;
|
||||||
}
|
}
|
||||||
if (done) {
|
if (done) {
|
||||||
|
++mFinalizeFunctionToRun;
|
||||||
|
}
|
||||||
|
if (timeout) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
function.run(UINT32_MAX, function.data);
|
||||||
++mFinalizeFunctionToRun;
|
++mFinalizeFunctionToRun;
|
||||||
}
|
}
|
||||||
if (timeout) {
|
} while (mFinalizeFunctionToRun < mDeferredFinalizeFunctions.Length());
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
} else {
|
|
||||||
function.run(UINT32_MAX, function.data);
|
|
||||||
++mFinalizeFunctionToRun;
|
|
||||||
}
|
|
||||||
} while (mFinalizeFunctionToRun < mDeferredFinalizeFunctions.Length());
|
|
||||||
|
|
||||||
if (mFinalizeFunctionToRun == mDeferredFinalizeFunctions.Length()) {
|
if (mFinalizeFunctionToRun == mDeferredFinalizeFunctions.Length()) {
|
||||||
MOZ_ASSERT(mRuntime->mFinalizeRunnable == this);
|
MOZ_ASSERT(mRuntime->mFinalizeRunnable == this);
|
||||||
@ -1210,7 +1220,21 @@ IncrementalFinalizeRunnable::Run()
|
|||||||
void
|
void
|
||||||
CycleCollectedJSRuntime::FinalizeDeferredThings(DeferredFinalizeType aType)
|
CycleCollectedJSRuntime::FinalizeDeferredThings(DeferredFinalizeType aType)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!mFinalizeRunnable);
|
/*
|
||||||
|
* If the previous GC created a runnable to finalize objects
|
||||||
|
* incrementally, and if it hasn't finished yet, finish it now. We
|
||||||
|
* don't want these to build up. We also don't want to allow any
|
||||||
|
* existing incremental finalize runnables to run after a
|
||||||
|
* non-incremental GC, since they are often used to detect leaks.
|
||||||
|
*/
|
||||||
|
if (mFinalizeRunnable) {
|
||||||
|
mFinalizeRunnable->ReleaseNow(false);
|
||||||
|
if (mFinalizeRunnable) {
|
||||||
|
// If we re-entered ReleaseNow, we couldn't delete mFinalizeRunnable and
|
||||||
|
// we need to just continue processing it.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
mFinalizeRunnable = new IncrementalFinalizeRunnable(this,
|
mFinalizeRunnable = new IncrementalFinalizeRunnable(this,
|
||||||
mDeferredSupports,
|
mDeferredSupports,
|
||||||
mDeferredFinalizerTable);
|
mDeferredFinalizerTable);
|
||||||
@ -1261,17 +1285,6 @@ CycleCollectedJSRuntime::OnGC(JSGCStatus aStatus)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* If the previous GC created a runnable to finalize objects
|
|
||||||
* incrementally, and if it hasn't finished yet, finish it now. We
|
|
||||||
* don't want these to build up. We also don't want to allow any
|
|
||||||
* existing incremental finalize runnables to run after a
|
|
||||||
* non-incremental GC, since they are often used to detect leaks.
|
|
||||||
*/
|
|
||||||
if (mFinalizeRunnable) {
|
|
||||||
mFinalizeRunnable->ReleaseNow(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do any deferred finalization of native objects.
|
// Do any deferred finalization of native objects.
|
||||||
FinalizeDeferredThings(JS::WasIncrementalGC(mJSRuntime) ? FinalizeIncrementally :
|
FinalizeDeferredThings(JS::WasIncrementalGC(mJSRuntime) ? FinalizeIncrementally :
|
||||||
FinalizeNow);
|
FinalizeNow);
|
||||||
|
Loading…
Reference in New Issue
Block a user