зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1149526 - Rework HeapPtr lifetime checks using TLS r=terrence
This commit is contained in:
Родитель
9d590ffe5a
Коммит
0078e35637
|
@ -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.
|
||||
|
|
Загрузка…
Ссылка в новой задаче