Bug 1149526 - Rework HeapPtr lifetime checks using TLS r=terrence

This commit is contained in:
Jon Coppeard 2015-04-09 18:08:54 +01:00
Родитель 9d590ffe5a
Коммит 0078e35637
11 изменённых файлов: 76 добавлений и 161 удалений

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

@ -848,7 +848,7 @@ class AsmJSModule
uint8_t * interruptExit_;
uint8_t * outOfBoundsExit_;
StaticLinkData staticLinkData_;
HeapPtrArrayBufferObjectMaybeShared maybeHeap_;
RelocatablePtrArrayBufferObjectMaybeShared maybeHeap_;
AsmJSModule ** prevLinked_;
AsmJSModule * nextLinked_;
bool dynamicallyLinked_;

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

@ -67,53 +67,10 @@ CurrentThreadIsIonCompiling()
return TlsPerThreadData.get()->ionCompiling;
}
static bool
GCIsSweepingOnMainThread(JSRuntime* rt, Zone* zone)
bool
CurrentThreadIsGCSweeping()
{
return rt->isHeapMajorCollecting() && rt->gc.state() == SWEEP &&
(zone->isGCSweeping() || rt->isAtomsZone(zone));
}
static bool
GCIsSweepingOnBackgroundThread(JSRuntime* rt, Zone* zone)
{
return rt->gc.isBackgroundSweeping() &&
(zone->isGCBackgroundSweeping() || rt->isAtomsZone(zone));
}
static bool
ThingMayHaveDifferentRuntime(TenuredCell* cell)
{
// Some GC things may be associated with another runtime.
AllocKind kind = cell->getAllocKind();
if (kind == AllocKind::STRING)
return static_cast<const JSString*>(cell)->isPermanentAtom();
else if (kind == AllocKind::SYMBOL)
return static_cast<const JS::Symbol*>(cell)->isWellKnownSymbol();
return false;
}
void
CheckGCIsSweepingZone(gc::Cell* cell)
{
MOZ_ASSERT(!IsInsideNursery(cell));
TenuredCell* tenured = &cell->asTenured();
if (ThingMayHaveDifferentRuntime(tenured))
return;
Zone* zone = tenured->zoneFromAnyThread();
JSRuntime* rt = zone->runtimeFromAnyThread();
if (CurrentThreadCanAccessRuntime(rt)) {
// We're on the main thread.
MOZ_ASSERT(GCIsSweepingOnMainThread(rt, zone));
} else {
// We're not on the main thread, so we're either on a helper thread run
// while the GC is active on the main thread or we are background
// sweeping.
MOZ_ASSERT(GCIsSweepingOnMainThread(rt, zone) ||
GCIsSweepingOnBackgroundThread(rt, zone));
}
return js::TlsPerThreadData.get()->gcSweeping;
}
#endif // DEBUG

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

@ -192,6 +192,9 @@ class JitCode;
// a helper thread.
bool
CurrentThreadIsIonCompiling();
bool
CurrentThreadIsGCSweeping();
#endif
bool
@ -287,11 +290,6 @@ ZoneOfIdFromAnyThread(const jsid& id)
void
ValueReadBarrier(const Value& value);
#ifdef DEBUG
void
CheckGCIsSweepingZone(gc::Cell* cell);
#endif
template <typename T>
struct InternalGCMethods {};
@ -308,13 +306,6 @@ struct InternalGCMethods<T*>
static void postBarrierRemove(T** vp) { T::writeBarrierPostRemove(*vp, vp); }
static void readBarrier(T* v) { T::readBarrier(v); }
#ifdef DEBUG
static void checkGCIsSweeping(T* v) {
if (v)
CheckGCIsSweepingZone(v);
}
#endif
};
template <>
@ -392,13 +383,6 @@ struct InternalGCMethods<Value>
}
static void readBarrier(const Value& v) { ValueReadBarrier(v); }
#ifdef DEBUG
static void checkGCIsSweeping(const Value& v) {
if (v.isMarkable())
CheckGCIsSweepingZone(v.toGCThing());
}
#endif
};
template <>
@ -422,13 +406,6 @@ struct InternalGCMethods<jsid>
static void postBarrier(jsid* idp) {}
static void postBarrierRelocate(jsid* idp) {}
static void postBarrierRemove(jsid* idp) {}
#ifdef DEBUG
static void checkGCIsSweeping(jsid id) {
if (JSID_IS_GCTHING(id))
CheckGCIsSweepingZone(JSID_TO_GCTHING(id).asCell());
}
#endif
};
template <typename T>
@ -472,10 +449,6 @@ class BarrieredBase : public BarrieredBaseMixins<T>
protected:
void pre() { InternalGCMethods<T>::preBarrier(value); }
void pre(Zone* zone) { InternalGCMethods<T>::preBarrier(zone, value); }
#ifdef DEBUG
void checkGCIsSweeping() { InternalGCMethods<T>::checkGCIsSweeping(value); }
#endif
};
template <>
@ -542,7 +515,9 @@ class HeapPtr : public BarrieredBase<T>
explicit HeapPtr(T v) : BarrieredBase<T>(v) { post(); }
explicit HeapPtr(const HeapPtr<T>& v) : BarrieredBase<T>(v) { post(); }
#ifdef DEBUG
~HeapPtr() { this->checkGCIsSweeping(); }
~HeapPtr() {
MOZ_ASSERT(CurrentThreadIsGCSweeping());
}
#endif
void init(T v) {
@ -555,13 +530,6 @@ class HeapPtr : public BarrieredBase<T>
protected:
void post() { InternalGCMethods<T>::postBarrier(&this->value); }
/* Make this friend so it can access pre() and post(). */
template <class T1, class T2>
friend inline void
BarrieredSetPair(Zone* zone,
HeapPtr<T1*>& v1, T1* val1,
HeapPtr<T2*>& v2, T2* val2);
private:
void set(const T& v) {
this->pre();
@ -684,26 +652,6 @@ class RelocatablePtr : public BarrieredBase<T>
}
};
/*
* This is a hack for RegExpStatics::updateFromMatch. It allows us to do two
* barriers with only one branch to check if we're in an incremental GC.
*/
template <class T1, class T2>
static inline void
BarrieredSetPair(Zone* zone,
HeapPtr<T1*>& v1, T1* val1,
HeapPtr<T2*>& v2, T2* val2)
{
if (T1::needWriteBarrierPre(zone)) {
v1.pre();
v2.pre();
}
v1.unsafeSet(val1);
v2.unsafeSet(val2);
v1.post();
v2.post();
}
/*
* This is a hack for RegExpStatics::updateFromMatch. It allows us to do two
* barriers with only one branch to check if we're in an incremental GC.
@ -841,6 +789,7 @@ typedef RelocatablePtr<jit::JitCode*> RelocatablePtrJitCode;
typedef RelocatablePtr<JSLinearString*> RelocatablePtrLinearString;
typedef RelocatablePtr<JSString*> RelocatablePtrString;
typedef RelocatablePtr<JSAtom*> RelocatablePtrAtom;
typedef RelocatablePtr<ArrayBufferObjectMaybeShared*> RelocatablePtrArrayBufferObjectMaybeShared;
typedef HeapPtr<NativeObject*> HeapPtrNativeObject;
typedef HeapPtr<ArrayObject*> HeapPtrArrayObject;

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

@ -172,6 +172,31 @@ class AutoMaybeStartBackgroundAllocation
}
};
// In debug builds, set/unset the GC sweeping flag for the current thread.
struct AutoSetThreadIsSweeping
{
#ifdef DEBUG
explicit AutoSetThreadIsSweeping(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
: threadData_(js::TlsPerThreadData.get())
{
MOZ_ASSERT(!threadData_->gcSweeping);
threadData_->gcSweeping = true;
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
~AutoSetThreadIsSweeping() {
MOZ_ASSERT(threadData_->gcSweeping);
threadData_->gcSweeping = false;
}
private:
PerThreadData* threadData_;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
#else
AutoSetThreadIsSweeping() {}
#endif
};
} /* namespace gc */
} /* namespace js */

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

@ -39,9 +39,6 @@ JS::Zone::Zone(JSRuntime* rt)
gcState_(NoGC),
gcScheduled_(false),
gcPreserveCode_(false),
#ifdef DEBUG
gcBackgroundSweeping_(false),
#endif
jitUsingBarriers_(false),
listNext_(NotOnList)
{
@ -273,15 +270,6 @@ Zone::notifyObservingDebuggers()
}
}
#ifdef DEBUG
void
Zone::setGCBackgroundSweeping(bool newState)
{
MOZ_ASSERT(gcBackgroundSweeping_ != newState);
gcBackgroundSweeping_ = newState;
}
#endif
JS::Zone*
js::ZoneOfValue(const JS::Value& value)
{

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

@ -226,9 +226,6 @@ struct Zone : public JS::shadow::Zone,
// For testing purposes, return the index of the zone group which this zone
// was swept in in the last GC.
unsigned lastZoneGroupIndex() { return gcLastZoneGroupIndex; }
void setGCBackgroundSweeping(bool newState);
bool isGCBackgroundSweeping() { return gcBackgroundSweeping_; }
#endif
private:
@ -303,9 +300,6 @@ struct Zone : public JS::shadow::Zone,
GCState gcState_;
bool gcScheduled_;
bool gcPreserveCode_;
#ifdef DEBUG
bool gcBackgroundSweeping_;
#endif
bool jitUsingBarriers_;
// Allow zones to be linked into a list

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

@ -3208,27 +3208,6 @@ GCRuntime::expireChunksAndArenas(bool shouldShrink, AutoLockGC& lock)
decommitArenas(lock);
}
// In debug builds, set/unset the background sweeping flag on the zone.
struct AutoSetZoneBackgroundSweeping
{
#ifdef DEBUG
explicit AutoSetZoneBackgroundSweeping(Zone* zone)
: zone_(zone)
{
zone_->setGCBackgroundSweeping(true);
}
~AutoSetZoneBackgroundSweeping() {
zone_->setGCBackgroundSweeping(false);
}
private:
Zone* zone_;
#else
AutoSetZoneBackgroundSweeping(Zone* zone) {}
#endif
};
void
GCRuntime::sweepBackgroundThings(ZoneList& zones, LifoAlloc& freeBlocks, ThreadType threadType)
{
@ -3242,7 +3221,6 @@ GCRuntime::sweepBackgroundThings(ZoneList& zones, LifoAlloc& freeBlocks, ThreadT
FreeOp fop(rt, threadType);
for (unsigned phase = 0 ; phase < ArrayLength(BackgroundFinalizePhases) ; ++phase) {
for (Zone* zone = zones.front(); zone; zone = zone->nextZone()) {
AutoSetZoneBackgroundSweeping zbs(zone);
for (unsigned index = 0 ; index < BackgroundFinalizePhases[phase].length ; ++index) {
AllocKind kind = BackgroundFinalizePhases[phase].kinds[index];
ArenaHeader* arenas = zone->arenas.arenaListsToSweep[kind];
@ -3482,6 +3460,8 @@ GCHelperState::doSweep(AutoLockGC& lock)
do {
while (!rt->gc.backgroundSweepZones.isEmpty()) {
AutoSetThreadIsSweeping threadIsSweeping;
ZoneList zones;
zones.transferFrom(rt->gc.backgroundSweepZones);
LifoAlloc freeLifoAlloc(JSRuntime::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
@ -4720,21 +4700,33 @@ GCRuntime::endMarkingZoneGroup()
marker.setMarkColorBlack();
}
#define MAKE_GC_PARALLEL_TASK(name) \
class name : public GCParallelTask {\
JSRuntime* runtime;\
virtual void run() override;\
public:\
explicit name (JSRuntime* rt) : runtime(rt) {}\
class GCSweepTask : public GCParallelTask
{
virtual void runFromHelperThread() override {
AutoSetThreadIsSweeping threadIsSweeping;
GCParallelTask::runFromHelperThread();
}
MAKE_GC_PARALLEL_TASK(SweepAtomsTask);
MAKE_GC_PARALLEL_TASK(SweepInnerViewsTask);
MAKE_GC_PARALLEL_TASK(SweepCCWrappersTask);
MAKE_GC_PARALLEL_TASK(SweepBaseShapesTask);
MAKE_GC_PARALLEL_TASK(SweepInitialShapesTask);
MAKE_GC_PARALLEL_TASK(SweepObjectGroupsTask);
MAKE_GC_PARALLEL_TASK(SweepRegExpsTask);
MAKE_GC_PARALLEL_TASK(SweepMiscTask);
protected:
JSRuntime* runtime;
public:
explicit GCSweepTask(JSRuntime* rt) : runtime(rt) {}
};
#define MAKE_GC_SWEEP_TASK(name) \
class name : public GCSweepTask { \
virtual void run() override; \
public: \
explicit name (JSRuntime* rt) : GCSweepTask(rt) {} \
}
MAKE_GC_SWEEP_TASK(SweepAtomsTask);
MAKE_GC_SWEEP_TASK(SweepInnerViewsTask);
MAKE_GC_SWEEP_TASK(SweepCCWrappersTask);
MAKE_GC_SWEEP_TASK(SweepBaseShapesTask);
MAKE_GC_SWEEP_TASK(SweepInitialShapesTask);
MAKE_GC_SWEEP_TASK(SweepObjectGroupsTask);
MAKE_GC_SWEEP_TASK(SweepRegExpsTask);
MAKE_GC_SWEEP_TASK(SweepMiscTask);
#undef MAKE_GC_SWEEP_TASK
/* virtual */ void
SweepAtomsTask::run()
@ -5028,6 +5020,8 @@ GCRuntime::beginSweepPhase(bool destroyingRuntime)
MOZ_ASSERT(!abortSweepAfterCurrentGroup);
AutoSetThreadIsSweeping threadIsSweeping;
releaseHeldRelocatedArenas();
computeNonIncrementalMarkingForValidation();
@ -5130,6 +5124,8 @@ SweepArenaList(ArenaHeader** arenasToSweep, SliceBudget& sliceBudget, Args... ar
GCRuntime::IncrementalProgress
GCRuntime::sweepPhase(SliceBudget& sliceBudget)
{
AutoSetThreadIsSweeping threadIsSweeping;
gcstats::AutoPhase ap(stats, gcstats::PHASE_SWEEP);
FreeOp fop(rt);
@ -5235,6 +5231,8 @@ GCRuntime::sweepPhase(SliceBudget& sliceBudget)
void
GCRuntime::endSweepPhase(bool destroyingRuntime)
{
AutoSetThreadIsSweeping threadIsSweeping;
gcstats::AutoPhase ap(stats, gcstats::PHASE_SWEEP);
FreeOp fop(rt);

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

@ -1026,7 +1026,7 @@ class GCParallelTask
// This should be friended to HelperThread, but cannot be because it
// would introduce several circular dependencies.
public:
void runFromHelperThread();
virtual void runFromHelperThread();
};
struct GCChunkHasher {

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

@ -92,7 +92,7 @@ class WeakMapBase {
virtual void finish() = 0;
// Object that this weak map is part of, if any.
HeapPtrObject memberOf;
RelocatablePtrObject memberOf;
// Compartment that this weak map is part of.
JSCompartment* compartment;

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

@ -81,6 +81,7 @@ PerThreadData::PerThreadData(JSRuntime* runtime)
suppressGC(0),
#ifdef DEBUG
ionCompiling(false),
gcSweeping(false),
#endif
activeCompilations(0)
{}

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

@ -520,6 +520,9 @@ class PerThreadData : public PerThreadDataFriendFields
#ifdef DEBUG
// Whether this thread is actively Ion compiling.
bool ionCompiling;
// Whether this thread is currently sweeping GC things.
bool gcSweeping;
#endif
// Number of active bytecode compilation on this thread.