Bug 650161 - Add an assertion that something is only ever called from a GC callback r=terrence

This commit is contained in:
Jon Coppeard 2014-09-19 09:57:11 +01:00
Родитель 98811767d8
Коммит 1ae2e41b28
4 изменённых файлов: 72 добавлений и 38 удалений

Просмотреть файл

@ -393,10 +393,32 @@ class JS_PUBLIC_API(AutoAssertOnGC)
};
/*
* Disable the static rooting hazard analysis in the live region, but assert if
* any GC occurs while this guard object is live. This is most useful to help
* the exact rooting hazard analysis in complex regions, since it cannot
* understand dataflow.
* Assert if an allocation of a GC thing occurs while this class is live. This
* class does not disable the static rooting hazard analysis.
*/
class JS_PUBLIC_API(AutoAssertNoAlloc)
{
#ifdef JS_DEBUG
js::gc::GCRuntime *gc;
public:
AutoAssertNoAlloc() : gc(nullptr) {}
explicit AutoAssertNoAlloc(JSRuntime *rt);
void disallowAlloc(JSRuntime *rt);
~AutoAssertNoAlloc();
#else
public:
AutoAssertNoAlloc() {}
explicit AutoAssertNoAlloc(JSRuntime *rt) {}
void disallowAlloc(JSRuntime *rt) {}
#endif
};
/*
* Disable the static rooting hazard analysis in the live region and assert if
* any allocation that could potentially trigger a GC occurs while this guard
* object is live. This is most useful to help the exact rooting hazard analysis
* in complex regions, since it cannot understand dataflow.
*
* Note: GC behavior is unpredictable even when deterministice and is generally
* non-deterministic in practice. The fact that this guard has not
@ -406,11 +428,25 @@ class JS_PUBLIC_API(AutoAssertOnGC)
* that the hazard analysis is correct for that code, rather than relying
* on this class.
*/
class JS_PUBLIC_API(AutoSuppressGCAnalysis) : public AutoAssertOnGC
class JS_PUBLIC_API(AutoSuppressGCAnalysis) : public AutoAssertNoAlloc
{
public:
AutoSuppressGCAnalysis() : AutoAssertOnGC() {}
explicit AutoSuppressGCAnalysis(JSRuntime *rt) : AutoAssertOnGC(rt) {}
AutoSuppressGCAnalysis() : AutoAssertNoAlloc() {}
explicit AutoSuppressGCAnalysis(JSRuntime *rt) : AutoAssertNoAlloc(rt) {}
};
/*
* Assert that code is only ever called from a GC callback, disable the static
* rooting hazard analysis and assert if any allocation that could potentially
* trigger a GC occurs while this guard object is live.
*
* This is useful to make the static analysis ignore code that runs in GC
* callbacks.
*/
class JS_PUBLIC_API(AutoAssertGCCallback) : public AutoSuppressGCAnalysis
{
public:
explicit AutoAssertGCCallback(JSObject *obj);
};
/*

Просмотреть файл

@ -222,6 +222,7 @@ function isRootedPointerTypeName(name)
function isSuppressConstructor(name)
{
return name.indexOf("::AutoSuppressGC") != -1
|| name.indexOf("::AutoAssertGCCallback") != -1
|| name.indexOf("::AutoEnterAnalysis") != -1
|| name.indexOf("::AutoSuppressGCAnalysis") != -1
|| name.indexOf("::AutoIgnoreRootingHazards") != -1;

Просмотреть файл

@ -5642,12 +5642,12 @@ GCRuntime::collect(bool incremental, int64_t budget, JSGCInvocationKind gckind,
JS::gcreason::Reason reason)
{
/* GC shouldn't be running in parallel execution mode */
MOZ_ASSERT(!InParallelSection());
MOZ_ALWAYS_TRUE(!InParallelSection());
JS_AbortIfWrongThread(rt);
/* If we attempt to invoke the GC while we are running in the GC, assert. */
MOZ_ASSERT(!rt->isHeapBusy());
MOZ_ALWAYS_TRUE(!rt->isHeapBusy());
/* The engine never locks across anything that could GC. */
MOZ_ASSERT(!rt->currentThreadHasExclusiveAccess());
@ -6359,8 +6359,33 @@ JS::AutoAssertOnGC::VerifyIsSafeToGC(JSRuntime *rt)
if (rt->gc.isInsideUnsafeRegion())
MOZ_CRASH("[AutoAssertOnGC] possible GC in GC-unsafe region");
}
JS::AutoAssertNoAlloc::AutoAssertNoAlloc(JSRuntime *rt)
: gc(nullptr)
{
disallowAlloc(rt);
}
void JS::AutoAssertNoAlloc::disallowAlloc(JSRuntime *rt)
{
JS_ASSERT(!gc);
gc = &rt->gc;
gc->disallowAlloc();
}
JS::AutoAssertNoAlloc::~AutoAssertNoAlloc()
{
if (gc)
gc->allowAlloc();
}
#endif
JS::AutoAssertGCCallback::AutoAssertGCCallback(JSObject *obj)
: AutoSuppressGCAnalysis()
{
MOZ_ASSERT(obj->runtimeFromMainThread()->isHeapMajorCollecting());
}
#ifdef JSGC_HASH_TABLE_CHECKS
void
js::gc::CheckHashTablesAfterMovingGC(JSRuntime *rt)

Просмотреть файл

@ -325,37 +325,9 @@ class ZoneCellIterUnderGC : public ZoneCellIterImpl
}
};
/* In debug builds, assert that no allocation occurs. */
class AutoAssertNoAlloc
{
#ifdef JS_DEBUG
GCRuntime *gc;
public:
AutoAssertNoAlloc() : gc(nullptr) {}
explicit AutoAssertNoAlloc(JSRuntime *rt) : gc(nullptr) {
disallowAlloc(rt);
}
void disallowAlloc(JSRuntime *rt) {
JS_ASSERT(!gc);
gc = &rt->gc;
gc->disallowAlloc();
}
~AutoAssertNoAlloc() {
if (gc)
gc->allowAlloc();
}
#else
public:
AutoAssertNoAlloc() {}
explicit AutoAssertNoAlloc(JSRuntime *) {}
void disallowAlloc(JSRuntime *rt) {}
#endif
};
class ZoneCellIter : public ZoneCellIterImpl
{
AutoAssertNoAlloc noAlloc;
JS::AutoAssertNoAlloc noAlloc;
ArenaLists *lists;
AllocKind kind;