mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 988486 - Make more GCRuntime members private and add necessary accessors r=terrence
This commit is contained in:
parent
efb8fda24d
commit
ae458fbb93
@ -375,7 +375,7 @@ ShrinkGCBuffers(JSRuntime *rt);
|
||||
class JS_PUBLIC_API(AutoAssertOnGC)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
JSRuntime *runtime;
|
||||
js::gc::GCRuntime *gc;
|
||||
size_t gcNumber;
|
||||
|
||||
public:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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. */
|
||||
|
@ -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();
|
||||
|
||||
|
@ -68,7 +68,7 @@ CompileRuntime::addressOfLastCachedNativeIterator()
|
||||
const void *
|
||||
CompileRuntime::addressOfGCZeal()
|
||||
{
|
||||
return &runtime()->gc.zealMode;
|
||||
return runtime()->gc.addressOfZealMode();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -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,21 @@ 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;
|
||||
}
|
||||
}
|
||||
AssertHeapIsIdle(rt);
|
||||
rt->gc.removeFinalizeCallback(cb);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
@ -1945,7 +1931,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 +6206,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
|
||||
|
||||
|
@ -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 *)
|
||||
|
217
js/src/jsgc.cpp
217
js/src/jsgc.cpp
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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>()) {
|
||||
|
@ -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
|
||||
|
@ -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 *)
|
||||
|
@ -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.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user