Bug 988486 - Make more GCRuntime members private and add necessary accessors r=terrence

This commit is contained in:
Jon Coppeard 2014-06-07 10:34:57 +01:00
parent 62086f2135
commit 0d943dd656
16 changed files with 283 additions and 205 deletions

View File

@ -375,7 +375,7 @@ ShrinkGCBuffers(JSRuntime *rt);
class JS_PUBLIC_API(AutoAssertOnGC)
{
#ifdef DEBUG
JSRuntime *runtime;
js::gc::GCRuntime *gc;
size_t gcNumber;
public:

View File

@ -520,7 +520,7 @@ SelectForGC(JSContext *cx, unsigned argc, Value *vp)
for (unsigned i = 0; i < args.length(); i++) {
if (args[i].isObject()) {
if (!rt->gc.selectedForMarking.append(&args[i].toObject()))
if (!rt->gc.selectForMarking(&args[i].toObject()))
return false;
}
}
@ -599,7 +599,7 @@ DeterministicGC(JSContext *cx, unsigned argc, jsval *vp)
return false;
}
gc::SetDeterministicGC(cx, ToBoolean(args[0]));
cx->runtime()->gc.setDeterministic(ToBoolean(args[0]));
args.rval().setUndefined();
return true;
}
@ -641,7 +641,7 @@ ValidateGC(JSContext *cx, unsigned argc, jsval *vp)
return false;
}
gc::SetValidateGC(cx, ToBoolean(args[0]));
cx->runtime()->gc.setValidate(ToBoolean(args[0]));
args.rval().setUndefined();
return true;
}
@ -657,7 +657,7 @@ FullCompartmentChecks(JSContext *cx, unsigned argc, jsval *vp)
return false;
}
gc::SetFullCompartmentChecks(cx, ToBoolean(args[0]));
cx->runtime()->gc.setFullCompartmentChecks(ToBoolean(args[0]));
args.rval().setUndefined();
return true;
}

View File

@ -96,7 +96,10 @@ class GCRuntime
bool init(uint32_t maxbytes);
void finish();
void setGCZeal(uint8_t zeal, uint32_t frequency);
inline int zeal();
inline bool upcomingZealousGC();
inline bool needZealousGC();
template <typename T> bool addRoot(T *rp, const char *name, JSGCRootType rootType);
void removeRoot(void *rp);
void setMarkStackLimit(size_t limit);
@ -116,14 +119,21 @@ class GCRuntime
JS::gcreason::Reason reason);
void gcSlice(JSGCInvocationKind gckind, JS::gcreason::Reason reason, int64_t millis);
void runDebugGC();
inline void poke();
void markRuntime(JSTracer *trc, bool useSavedRoots = false);
#ifdef JS_GC_ZEAL
const void *addressOfZealMode() { return &zealMode; }
void setZeal(uint8_t zeal, uint32_t frequency);
void setNextScheduled(uint32_t count);
void verifyPreBarriers();
void verifyPostBarriers();
void maybeVerifyPreBarriers(bool always);
void maybeVerifyPostBarriers(bool always);
bool selectForMarking(JSObject *object);
void clearSelectedForMarking();
void setDeterministic(bool enable);
#endif
public:
@ -184,6 +194,13 @@ class GCRuntime
JS_ASSERT(!isAllocAllowed());
--noGCOrAllocationCheck;
}
bool isInsideUnsafeRegion() { return inUnsafeRegion != 0; }
void enterUnsafeRegion() { ++inUnsafeRegion; }
void leaveUnsafeRegion() {
JS_ASSERT(inUnsafeRegion > 0);
--inUnsafeRegion;
}
#endif
void setAlwaysPreserveCode() { alwaysPreserveCode = true; }
@ -192,6 +209,24 @@ class GCRuntime
void disableGenerationalGC();
void enableGenerationalGC();
void setGrayRootsTracer(JSTraceDataOp traceOp, void *data);
bool addBlackRootsTracer(JSTraceDataOp traceOp, void *data);
void removeBlackRootsTracer(JSTraceDataOp traceOp, void *data);
void setMaxMallocBytes(size_t value);
void resetMallocBytes();
bool isTooMuchMalloc() const { return mallocBytes <= 0; }
void updateMallocCounter(JS::Zone *zone, size_t nbytes);
void onTooMuchMalloc();
void setGCCallback(JSGCCallback callback, void *data);
bool addFinalizeCallback(JSFinalizeCallback callback, void *data);
void removeFinalizeCallback(JSFinalizeCallback func);
JS::GCSliceCallback setSliceCallback(JS::GCSliceCallback callback);
void setValidate(bool enable);
void setFullCompartmentChecks(bool enable);
#ifdef JS_GC_ZEAL
void startVerifyPreBarriers();
bool endVerifyPreBarriers();
@ -207,7 +242,7 @@ class GCRuntime
inline bool wantBackgroundAllocation() const;
bool initGCZeal();
bool initZeal();
void requestInterrupt(JS::gcreason::Reason reason);
bool gcCycle(bool incremental, int64_t budget, JSGCInvocationKind gckind,
JS::gcreason::Reason reason);
@ -440,7 +475,7 @@ class GCRuntime
*/
unsigned objectsMarkedInDeadZones;
bool poke;
bool poked;
volatile js::HeapState heapState;
@ -449,6 +484,7 @@ class GCRuntime
js::gc::StoreBuffer storeBuffer;
#endif
private:
/*
* These options control the zealousness of the GC. The fundamental values
* are nextScheduled and gcDebugCompartmentGC. At every allocation,
@ -486,10 +522,7 @@ class GCRuntime
bool validate;
bool fullCompartmentChecks;
JSGCCallback gcCallback;
void *gcCallbackData;
JS::GCSliceCallback sliceCallback;
Callback<JSGCCallback> gcCallback;
CallbackVector<JSFinalizeCallback> finalizeCallbacks;
/*
@ -499,7 +532,7 @@ class GCRuntime
mozilla::Atomic<ptrdiff_t, mozilla::ReleaseAcquire> mallocBytes;
/*
* Whether a GC has been triggered as a result of mallocBytes falling
* Whether a GC has been triggered as a result of mallocBytes falling
* below zero.
*/
mozilla::Atomic<bool, mozilla::ReleaseAcquire> mallocGCTriggered;
@ -513,15 +546,6 @@ class GCRuntime
CallbackVector<JSTraceDataOp> blackRootTracers;
Callback<JSTraceDataOp> grayRootTracer;
/*
* The GC can only safely decommit memory when the page size of the
* running process matches the compiled arena size.
*/
size_t systemPageSize;
/* The OS allocation granularity may not match the page size. */
size_t systemAllocGranularity;
#ifdef DEBUG
/*
* Some regions of code are hard for the static rooting hazard analysis to
@ -532,7 +556,6 @@ class GCRuntime
int inUnsafeRegion;
#endif
private:
/* Always preserve JIT code during GCs, for testing. */
bool alwaysPreserveCode;
@ -548,11 +571,42 @@ class GCRuntime
ConservativeGCData conservativeGC;
//friend class js::gc::Chunk; // todo: remove
friend class js::GCHelperState;
friend class js::gc::MarkingValidator;
};
#ifdef JS_GC_ZEAL
inline int
GCRuntime::zeal() {
return zealMode;
}
inline bool
GCRuntime::upcomingZealousGC() {
return nextScheduled == 1;
}
inline bool
GCRuntime::needZealousGC() {
if (nextScheduled > 0 && --nextScheduled == 0) {
if (zealMode == ZealAllocValue ||
zealMode == ZealGenerationalGCValue ||
(zealMode >= ZealIncrementalRootsThenFinish &&
zealMode <= ZealIncrementalMultipleSlices))
{
nextScheduled = zealFrequency;
}
return true;
}
return false;
}
#else
inline int GCRuntime::zeal() { return 0; }
inline bool GCRuntime::upcomingZealousGC() { return false; }
inline bool GCRuntime::needZealousGC() { return false; }
#endif
} /* namespace gc */
} /* namespace js */

View File

@ -107,7 +107,7 @@ js::Nursery::enable()
setCurrentChunk(0);
currentStart_ = position();
#ifdef JS_GC_ZEAL
if (runtime()->gc.zealMode == ZealGenerationalGCValue)
if (runtime()->gcZeal() == ZealGenerationalGCValue)
enterZealMode();
#endif
}
@ -129,7 +129,7 @@ js::Nursery::isEmpty() const
JS_ASSERT(runtime_);
if (!isEnabled())
return true;
JS_ASSERT_IF(runtime_->gc.zealMode != ZealGenerationalGCValue, currentStart_ == start());
JS_ASSERT_IF(runtime_->gcZeal() != ZealGenerationalGCValue, currentStart_ == start());
return position() == currentStart_;
}
@ -930,7 +930,7 @@ js::Nursery::sweep()
for (int i = 0; i < NumNurseryChunks; ++i)
initChunk(i);
if (runtime()->gc.zealMode == ZealGenerationalGCValue) {
if (runtime()->gcZeal() == ZealGenerationalGCValue) {
MOZ_ASSERT(numActiveChunks_ == NumNurseryChunks);
/* Only reset the alloc point when we are close to the end. */
@ -955,7 +955,7 @@ void
js::Nursery::growAllocableSpace()
{
#ifdef JS_GC_ZEAL
MOZ_ASSERT_IF(runtime()->gc.zealMode == ZealGenerationalGCValue,
MOZ_ASSERT_IF(runtime()->gcZeal() == ZealGenerationalGCValue,
numActiveChunks_ == NumNurseryChunks);
#endif
numActiveChunks_ = Min(numActiveChunks_ * 2, NumNurseryChunks);
@ -965,7 +965,7 @@ void
js::Nursery::shrinkAllocableSpace()
{
#ifdef JS_GC_ZEAL
if (runtime()->gc.zealMode == ZealGenerationalGCValue)
if (runtime()->gcZeal() == ZealGenerationalGCValue)
return;
#endif
numActiveChunks_ = Max(numActiveChunks_ - 1, 1);

View File

@ -446,7 +446,8 @@ Statistics::Statistics(JSRuntime *rt)
compartmentCount(0),
nonincrementalReason(nullptr),
preBytes(0),
phaseNestingDepth(0)
phaseNestingDepth(0),
sliceCallback(nullptr)
{
PodArrayZero(phaseTotals);
PodArrayZero(counts);
@ -489,6 +490,13 @@ Statistics::~Statistics()
}
}
JS::GCSliceCallback
Statistics::setSliceCallback(JS::GCSliceCallback newCallback) {
JS::GCSliceCallback oldCallback = sliceCallback;
sliceCallback = newCallback;
return oldCallback;
}
void
Statistics::printStats()
{
@ -581,9 +589,9 @@ Statistics::beginSlice(int collectedCount, int zoneCount, int compartmentCount,
// Slice callbacks should only fire for the outermost level
if (++gcDepth == 1) {
bool wasFullGC = collectedCount == zoneCount;
if (JS::GCSliceCallback cb = runtime->gc.sliceCallback)
(*cb)(runtime, first ? JS::GC_CYCLE_BEGIN : JS::GC_SLICE_BEGIN,
JS::GCDescription(!wasFullGC));
if (sliceCallback)
(*sliceCallback)(runtime, first ? JS::GC_CYCLE_BEGIN : JS::GC_SLICE_BEGIN,
JS::GCDescription(!wasFullGC));
}
}
@ -605,9 +613,9 @@ Statistics::endSlice()
// Slice callbacks should only fire for the outermost level
if (--gcDepth == 0) {
bool wasFullGC = collectedCount == zoneCount;
if (JS::GCSliceCallback cb = runtime->gc.sliceCallback)
(*cb)(runtime, last ? JS::GC_CYCLE_END : JS::GC_SLICE_END,
JS::GCDescription(!wasFullGC));
if (sliceCallback)
(*sliceCallback)(runtime, last ? JS::GC_CYCLE_END : JS::GC_SLICE_END,
JS::GCDescription(!wasFullGC));
}
/* Do this after the slice callback since it uses these values. */

View File

@ -98,6 +98,8 @@ struct Statistics {
jschar *formatMessage();
jschar *formatJSON(uint64_t timestamp);
JS::GCSliceCallback setSliceCallback(JS::GCSliceCallback callback);
private:
JSRuntime *runtime;
@ -160,6 +162,8 @@ struct Statistics {
/* Sweep times for SCCs of compartments. */
Vector<int64_t, 0, SystemAllocPolicy> sccTimes;
JS::GCSliceCallback sliceCallback;
void beginGC();
void endGC();

View File

@ -68,7 +68,7 @@ CompileRuntime::addressOfLastCachedNativeIterator()
const void *
CompileRuntime::addressOfGCZeal()
{
return &runtime()->gc.zealMode;
return runtime()->gc.addressOfZealMode();
}
#endif

View File

@ -1615,20 +1615,13 @@ JS::RemoveScriptRootRT(JSRuntime *rt, JS::Heap<JSScript *> *rp)
JS_PUBLIC_API(bool)
JS_AddExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
{
AssertHeapIsIdle(rt);
return !!rt->gc.blackRootTracers.append(Callback<JSTraceDataOp>(traceOp, data));
return rt->gc.addBlackRootsTracer(traceOp, data);
}
JS_PUBLIC_API(void)
JS_RemoveExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
{
for (size_t i = 0; i < rt->gc.blackRootTracers.length(); i++) {
Callback<JSTraceDataOp> *e = &rt->gc.blackRootTracers[i];
if (e->op == traceOp && e->data == data) {
rt->gc.blackRootTracers.erase(e);
break;
}
}
return rt->gc.removeBlackRootsTracer(traceOp, data);
}
#ifdef DEBUG
@ -1899,28 +1892,20 @@ JS_PUBLIC_API(void)
JS_SetGCCallback(JSRuntime *rt, JSGCCallback cb, void *data)
{
AssertHeapIsIdle(rt);
rt->gc.gcCallback = cb;
rt->gc.gcCallbackData = data;
rt->gc.setGCCallback(cb, data);
}
JS_PUBLIC_API(bool)
JS_AddFinalizeCallback(JSRuntime *rt, JSFinalizeCallback cb, void *data)
{
AssertHeapIsIdle(rt);
return rt->gc.finalizeCallbacks.append(Callback<JSFinalizeCallback>(cb, data));
return rt->gc.addFinalizeCallback(cb, data);
}
JS_PUBLIC_API(void)
JS_RemoveFinalizeCallback(JSRuntime *rt, JSFinalizeCallback cb)
{
for (Callback<JSFinalizeCallback> *p = rt->gc.finalizeCallbacks.begin();
p < rt->gc.finalizeCallbacks.end(); p++)
{
if (p->op == cb) {
rt->gc.finalizeCallbacks.erase(p);
break;
}
}
rt->gc.removeFinalizeCallback(cb);
}
JS_PUBLIC_API(bool)
@ -1945,7 +1930,7 @@ JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32_t value)
break;
}
case JSGC_MAX_MALLOC_BYTES:
rt->setGCMaxMallocBytes(value);
rt->gc.setMaxMallocBytes(value);
break;
case JSGC_SLICE_TIME_BUDGET:
rt->gc.sliceBudget = SliceBudget::TimeBudget(value);
@ -6220,13 +6205,13 @@ JS_AbortIfWrongThread(JSRuntime *rt)
JS_PUBLIC_API(void)
JS_SetGCZeal(JSContext *cx, uint8_t zeal, uint32_t frequency)
{
SetGCZeal(cx->runtime(), zeal, frequency);
cx->runtime()->gc.setZeal(zeal, frequency);
}
JS_PUBLIC_API(void)
JS_ScheduleGC(JSContext *cx, uint32_t count)
{
cx->runtime()->gc.nextScheduled = count;
cx->runtime()->gc.setNextScheduled(count);
}
#endif

View File

@ -63,8 +63,7 @@ js::ForgetSourceHook(JSRuntime *rt)
JS_FRIEND_API(void)
JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
{
rt->gc.grayRootTracer.op = traceOp;
rt->gc.grayRootTracer.data = data;
rt->gc.setGrayRootsTracer(traceOp, data);
}
JS_FRIEND_API(JSString *)
@ -864,9 +863,7 @@ js::IsContextRunningJS(JSContext *cx)
JS_FRIEND_API(JS::GCSliceCallback)
JS::SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback)
{
JS::GCSliceCallback old = rt->gc.sliceCallback;
rt->gc.sliceCallback = callback;
return old;
return rt->gc.setSliceCallback(callback);
}
JS_FRIEND_API(bool)
@ -1026,7 +1023,7 @@ JS::IncrementalValueBarrier(const Value &v)
JS_FRIEND_API(void)
JS::PokeGC(JSRuntime *rt)
{
rt->gc.poke = true;
rt->gc.poke();
}
JS_FRIEND_API(JSCompartment *)

View File

@ -1095,7 +1095,7 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
generationalDisabled(0),
manipulatingDeadZones(false),
objectsMarkedInDeadZones(0),
poke(false),
poked(false),
heapState(Idle),
#ifdef JSGC_GENERATIONAL
nursery(rt),
@ -1110,8 +1110,6 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
#endif
validate(true),
fullCompartmentChecks(false),
gcCallback(nullptr),
sliceCallback(nullptr),
mallocBytes(0),
mallocGCTriggered(false),
#ifdef DEBUG
@ -1129,14 +1127,8 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
#ifdef JS_GC_ZEAL
extern void
js::SetGCZeal(JSRuntime *rt, uint8_t zeal, uint32_t frequency)
{
rt->gc.setGCZeal(zeal, frequency);
}
void
GCRuntime::setGCZeal(uint8_t zeal, uint32_t frequency)
GCRuntime::setZeal(uint8_t zeal, uint32_t frequency)
{
if (verifyPreData)
VerifyBarriers(rt, PreBarrierVerifier);
@ -1159,8 +1151,14 @@ GCRuntime::setGCZeal(uint8_t zeal, uint32_t frequency)
nextScheduled = schedule ? frequency : 0;
}
void
GCRuntime::setNextScheduled(uint32_t count)
{
nextScheduled = count;
}
bool
GCRuntime::initGCZeal()
GCRuntime::initZeal()
{
const char *env = getenv("JS_GC_ZEAL");
if (!env)
@ -1196,7 +1194,7 @@ GCRuntime::initGCZeal()
return false;
}
setGCZeal(zeal, frequency);
setZeal(zeal, frequency);
return true;
}
@ -1228,7 +1226,7 @@ GCRuntime::init(uint32_t maxbytes)
* for default backward API compatibility.
*/
maxBytes = maxbytes;
rt->setGCMaxMallocBytes(maxbytes);
setMaxMallocBytes(maxbytes);
#ifndef JS_MORE_DETERMINISTIC
jitReleaseTime = PRMJ_Now() + JIT_SCRIPT_RELEASE_TYPES_INTERVAL;
@ -1243,7 +1241,7 @@ GCRuntime::init(uint32_t maxbytes)
#endif
#ifdef JS_GC_ZEAL
if (!initGCZeal())
if (!initZeal())
return false;
#endif
@ -1328,6 +1326,63 @@ template <typename T> struct BarrierOwner {};
template <typename T> struct BarrierOwner<T *> { typedef T result; };
template <> struct BarrierOwner<Value> { typedef HeapValue result; };
bool
GCRuntime::addBlackRootsTracer(JSTraceDataOp traceOp, void *data)
{
AssertHeapIsIdle(rt);
return !!blackRootTracers.append(Callback<JSTraceDataOp>(traceOp, data));
}
void
GCRuntime::removeBlackRootsTracer(JSTraceDataOp traceOp, void *data)
{
// Can be called from finalizers
for (size_t i = 0; i < blackRootTracers.length(); i++) {
Callback<JSTraceDataOp> *e = &blackRootTracers[i];
if (e->op == traceOp && e->data == data) {
blackRootTracers.erase(e);
}
}
}
void
GCRuntime::setGrayRootsTracer(JSTraceDataOp traceOp, void *data)
{
AssertHeapIsIdle(rt);
grayRootTracer.op = traceOp;
grayRootTracer.data = data;
}
void
GCRuntime::setGCCallback(JSGCCallback callback, void *data)
{
gcCallback.op = callback;
gcCallback.data = data;
}
bool
GCRuntime::addFinalizeCallback(JSFinalizeCallback callback, void *data)
{
return finalizeCallbacks.append(Callback<JSFinalizeCallback>(callback, data));
}
void
GCRuntime::removeFinalizeCallback(JSFinalizeCallback callback)
{
for (Callback<JSFinalizeCallback> *p = finalizeCallbacks.begin();
p < finalizeCallbacks.end(); p++) {
if (p->op == callback) {
finalizeCallbacks.erase(p);
break;
}
}
}
JS::GCSliceCallback
GCRuntime::setSliceCallback(JS::GCSliceCallback callback) {
return stats.setSliceCallback(callback);
}
template <typename T>
bool
GCRuntime::addRoot(T *rp, const char *name, JSGCRootType rootType)
@ -1348,7 +1403,7 @@ void
GCRuntime::removeRoot(void *rp)
{
rootsHash.remove(rp);
poke = true;
poke();
}
template <typename T>
@ -1422,9 +1477,42 @@ js::RemoveRoot(JSRuntime *rt, void *rp)
rt->gc.removeRoot(rp);
}
typedef RootedValueMap::Range RootRange;
typedef RootedValueMap::Entry RootEntry;
typedef RootedValueMap::Enum RootEnum;
void
GCRuntime::setMaxMallocBytes(size_t value)
{
/*
* For compatibility treat any value that exceeds PTRDIFF_T_MAX to
* mean that value.
*/
maxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1;
resetMallocBytes();
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
zone->setGCMaxMallocBytes(value);
}
void
GCRuntime::resetMallocBytes()
{
mallocBytes = ptrdiff_t(maxMallocBytes);
mallocGCTriggered = false;
}
void
GCRuntime::updateMallocCounter(JS::Zone *zone, size_t nbytes)
{
mallocBytes -= ptrdiff_t(nbytes);
if (MOZ_UNLIKELY(isTooMuchMalloc()))
onTooMuchMalloc();
else if (zone)
zone->updateMallocCounter(nbytes);
}
void
GCRuntime::onTooMuchMalloc()
{
if (!mallocGCTriggered)
mallocGCTriggered = triggerGC(JS::gcreason::TOO_MUCH_MALLOC);
}
static size_t
ComputeTriggerBytes(Zone *zone, size_t lastBytes, size_t maxBytes, JSGCInvocationKind gckind)
@ -4353,7 +4441,7 @@ AutoGCSession::~AutoGCSession()
#ifdef JS_GC_ZEAL
/* Keeping these around after a GC is dangerous. */
gc->selectedForMarking.clearAndFree();
gc->clearSelectedForMarking();
#endif
/* Clear gcMallocBytes for all compartments */
@ -4362,7 +4450,7 @@ AutoGCSession::~AutoGCSession()
zone->unscheduleGC();
}
gc->rt->resetGCMallocBytes();
gc->resetMallocBytes();
}
AutoCopyFreeListToArenas::AutoCopyFreeListToArenas(JSRuntime *rt, ZoneSelector selector)
@ -4695,7 +4783,7 @@ GCRuntime::budgetIncrementalGC(int64_t *budget)
return;
}
if (rt->isTooMuchMalloc()) {
if (isTooMuchMalloc()) {
*budget = SliceBudget::Unlimited;
stats.nonincremental("malloc bytes trigger");
}
@ -4894,21 +4982,21 @@ GCRuntime::collect(bool incremental, int64_t budget, JSGCInvocationKind gckind,
*/
if (incrementalState == NO_INCREMENTAL) {
gcstats::AutoPhase ap(stats, gcstats::PHASE_GC_BEGIN);
if (gcCallback)
gcCallback(rt, JSGC_BEGIN, gcCallbackData);
if (gcCallback.op)
gcCallback.op(rt, JSGC_BEGIN, gcCallback.data);
}
poke = false;
poked = false;
bool wasReset = gcCycle(incremental, budget, gckind, reason);
if (incrementalState == NO_INCREMENTAL) {
gcstats::AutoPhase ap(stats, gcstats::PHASE_GC_END);
if (gcCallback)
gcCallback(rt, JSGC_END, gcCallbackData);
if (gcCallback.op)
gcCallback.op(rt, JSGC_END, gcCallback.data);
}
/* Need to re-schedule all zones for GC. */
if (poke && shouldCleanUpEverything)
if (poked && shouldCleanUpEverything)
JS::PrepareForFullGC(rt);
/*
@ -4934,7 +5022,7 @@ GCRuntime::collect(bool incremental, int64_t budget, JSGCInvocationKind gckind,
* case) until we can be sure that no additional garbage is created
* (which typically happens if roots are dropped during finalizers).
*/
repeat = (poke && shouldCleanUpEverything) || wasReset || repeatForDeadZone;
repeat = (poked && shouldCleanUpEverything) || wasReset || repeatForDeadZone;
} while (repeat);
if (incrementalState == NO_INCREMENTAL) {
@ -5294,27 +5382,40 @@ GCRuntime::runDebugGC()
}
void
gc::SetDeterministicGC(JSContext *cx, bool enabled)
GCRuntime::setValidate(bool enabled)
{
JS_ASSERT(!isHeapMajorCollecting());
validate = enabled;
}
void
GCRuntime::setFullCompartmentChecks(bool enabled)
{
JS_ASSERT(!isHeapMajorCollecting());
fullCompartmentChecks = enabled;
}
#ifdef JS_GC_ZEAL
JSRuntime *rt = cx->runtime();
rt->gc.deterministicOnly = enabled;
bool
GCRuntime::selectForMarking(JSObject *object)
{
JS_ASSERT(!isHeapMajorCollecting());
return selectedForMarking.append(object);
}
void
GCRuntime::clearSelectedForMarking()
{
selectedForMarking.clearAndFree();
}
void
GCRuntime::setDeterministic(bool enabled)
{
JS_ASSERT(!isHeapMajorCollecting());
deterministicOnly = enabled;
}
#endif
}
void
gc::SetValidateGC(JSContext *cx, bool enabled)
{
JSRuntime *rt = cx->runtime();
rt->gc.validate = enabled;
}
void
gc::SetFullCompartmentChecks(JSContext *cx, bool enabled)
{
JSRuntime *rt = cx->runtime();
rt->gc.fullCompartmentChecks = enabled;
}
#ifdef DEBUG
@ -5501,13 +5602,11 @@ JS::AssertGCThingMustBeTenured(JSObject *obj)
JS_FRIEND_API(void)
js::gc::AssertGCThingHasType(js::gc::Cell *cell, JSGCTraceKind kind)
{
#ifdef DEBUG
JS_ASSERT(cell);
if (IsInsideNursery(cell))
JS_ASSERT(kind == JSTRACE_OBJECT);
else
JS_ASSERT(MapAllocToTraceKind(cell->tenuredGetAllocKind()) == kind);
#endif
}
JS_FRIEND_API(size_t)
@ -5522,7 +5621,7 @@ JS::GetGCNumber()
#ifdef DEBUG
JS::AutoAssertOnGC::AutoAssertOnGC()
: runtime(nullptr), gcNumber(0)
: gc(nullptr), gcNumber(0)
{
js::PerThreadData *data = js::TlsPerThreadData.get();
if (data) {
@ -5532,38 +5631,38 @@ JS::AutoAssertOnGC::AutoAssertOnGC()
* code that works from both threads, however. We also use this to
* annotate the off thread run loops.
*/
runtime = data->runtimeIfOnOwnerThread();
JSRuntime *runtime = data->runtimeIfOnOwnerThread();
if (runtime) {
gcNumber = runtime->gc.number;
++runtime->gc.inUnsafeRegion;
gc = &runtime->gc;
gcNumber = gc->number;
gc->enterUnsafeRegion();
}
}
}
JS::AutoAssertOnGC::AutoAssertOnGC(JSRuntime *rt)
: runtime(rt), gcNumber(rt->gc.number)
: gc(&rt->gc), gcNumber(rt->gc.number)
{
++rt->gc.inUnsafeRegion;
gc->enterUnsafeRegion();
}
JS::AutoAssertOnGC::~AutoAssertOnGC()
{
if (runtime) {
--runtime->gc.inUnsafeRegion;
MOZ_ASSERT(runtime->gc.inUnsafeRegion >= 0);
if (gc) {
gc->leaveUnsafeRegion();
/*
* The following backstop assertion should never fire: if we bumped the
* gcNumber, we should have asserted because inUnsafeRegion was true.
*/
MOZ_ASSERT(gcNumber == runtime->gc.number, "GC ran inside an AutoAssertOnGC scope.");
MOZ_ASSERT(gcNumber == gc->number, "GC ran inside an AutoAssertOnGC scope.");
}
}
/* static */ void
JS::AutoAssertOnGC::VerifyIsSafeToGC(JSRuntime *rt)
{
if (rt->gc.inUnsafeRegion > 0)
if (rt->gc.isInsideUnsafeRegion())
MOZ_CRASH("[AutoAssertOnGC] possible GC in GC-unsafe region");
}
#endif

View File

@ -900,11 +900,6 @@ MinorGC(JSRuntime *rt, JS::gcreason::Reason reason);
extern void
MinorGC(JSContext *cx, JS::gcreason::Reason reason);
#ifdef JS_GC_ZEAL
extern void
SetGCZeal(JSRuntime *rt, uint8_t zeal, uint32_t frequency);
#endif
/* Functions for managing cross compartment gray pointers. */
extern void
@ -1161,15 +1156,6 @@ GCIfNeeded(JSContext *cx);
void
RunDebugGC(JSContext *cx);
void
SetDeterministicGC(JSContext *cx, bool enabled);
void
SetValidateGC(JSContext *cx, bool enabled);
void
SetFullCompartmentChecks(JSContext *cx, bool enabled);
/* Wait for the background thread to finish sweeping if it is running. */
void
FinishBackgroundFinalize(JSRuntime *rt);

View File

@ -76,15 +76,15 @@ GetGCThingTraceKind(const void *thing)
return MapAllocToTraceKind(cell->tenuredGetAllocKind());
}
static inline void
GCPoke(JSRuntime *rt)
inline void
GCRuntime::poke()
{
rt->gc.poke = true;
poked = true;
#ifdef JS_GC_ZEAL
/* Schedule a GC to happen "soon" after a GC poke. */
if (rt->gcZeal() == js::gc::ZealPokeValue)
rt->gc.nextScheduled = 1;
if (zealMode == ZealPokeValue)
nextScheduled = 1;
#endif
}
@ -489,7 +489,7 @@ CheckAllocatorState(ThreadSafeContext *cx, AllocKind kind)
if (allowGC) {
#ifdef JS_GC_ZEAL
if (rt->needZealousGC())
if (rt->gc.needZealousGC())
js::gc::RunDebugGC(ncx);
#endif

View File

@ -5274,7 +5274,7 @@ baseops::DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, bool *succe
return CallJSDeletePropertyOp(cx, obj->getClass()->delProperty, obj, id, succeeded);
}
GCPoke(cx->runtime());
cx->runtime()->gc.poke();
if (IsImplicitDenseOrTypedArrayElement(shape)) {
if (obj->is<TypedArrayObject>()) {

View File

@ -56,7 +56,7 @@ NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entry_, js::gc::Initi
if (type->shouldPreTenure())
heap = gc::TenuredHeap;
if (cx->runtime()->upcomingZealousGC())
if (cx->runtime()->gc.upcomingZealousGC())
return nullptr;
// Trigger an identical allocation to the one that notified us of OOM

View File

@ -695,19 +695,6 @@ JSRuntime::triggerActivityCallback(bool active)
activityCallback(activityCallbackArg, active);
}
void
JSRuntime::setGCMaxMallocBytes(size_t value)
{
/*
* For compatibility treat any value that exceeds PTRDIFF_T_MAX to
* mean that value.
*/
gc.maxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1;
resetGCMallocBytes();
for (ZonesIter zone(this, WithAtoms); !zone.done(); zone.next())
zone->setGCMaxMallocBytes(value);
}
void
JSRuntime::updateMallocCounter(size_t nbytes)
{
@ -717,12 +704,7 @@ JSRuntime::updateMallocCounter(size_t nbytes)
void
JSRuntime::updateMallocCounter(JS::Zone *zone, size_t nbytes)
{
/* We tolerate any thread races when updating gcMallocBytes. */
gc.mallocBytes -= ptrdiff_t(nbytes);
if (MOZ_UNLIKELY(gc.mallocBytes <= 0))
onTooMuchMalloc();
else if (zone)
zone->updateMallocCounter(nbytes);
gc.updateMallocCounter(zone, nbytes);
}
JS_FRIEND_API(void)
@ -730,9 +712,7 @@ JSRuntime::onTooMuchMalloc()
{
if (!CurrentThreadCanAccessRuntime(this))
return;
if (!gc.mallocGCTriggered)
gc.mallocGCTriggered = TriggerGC(this, JS::gcreason::TOO_MUCH_MALLOC);
gc.onTooMuchMalloc();
}
JS_FRIEND_API(void *)

View File

@ -955,31 +955,7 @@ struct JSRuntime : public JS::shadow::Runtime,
bool isHeapMinorCollecting() { return gc.isHeapMinorCollecting(); }
bool isHeapCollecting() { return gc.isHeapCollecting(); }
#ifdef JS_GC_ZEAL
int gcZeal() { return gc.zealMode; }
bool upcomingZealousGC() {
return gc.nextScheduled == 1;
}
bool needZealousGC() {
if (gc.nextScheduled > 0 && --gc.nextScheduled == 0) {
if (gcZeal() == js::gc::ZealAllocValue ||
gcZeal() == js::gc::ZealGenerationalGCValue ||
(gcZeal() >= js::gc::ZealIncrementalRootsThenFinish &&
gcZeal() <= js::gc::ZealIncrementalMultipleSlices))
{
gc.nextScheduled = gc.zealFrequency;
}
return true;
}
return false;
}
#else
int gcZeal() { return 0; }
bool upcomingZealousGC() { return false; }
bool needZealousGC() { return false; }
#endif
int gcZeal() { return gc.zeal(); }
void lockGC() {
assertCanLock(js::GCLock);
@ -1281,13 +1257,6 @@ struct JSRuntime : public JS::shadow::Runtime,
JSRuntime *thisFromCtor() { return this; }
void setGCMaxMallocBytes(size_t value);
void resetGCMallocBytes() {
gc.mallocBytes = ptrdiff_t(gc.maxMallocBytes);
gc.mallocGCTriggered = false;
}
/*
* Call this after allocating memory held by GC things, to update memory
* pressure counters or report the OOM error if necessary. If oomError and
@ -1301,10 +1270,6 @@ struct JSRuntime : public JS::shadow::Runtime,
void reportAllocationOverflow() { js_ReportAllocationOverflow(nullptr); }
bool isTooMuchMalloc() const {
return gc.mallocBytes <= 0;
}
/*
* The function must be called outside the GC lock.
*/