mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backed out 3 changesets (bug 1021114, bug 988486) for GC crashes on a CLOSED TREE.
Backed out changeset f56234ba7ec7 (bug 1021114) Backed out changeset 14a4a9062253 (bug 988486) Backed out changeset 03eccac81e15 (bug 988486)
This commit is contained in:
parent
2959413a50
commit
9c350ad8b0
@ -16,9 +16,6 @@
|
|||||||
* The purpose of abstracting this as a separate class is to allow it to be
|
* The purpose of abstracting this as a separate class is to allow it to be
|
||||||
* wrapped in a JS::Heap<T> to correctly handle post-barriering of the JSObject
|
* wrapped in a JS::Heap<T> to correctly handle post-barriering of the JSObject
|
||||||
* pointer, when present.
|
* pointer, when present.
|
||||||
*
|
|
||||||
* No implementation of rootKind() is provided, which prevents
|
|
||||||
* Root<nsXBLMaybeCompiled<UncompiledT>> from being used.
|
|
||||||
*/
|
*/
|
||||||
template <class UncompiledT>
|
template <class UncompiledT>
|
||||||
class nsXBLMaybeCompiled
|
class nsXBLMaybeCompiled
|
||||||
@ -91,6 +88,11 @@ struct GCMethods<nsXBLMaybeCompiled<UncompiledT> >
|
|||||||
|
|
||||||
static nsXBLMaybeCompiled<UncompiledT> initial() { return nsXBLMaybeCompiled<UncompiledT>(); }
|
static nsXBLMaybeCompiled<UncompiledT> initial() { return nsXBLMaybeCompiled<UncompiledT>(); }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* No implementation of kind() is provided to prevent
|
||||||
|
* Root<nsXBLMaybeCompiled<UncompiledT>> from being used.
|
||||||
|
*/
|
||||||
|
|
||||||
static bool poisoned(nsXBLMaybeCompiled<UncompiledT> function)
|
static bool poisoned(nsXBLMaybeCompiled<UncompiledT> function)
|
||||||
{
|
{
|
||||||
return function.IsCompiled() && Base::poisoned(function.GetJSFunction());
|
return function.IsCompiled() && Base::poisoned(function.GetJSFunction());
|
||||||
|
@ -375,7 +375,7 @@ ShrinkGCBuffers(JSRuntime *rt);
|
|||||||
class JS_PUBLIC_API(AutoAssertOnGC)
|
class JS_PUBLIC_API(AutoAssertOnGC)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
js::gc::GCRuntime *gc;
|
JSRuntime *runtime;
|
||||||
size_t gcNumber;
|
size_t gcNumber;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -171,6 +171,7 @@ IsPoisonedId(jsid iden)
|
|||||||
template <> struct GCMethods<jsid>
|
template <> struct GCMethods<jsid>
|
||||||
{
|
{
|
||||||
static jsid initial() { return JSID_VOID; }
|
static jsid initial() { return JSID_VOID; }
|
||||||
|
static ThingRootKind kind() { return THING_ROOT_ID; }
|
||||||
static bool poisoned(jsid id) { return IsPoisonedId(id); }
|
static bool poisoned(jsid id) { return IsPoisonedId(id); }
|
||||||
static bool needsPostBarrier(jsid id) { return false; }
|
static bool needsPostBarrier(jsid id) { return false; }
|
||||||
#ifdef JSGC_GENERATIONAL
|
#ifdef JSGC_GENERATIONAL
|
||||||
|
@ -654,6 +654,7 @@ template <typename T>
|
|||||||
struct GCMethods<T *>
|
struct GCMethods<T *>
|
||||||
{
|
{
|
||||||
static T *initial() { return nullptr; }
|
static T *initial() { return nullptr; }
|
||||||
|
static ThingRootKind kind() { return RootKind<T *>::rootKind(); }
|
||||||
static bool poisoned(T *v) { return JS::IsPoisonedPtr(v); }
|
static bool poisoned(T *v) { return JS::IsPoisonedPtr(v); }
|
||||||
static bool needsPostBarrier(T *v) { return false; }
|
static bool needsPostBarrier(T *v) { return false; }
|
||||||
#ifdef JSGC_GENERATIONAL
|
#ifdef JSGC_GENERATIONAL
|
||||||
@ -666,6 +667,7 @@ template <>
|
|||||||
struct GCMethods<JSObject *>
|
struct GCMethods<JSObject *>
|
||||||
{
|
{
|
||||||
static JSObject *initial() { return nullptr; }
|
static JSObject *initial() { return nullptr; }
|
||||||
|
static ThingRootKind kind() { return RootKind<JSObject *>::rootKind(); }
|
||||||
static bool poisoned(JSObject *v) { return JS::IsPoisonedPtr(v); }
|
static bool poisoned(JSObject *v) { return JS::IsPoisonedPtr(v); }
|
||||||
static bool needsPostBarrier(JSObject *v) {
|
static bool needsPostBarrier(JSObject *v) {
|
||||||
return v != nullptr && gc::IsInsideNursery(reinterpret_cast<gc::Cell *>(v));
|
return v != nullptr && gc::IsInsideNursery(reinterpret_cast<gc::Cell *>(v));
|
||||||
@ -705,7 +707,7 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
|
|||||||
template <typename CX>
|
template <typename CX>
|
||||||
void init(CX *cx) {
|
void init(CX *cx) {
|
||||||
#ifdef JSGC_TRACK_EXACT_ROOTS
|
#ifdef JSGC_TRACK_EXACT_ROOTS
|
||||||
js::ThingRootKind kind = js::RootKind<T>::rootKind();
|
js::ThingRootKind kind = js::GCMethods<T>::kind();
|
||||||
this->stack = &cx->thingGCRooters[kind];
|
this->stack = &cx->thingGCRooters[kind];
|
||||||
this->prev = *stack;
|
this->prev = *stack;
|
||||||
*stack = reinterpret_cast<Rooted<void*>*>(this);
|
*stack = reinterpret_cast<Rooted<void*>*>(this);
|
||||||
|
@ -1550,12 +1550,14 @@ namespace js {
|
|||||||
template <> struct GCMethods<const JS::Value>
|
template <> struct GCMethods<const JS::Value>
|
||||||
{
|
{
|
||||||
static JS::Value initial() { return JS::UndefinedValue(); }
|
static JS::Value initial() { return JS::UndefinedValue(); }
|
||||||
|
static ThingRootKind kind() { return THING_ROOT_VALUE; }
|
||||||
static bool poisoned(const JS::Value &v) { return JS::IsPoisonedValue(v); }
|
static bool poisoned(const JS::Value &v) { return JS::IsPoisonedValue(v); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct GCMethods<JS::Value>
|
template <> struct GCMethods<JS::Value>
|
||||||
{
|
{
|
||||||
static JS::Value initial() { return JS::UndefinedValue(); }
|
static JS::Value initial() { return JS::UndefinedValue(); }
|
||||||
|
static ThingRootKind kind() { return THING_ROOT_VALUE; }
|
||||||
static bool poisoned(const JS::Value &v) { return JS::IsPoisonedValue(v); }
|
static bool poisoned(const JS::Value &v) { return JS::IsPoisonedValue(v); }
|
||||||
static bool needsPostBarrier(const JS::Value &v) {
|
static bool needsPostBarrier(const JS::Value &v) {
|
||||||
return v.isObject() && gc::IsInsideNursery(reinterpret_cast<gc::Cell*>(&v.toObject()));
|
return v.isObject() && gc::IsInsideNursery(reinterpret_cast<gc::Cell*>(&v.toObject()));
|
||||||
|
@ -520,7 +520,7 @@ SelectForGC(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
|
|
||||||
for (unsigned i = 0; i < args.length(); i++) {
|
for (unsigned i = 0; i < args.length(); i++) {
|
||||||
if (args[i].isObject()) {
|
if (args[i].isObject()) {
|
||||||
if (!rt->gc.selectForMarking(&args[i].toObject()))
|
if (!rt->gc.selectedForMarking.append(&args[i].toObject()))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -599,7 +599,7 @@ DeterministicGC(JSContext *cx, unsigned argc, jsval *vp)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
cx->runtime()->gc.setDeterministic(ToBoolean(args[0]));
|
gc::SetDeterministicGC(cx, ToBoolean(args[0]));
|
||||||
args.rval().setUndefined();
|
args.rval().setUndefined();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -641,7 +641,7 @@ ValidateGC(JSContext *cx, unsigned argc, jsval *vp)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
cx->runtime()->gc.setValidate(ToBoolean(args[0]));
|
gc::SetValidateGC(cx, ToBoolean(args[0]));
|
||||||
args.rval().setUndefined();
|
args.rval().setUndefined();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -657,7 +657,7 @@ FullCompartmentChecks(JSContext *cx, unsigned argc, jsval *vp)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
cx->runtime()->gc.setFullCompartmentChecks(ToBoolean(args[0]));
|
gc::SetFullCompartmentChecks(cx, ToBoolean(args[0]));
|
||||||
args.rval().setUndefined();
|
args.rval().setUndefined();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,23 @@
|
|||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
|
struct ScriptAndCounts
|
||||||
|
{
|
||||||
|
/* This structure is stored and marked from the JSRuntime. */
|
||||||
|
JSScript *script;
|
||||||
|
ScriptCounts scriptCounts;
|
||||||
|
|
||||||
|
PCCounts &getPCCounts(jsbytecode *pc) const {
|
||||||
|
return scriptCounts.pcCountsVector[script->pcToOffset(pc)];
|
||||||
|
}
|
||||||
|
|
||||||
|
jit::IonScriptCounts *getIonCounts() const {
|
||||||
|
return scriptCounts.ionCounts;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef Vector<ScriptAndCounts, 0, SystemAllocPolicy> ScriptAndCountsVector;
|
||||||
|
|
||||||
namespace gc {
|
namespace gc {
|
||||||
|
|
||||||
typedef Vector<JS::Zone *, 4, SystemAllocPolicy> ZoneVector;
|
typedef Vector<JS::Zone *, 4, SystemAllocPolicy> ZoneVector;
|
||||||
@ -96,10 +113,7 @@ class GCRuntime
|
|||||||
bool init(uint32_t maxbytes);
|
bool init(uint32_t maxbytes);
|
||||||
void finish();
|
void finish();
|
||||||
|
|
||||||
inline int zeal();
|
void setGCZeal(uint8_t zeal, uint32_t frequency);
|
||||||
inline bool upcomingZealousGC();
|
|
||||||
inline bool needZealousGC();
|
|
||||||
|
|
||||||
template <typename T> bool addRoot(T *rp, const char *name, JSGCRootType rootType);
|
template <typename T> bool addRoot(T *rp, const char *name, JSGCRootType rootType);
|
||||||
void removeRoot(void *rp);
|
void removeRoot(void *rp);
|
||||||
void setMarkStackLimit(size_t limit);
|
void setMarkStackLimit(size_t limit);
|
||||||
@ -119,21 +133,14 @@ class GCRuntime
|
|||||||
JS::gcreason::Reason reason);
|
JS::gcreason::Reason reason);
|
||||||
void gcSlice(JSGCInvocationKind gckind, JS::gcreason::Reason reason, int64_t millis);
|
void gcSlice(JSGCInvocationKind gckind, JS::gcreason::Reason reason, int64_t millis);
|
||||||
void runDebugGC();
|
void runDebugGC();
|
||||||
inline void poke();
|
|
||||||
|
|
||||||
void markRuntime(JSTracer *trc, bool useSavedRoots = false);
|
void markRuntime(JSTracer *trc, bool useSavedRoots = false);
|
||||||
|
|
||||||
#ifdef JS_GC_ZEAL
|
#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 verifyPreBarriers();
|
||||||
void verifyPostBarriers();
|
void verifyPostBarriers();
|
||||||
void maybeVerifyPreBarriers(bool always);
|
void maybeVerifyPreBarriers(bool always);
|
||||||
void maybeVerifyPostBarriers(bool always);
|
void maybeVerifyPostBarriers(bool always);
|
||||||
bool selectForMarking(JSObject *object);
|
|
||||||
void clearSelectedForMarking();
|
|
||||||
void setDeterministic(bool enable);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -194,13 +201,6 @@ class GCRuntime
|
|||||||
JS_ASSERT(!isAllocAllowed());
|
JS_ASSERT(!isAllocAllowed());
|
||||||
--noGCOrAllocationCheck;
|
--noGCOrAllocationCheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isInsideUnsafeRegion() { return inUnsafeRegion != 0; }
|
|
||||||
void enterUnsafeRegion() { ++inUnsafeRegion; }
|
|
||||||
void leaveUnsafeRegion() {
|
|
||||||
JS_ASSERT(inUnsafeRegion > 0);
|
|
||||||
--inUnsafeRegion;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void setAlwaysPreserveCode() { alwaysPreserveCode = true; }
|
void setAlwaysPreserveCode() { alwaysPreserveCode = true; }
|
||||||
@ -209,24 +209,6 @@ class GCRuntime
|
|||||||
void disableGenerationalGC();
|
void disableGenerationalGC();
|
||||||
void enableGenerationalGC();
|
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
|
#ifdef JS_GC_ZEAL
|
||||||
void startVerifyPreBarriers();
|
void startVerifyPreBarriers();
|
||||||
bool endVerifyPreBarriers();
|
bool endVerifyPreBarriers();
|
||||||
@ -242,7 +224,7 @@ class GCRuntime
|
|||||||
|
|
||||||
inline bool wantBackgroundAllocation() const;
|
inline bool wantBackgroundAllocation() const;
|
||||||
|
|
||||||
bool initZeal();
|
bool initGCZeal();
|
||||||
void requestInterrupt(JS::gcreason::Reason reason);
|
void requestInterrupt(JS::gcreason::Reason reason);
|
||||||
bool gcCycle(bool incremental, int64_t budget, JSGCInvocationKind gckind,
|
bool gcCycle(bool incremental, int64_t budget, JSGCInvocationKind gckind,
|
||||||
JS::gcreason::Reason reason);
|
JS::gcreason::Reason reason);
|
||||||
@ -475,7 +457,7 @@ class GCRuntime
|
|||||||
*/
|
*/
|
||||||
unsigned objectsMarkedInDeadZones;
|
unsigned objectsMarkedInDeadZones;
|
||||||
|
|
||||||
bool poked;
|
bool poke;
|
||||||
|
|
||||||
volatile js::HeapState heapState;
|
volatile js::HeapState heapState;
|
||||||
|
|
||||||
@ -484,7 +466,6 @@ class GCRuntime
|
|||||||
js::gc::StoreBuffer storeBuffer;
|
js::gc::StoreBuffer storeBuffer;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
|
||||||
/*
|
/*
|
||||||
* These options control the zealousness of the GC. The fundamental values
|
* These options control the zealousness of the GC. The fundamental values
|
||||||
* are nextScheduled and gcDebugCompartmentGC. At every allocation,
|
* are nextScheduled and gcDebugCompartmentGC. At every allocation,
|
||||||
@ -522,7 +503,10 @@ class GCRuntime
|
|||||||
bool validate;
|
bool validate;
|
||||||
bool fullCompartmentChecks;
|
bool fullCompartmentChecks;
|
||||||
|
|
||||||
Callback<JSGCCallback> gcCallback;
|
JSGCCallback gcCallback;
|
||||||
|
void *gcCallbackData;
|
||||||
|
|
||||||
|
JS::GCSliceCallback sliceCallback;
|
||||||
CallbackVector<JSFinalizeCallback> finalizeCallbacks;
|
CallbackVector<JSFinalizeCallback> finalizeCallbacks;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -532,7 +516,7 @@ class GCRuntime
|
|||||||
mozilla::Atomic<ptrdiff_t, mozilla::ReleaseAcquire> mallocBytes;
|
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.
|
* below zero.
|
||||||
*/
|
*/
|
||||||
mozilla::Atomic<bool, mozilla::ReleaseAcquire> mallocGCTriggered;
|
mozilla::Atomic<bool, mozilla::ReleaseAcquire> mallocGCTriggered;
|
||||||
@ -546,6 +530,18 @@ class GCRuntime
|
|||||||
CallbackVector<JSTraceDataOp> blackRootTracers;
|
CallbackVector<JSTraceDataOp> blackRootTracers;
|
||||||
Callback<JSTraceDataOp> grayRootTracer;
|
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;
|
||||||
|
|
||||||
|
/* Strong references on scripts held for PCCount profiling API. */
|
||||||
|
js::ScriptAndCountsVector *scriptAndCountsVector;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
/*
|
/*
|
||||||
* Some regions of code are hard for the static rooting hazard analysis to
|
* Some regions of code are hard for the static rooting hazard analysis to
|
||||||
@ -556,6 +552,7 @@ class GCRuntime
|
|||||||
int inUnsafeRegion;
|
int inUnsafeRegion;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
/* Always preserve JIT code during GCs, for testing. */
|
/* Always preserve JIT code during GCs, for testing. */
|
||||||
bool alwaysPreserveCode;
|
bool alwaysPreserveCode;
|
||||||
|
|
||||||
@ -571,42 +568,11 @@ class GCRuntime
|
|||||||
|
|
||||||
ConservativeGCData conservativeGC;
|
ConservativeGCData conservativeGC;
|
||||||
|
|
||||||
|
//friend class js::gc::Chunk; // todo: remove
|
||||||
friend class js::GCHelperState;
|
friend class js::GCHelperState;
|
||||||
friend class js::gc::MarkingValidator;
|
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 gc */
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ js::Nursery::enable()
|
|||||||
setCurrentChunk(0);
|
setCurrentChunk(0);
|
||||||
currentStart_ = position();
|
currentStart_ = position();
|
||||||
#ifdef JS_GC_ZEAL
|
#ifdef JS_GC_ZEAL
|
||||||
if (runtime()->gcZeal() == ZealGenerationalGCValue)
|
if (runtime()->gc.zealMode == ZealGenerationalGCValue)
|
||||||
enterZealMode();
|
enterZealMode();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -129,7 +129,7 @@ js::Nursery::isEmpty() const
|
|||||||
JS_ASSERT(runtime_);
|
JS_ASSERT(runtime_);
|
||||||
if (!isEnabled())
|
if (!isEnabled())
|
||||||
return true;
|
return true;
|
||||||
JS_ASSERT_IF(runtime_->gcZeal() != ZealGenerationalGCValue, currentStart_ == start());
|
JS_ASSERT_IF(runtime_->gc.zealMode != ZealGenerationalGCValue, currentStart_ == start());
|
||||||
return position() == currentStart_;
|
return position() == currentStart_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -930,7 +930,7 @@ js::Nursery::sweep()
|
|||||||
for (int i = 0; i < NumNurseryChunks; ++i)
|
for (int i = 0; i < NumNurseryChunks; ++i)
|
||||||
initChunk(i);
|
initChunk(i);
|
||||||
|
|
||||||
if (runtime()->gcZeal() == ZealGenerationalGCValue) {
|
if (runtime()->gc.zealMode == ZealGenerationalGCValue) {
|
||||||
MOZ_ASSERT(numActiveChunks_ == NumNurseryChunks);
|
MOZ_ASSERT(numActiveChunks_ == NumNurseryChunks);
|
||||||
|
|
||||||
/* Only reset the alloc point when we are close to the end. */
|
/* Only reset the alloc point when we are close to the end. */
|
||||||
@ -955,7 +955,7 @@ void
|
|||||||
js::Nursery::growAllocableSpace()
|
js::Nursery::growAllocableSpace()
|
||||||
{
|
{
|
||||||
#ifdef JS_GC_ZEAL
|
#ifdef JS_GC_ZEAL
|
||||||
MOZ_ASSERT_IF(runtime()->gcZeal() == ZealGenerationalGCValue,
|
MOZ_ASSERT_IF(runtime()->gc.zealMode == ZealGenerationalGCValue,
|
||||||
numActiveChunks_ == NumNurseryChunks);
|
numActiveChunks_ == NumNurseryChunks);
|
||||||
#endif
|
#endif
|
||||||
numActiveChunks_ = Min(numActiveChunks_ * 2, NumNurseryChunks);
|
numActiveChunks_ = Min(numActiveChunks_ * 2, NumNurseryChunks);
|
||||||
@ -965,7 +965,7 @@ void
|
|||||||
js::Nursery::shrinkAllocableSpace()
|
js::Nursery::shrinkAllocableSpace()
|
||||||
{
|
{
|
||||||
#ifdef JS_GC_ZEAL
|
#ifdef JS_GC_ZEAL
|
||||||
if (runtime()->gcZeal() == ZealGenerationalGCValue)
|
if (runtime()->gc.zealMode == ZealGenerationalGCValue)
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
numActiveChunks_ = Max(numActiveChunks_ - 1, 1);
|
numActiveChunks_ = Max(numActiveChunks_ - 1, 1);
|
||||||
|
@ -730,8 +730,8 @@ js::gc::GCRuntime::markRuntime(JSTracer *trc, bool useSavedRoots)
|
|||||||
|
|
||||||
MarkPersistentRootedChains(trc);
|
MarkPersistentRootedChains(trc);
|
||||||
|
|
||||||
if (rt->scriptAndCountsVector) {
|
if (scriptAndCountsVector) {
|
||||||
ScriptAndCountsVector &vec = *rt->scriptAndCountsVector;
|
ScriptAndCountsVector &vec = *scriptAndCountsVector;
|
||||||
for (size_t i = 0; i < vec.length(); i++)
|
for (size_t i = 0; i < vec.length(); i++)
|
||||||
MarkScriptRoot(trc, &vec[i].script, "scriptAndCountsVector");
|
MarkScriptRoot(trc, &vec[i].script, "scriptAndCountsVector");
|
||||||
}
|
}
|
||||||
|
@ -446,8 +446,7 @@ Statistics::Statistics(JSRuntime *rt)
|
|||||||
compartmentCount(0),
|
compartmentCount(0),
|
||||||
nonincrementalReason(nullptr),
|
nonincrementalReason(nullptr),
|
||||||
preBytes(0),
|
preBytes(0),
|
||||||
phaseNestingDepth(0),
|
phaseNestingDepth(0)
|
||||||
sliceCallback(nullptr)
|
|
||||||
{
|
{
|
||||||
PodArrayZero(phaseTotals);
|
PodArrayZero(phaseTotals);
|
||||||
PodArrayZero(counts);
|
PodArrayZero(counts);
|
||||||
@ -490,13 +489,6 @@ Statistics::~Statistics()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::GCSliceCallback
|
|
||||||
Statistics::setSliceCallback(JS::GCSliceCallback newCallback) {
|
|
||||||
JS::GCSliceCallback oldCallback = sliceCallback;
|
|
||||||
sliceCallback = newCallback;
|
|
||||||
return oldCallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Statistics::printStats()
|
Statistics::printStats()
|
||||||
{
|
{
|
||||||
@ -589,9 +581,9 @@ Statistics::beginSlice(int collectedCount, int zoneCount, int compartmentCount,
|
|||||||
// Slice callbacks should only fire for the outermost level
|
// Slice callbacks should only fire for the outermost level
|
||||||
if (++gcDepth == 1) {
|
if (++gcDepth == 1) {
|
||||||
bool wasFullGC = collectedCount == zoneCount;
|
bool wasFullGC = collectedCount == zoneCount;
|
||||||
if (sliceCallback)
|
if (JS::GCSliceCallback cb = runtime->gc.sliceCallback)
|
||||||
(*sliceCallback)(runtime, first ? JS::GC_CYCLE_BEGIN : JS::GC_SLICE_BEGIN,
|
(*cb)(runtime, first ? JS::GC_CYCLE_BEGIN : JS::GC_SLICE_BEGIN,
|
||||||
JS::GCDescription(!wasFullGC));
|
JS::GCDescription(!wasFullGC));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -613,9 +605,9 @@ Statistics::endSlice()
|
|||||||
// Slice callbacks should only fire for the outermost level
|
// Slice callbacks should only fire for the outermost level
|
||||||
if (--gcDepth == 0) {
|
if (--gcDepth == 0) {
|
||||||
bool wasFullGC = collectedCount == zoneCount;
|
bool wasFullGC = collectedCount == zoneCount;
|
||||||
if (sliceCallback)
|
if (JS::GCSliceCallback cb = runtime->gc.sliceCallback)
|
||||||
(*sliceCallback)(runtime, last ? JS::GC_CYCLE_END : JS::GC_SLICE_END,
|
(*cb)(runtime, last ? JS::GC_CYCLE_END : JS::GC_SLICE_END,
|
||||||
JS::GCDescription(!wasFullGC));
|
JS::GCDescription(!wasFullGC));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do this after the slice callback since it uses these values. */
|
/* Do this after the slice callback since it uses these values. */
|
||||||
|
@ -98,8 +98,6 @@ struct Statistics {
|
|||||||
jschar *formatMessage();
|
jschar *formatMessage();
|
||||||
jschar *formatJSON(uint64_t timestamp);
|
jschar *formatJSON(uint64_t timestamp);
|
||||||
|
|
||||||
JS::GCSliceCallback setSliceCallback(JS::GCSliceCallback callback);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JSRuntime *runtime;
|
JSRuntime *runtime;
|
||||||
|
|
||||||
@ -162,8 +160,6 @@ struct Statistics {
|
|||||||
/* Sweep times for SCCs of compartments. */
|
/* Sweep times for SCCs of compartments. */
|
||||||
Vector<int64_t, 0, SystemAllocPolicy> sccTimes;
|
Vector<int64_t, 0, SystemAllocPolicy> sccTimes;
|
||||||
|
|
||||||
JS::GCSliceCallback sliceCallback;
|
|
||||||
|
|
||||||
void beginGC();
|
void beginGC();
|
||||||
void endGC();
|
void endGC();
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ CompileRuntime::addressOfLastCachedNativeIterator()
|
|||||||
const void *
|
const void *
|
||||||
CompileRuntime::addressOfGCZeal()
|
CompileRuntime::addressOfGCZeal()
|
||||||
{
|
{
|
||||||
return runtime()->gc.addressOfZealMode();
|
return &runtime()->gc.zealMode;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1615,13 +1615,20 @@ JS::RemoveScriptRootRT(JSRuntime *rt, JS::Heap<JSScript *> *rp)
|
|||||||
JS_PUBLIC_API(bool)
|
JS_PUBLIC_API(bool)
|
||||||
JS_AddExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
|
JS_AddExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
|
||||||
{
|
{
|
||||||
return rt->gc.addBlackRootsTracer(traceOp, data);
|
AssertHeapIsIdle(rt);
|
||||||
|
return !!rt->gc.blackRootTracers.append(Callback<JSTraceDataOp>(traceOp, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(void)
|
JS_PUBLIC_API(void)
|
||||||
JS_RemoveExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
|
JS_RemoveExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
|
||||||
{
|
{
|
||||||
return rt->gc.removeBlackRootsTracer(traceOp, 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
@ -1892,21 +1899,28 @@ JS_PUBLIC_API(void)
|
|||||||
JS_SetGCCallback(JSRuntime *rt, JSGCCallback cb, void *data)
|
JS_SetGCCallback(JSRuntime *rt, JSGCCallback cb, void *data)
|
||||||
{
|
{
|
||||||
AssertHeapIsIdle(rt);
|
AssertHeapIsIdle(rt);
|
||||||
rt->gc.setGCCallback(cb, data);
|
rt->gc.gcCallback = cb;
|
||||||
|
rt->gc.gcCallbackData = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(bool)
|
JS_PUBLIC_API(bool)
|
||||||
JS_AddFinalizeCallback(JSRuntime *rt, JSFinalizeCallback cb, void *data)
|
JS_AddFinalizeCallback(JSRuntime *rt, JSFinalizeCallback cb, void *data)
|
||||||
{
|
{
|
||||||
AssertHeapIsIdle(rt);
|
AssertHeapIsIdle(rt);
|
||||||
return rt->gc.addFinalizeCallback(cb, data);
|
return rt->gc.finalizeCallbacks.append(Callback<JSFinalizeCallback>(cb, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(void)
|
JS_PUBLIC_API(void)
|
||||||
JS_RemoveFinalizeCallback(JSRuntime *rt, JSFinalizeCallback cb)
|
JS_RemoveFinalizeCallback(JSRuntime *rt, JSFinalizeCallback cb)
|
||||||
{
|
{
|
||||||
AssertHeapIsIdle(rt);
|
for (Callback<JSFinalizeCallback> *p = rt->gc.finalizeCallbacks.begin();
|
||||||
rt->gc.removeFinalizeCallback(cb);
|
p < rt->gc.finalizeCallbacks.end(); p++)
|
||||||
|
{
|
||||||
|
if (p->op == cb) {
|
||||||
|
rt->gc.finalizeCallbacks.erase(p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(bool)
|
JS_PUBLIC_API(bool)
|
||||||
@ -1931,7 +1945,7 @@ JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32_t value)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case JSGC_MAX_MALLOC_BYTES:
|
case JSGC_MAX_MALLOC_BYTES:
|
||||||
rt->gc.setMaxMallocBytes(value);
|
rt->setGCMaxMallocBytes(value);
|
||||||
break;
|
break;
|
||||||
case JSGC_SLICE_TIME_BUDGET:
|
case JSGC_SLICE_TIME_BUDGET:
|
||||||
rt->gc.sliceBudget = SliceBudget::TimeBudget(value);
|
rt->gc.sliceBudget = SliceBudget::TimeBudget(value);
|
||||||
@ -6206,13 +6220,13 @@ JS_AbortIfWrongThread(JSRuntime *rt)
|
|||||||
JS_PUBLIC_API(void)
|
JS_PUBLIC_API(void)
|
||||||
JS_SetGCZeal(JSContext *cx, uint8_t zeal, uint32_t frequency)
|
JS_SetGCZeal(JSContext *cx, uint8_t zeal, uint32_t frequency)
|
||||||
{
|
{
|
||||||
cx->runtime()->gc.setZeal(zeal, frequency);
|
SetGCZeal(cx->runtime(), zeal, frequency);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(void)
|
JS_PUBLIC_API(void)
|
||||||
JS_ScheduleGC(JSContext *cx, uint32_t count)
|
JS_ScheduleGC(JSContext *cx, uint32_t count)
|
||||||
{
|
{
|
||||||
cx->runtime()->gc.setNextScheduled(count);
|
cx->runtime()->gc.nextScheduled = count;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -3009,6 +3009,7 @@ namespace js {
|
|||||||
template <>
|
template <>
|
||||||
struct GCMethods<JSPropertyDescriptor> {
|
struct GCMethods<JSPropertyDescriptor> {
|
||||||
static JSPropertyDescriptor initial() { return JSPropertyDescriptor(); }
|
static JSPropertyDescriptor initial() { return JSPropertyDescriptor(); }
|
||||||
|
static ThingRootKind kind() { return THING_ROOT_PROPERTY_DESCRIPTOR; }
|
||||||
static bool poisoned(const JSPropertyDescriptor &desc) {
|
static bool poisoned(const JSPropertyDescriptor &desc) {
|
||||||
return (desc.obj && JS::IsPoisonedPtr(desc.obj)) ||
|
return (desc.obj && JS::IsPoisonedPtr(desc.obj)) ||
|
||||||
(desc.attrs & JSPROP_GETTER && desc.getter && JS::IsPoisonedPtr(desc.getter)) ||
|
(desc.attrs & JSPROP_GETTER && desc.getter && JS::IsPoisonedPtr(desc.getter)) ||
|
||||||
|
@ -63,7 +63,8 @@ js::ForgetSourceHook(JSRuntime *rt)
|
|||||||
JS_FRIEND_API(void)
|
JS_FRIEND_API(void)
|
||||||
JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
|
JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
|
||||||
{
|
{
|
||||||
rt->gc.setGrayRootsTracer(traceOp, data);
|
rt->gc.grayRootTracer.op = traceOp;
|
||||||
|
rt->gc.grayRootTracer.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_FRIEND_API(JSString *)
|
JS_FRIEND_API(JSString *)
|
||||||
@ -863,7 +864,9 @@ js::IsContextRunningJS(JSContext *cx)
|
|||||||
JS_FRIEND_API(JS::GCSliceCallback)
|
JS_FRIEND_API(JS::GCSliceCallback)
|
||||||
JS::SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback)
|
JS::SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback)
|
||||||
{
|
{
|
||||||
return rt->gc.setSliceCallback(callback);
|
JS::GCSliceCallback old = rt->gc.sliceCallback;
|
||||||
|
rt->gc.sliceCallback = callback;
|
||||||
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_FRIEND_API(bool)
|
JS_FRIEND_API(bool)
|
||||||
@ -1023,7 +1026,7 @@ JS::IncrementalValueBarrier(const Value &v)
|
|||||||
JS_FRIEND_API(void)
|
JS_FRIEND_API(void)
|
||||||
JS::PokeGC(JSRuntime *rt)
|
JS::PokeGC(JSRuntime *rt)
|
||||||
{
|
{
|
||||||
rt->gc.poke();
|
rt->gc.poke = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_FRIEND_API(JSCompartment *)
|
JS_FRIEND_API(JSCompartment *)
|
||||||
|
317
js/src/jsgc.cpp
317
js/src/jsgc.cpp
@ -1095,7 +1095,7 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
|
|||||||
generationalDisabled(0),
|
generationalDisabled(0),
|
||||||
manipulatingDeadZones(false),
|
manipulatingDeadZones(false),
|
||||||
objectsMarkedInDeadZones(0),
|
objectsMarkedInDeadZones(0),
|
||||||
poked(false),
|
poke(false),
|
||||||
heapState(Idle),
|
heapState(Idle),
|
||||||
#ifdef JSGC_GENERATIONAL
|
#ifdef JSGC_GENERATIONAL
|
||||||
nursery(rt),
|
nursery(rt),
|
||||||
@ -1110,8 +1110,11 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
|
|||||||
#endif
|
#endif
|
||||||
validate(true),
|
validate(true),
|
||||||
fullCompartmentChecks(false),
|
fullCompartmentChecks(false),
|
||||||
|
gcCallback(nullptr),
|
||||||
|
sliceCallback(nullptr),
|
||||||
mallocBytes(0),
|
mallocBytes(0),
|
||||||
mallocGCTriggered(false),
|
mallocGCTriggered(false),
|
||||||
|
scriptAndCountsVector(nullptr),
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
inUnsafeRegion(0),
|
inUnsafeRegion(0),
|
||||||
#endif
|
#endif
|
||||||
@ -1127,8 +1130,14 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
|
|||||||
|
|
||||||
#ifdef JS_GC_ZEAL
|
#ifdef JS_GC_ZEAL
|
||||||
|
|
||||||
|
extern void
|
||||||
|
js::SetGCZeal(JSRuntime *rt, uint8_t zeal, uint32_t frequency)
|
||||||
|
{
|
||||||
|
rt->gc.setGCZeal(zeal, frequency);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GCRuntime::setZeal(uint8_t zeal, uint32_t frequency)
|
GCRuntime::setGCZeal(uint8_t zeal, uint32_t frequency)
|
||||||
{
|
{
|
||||||
if (verifyPreData)
|
if (verifyPreData)
|
||||||
VerifyBarriers(rt, PreBarrierVerifier);
|
VerifyBarriers(rt, PreBarrierVerifier);
|
||||||
@ -1151,14 +1160,8 @@ GCRuntime::setZeal(uint8_t zeal, uint32_t frequency)
|
|||||||
nextScheduled = schedule ? frequency : 0;
|
nextScheduled = schedule ? frequency : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
GCRuntime::setNextScheduled(uint32_t count)
|
|
||||||
{
|
|
||||||
nextScheduled = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
GCRuntime::initZeal()
|
GCRuntime::initGCZeal()
|
||||||
{
|
{
|
||||||
const char *env = getenv("JS_GC_ZEAL");
|
const char *env = getenv("JS_GC_ZEAL");
|
||||||
if (!env)
|
if (!env)
|
||||||
@ -1194,7 +1197,7 @@ GCRuntime::initZeal()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
setZeal(zeal, frequency);
|
setGCZeal(zeal, frequency);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1226,7 +1229,7 @@ GCRuntime::init(uint32_t maxbytes)
|
|||||||
* for default backward API compatibility.
|
* for default backward API compatibility.
|
||||||
*/
|
*/
|
||||||
maxBytes = maxbytes;
|
maxBytes = maxbytes;
|
||||||
setMaxMallocBytes(maxbytes);
|
rt->setGCMaxMallocBytes(maxbytes);
|
||||||
|
|
||||||
#ifndef JS_MORE_DETERMINISTIC
|
#ifndef JS_MORE_DETERMINISTIC
|
||||||
jitReleaseTime = PRMJ_Now() + JIT_SCRIPT_RELEASE_TYPES_INTERVAL;
|
jitReleaseTime = PRMJ_Now() + JIT_SCRIPT_RELEASE_TYPES_INTERVAL;
|
||||||
@ -1241,7 +1244,7 @@ GCRuntime::init(uint32_t maxbytes)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef JS_GC_ZEAL
|
#ifdef JS_GC_ZEAL
|
||||||
if (!initZeal())
|
if (!initGCZeal())
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1326,63 +1329,6 @@ template <typename T> struct BarrierOwner {};
|
|||||||
template <typename T> struct BarrierOwner<T *> { typedef T result; };
|
template <typename T> struct BarrierOwner<T *> { typedef T result; };
|
||||||
template <> struct BarrierOwner<Value> { typedef HeapValue 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>
|
template <typename T>
|
||||||
bool
|
bool
|
||||||
GCRuntime::addRoot(T *rp, const char *name, JSGCRootType rootType)
|
GCRuntime::addRoot(T *rp, const char *name, JSGCRootType rootType)
|
||||||
@ -1403,7 +1349,7 @@ void
|
|||||||
GCRuntime::removeRoot(void *rp)
|
GCRuntime::removeRoot(void *rp)
|
||||||
{
|
{
|
||||||
rootsHash.remove(rp);
|
rootsHash.remove(rp);
|
||||||
poke();
|
poke = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -1477,42 +1423,9 @@ js::RemoveRoot(JSRuntime *rt, void *rp)
|
|||||||
rt->gc.removeRoot(rp);
|
rt->gc.removeRoot(rp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
typedef RootedValueMap::Range RootRange;
|
||||||
GCRuntime::setMaxMallocBytes(size_t value)
|
typedef RootedValueMap::Entry RootEntry;
|
||||||
{
|
typedef RootedValueMap::Enum RootEnum;
|
||||||
/*
|
|
||||||
* 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
|
static size_t
|
||||||
ComputeTriggerBytes(Zone *zone, size_t lastBytes, size_t maxBytes, JSGCInvocationKind gckind)
|
ComputeTriggerBytes(Zone *zone, size_t lastBytes, size_t maxBytes, JSGCInvocationKind gckind)
|
||||||
@ -4441,7 +4354,7 @@ AutoGCSession::~AutoGCSession()
|
|||||||
|
|
||||||
#ifdef JS_GC_ZEAL
|
#ifdef JS_GC_ZEAL
|
||||||
/* Keeping these around after a GC is dangerous. */
|
/* Keeping these around after a GC is dangerous. */
|
||||||
gc->clearSelectedForMarking();
|
gc->selectedForMarking.clearAndFree();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Clear gcMallocBytes for all compartments */
|
/* Clear gcMallocBytes for all compartments */
|
||||||
@ -4450,7 +4363,7 @@ AutoGCSession::~AutoGCSession()
|
|||||||
zone->unscheduleGC();
|
zone->unscheduleGC();
|
||||||
}
|
}
|
||||||
|
|
||||||
gc->resetMallocBytes();
|
gc->rt->resetGCMallocBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoCopyFreeListToArenas::AutoCopyFreeListToArenas(JSRuntime *rt, ZoneSelector selector)
|
AutoCopyFreeListToArenas::AutoCopyFreeListToArenas(JSRuntime *rt, ZoneSelector selector)
|
||||||
@ -4783,7 +4696,7 @@ GCRuntime::budgetIncrementalGC(int64_t *budget)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isTooMuchMalloc()) {
|
if (rt->isTooMuchMalloc()) {
|
||||||
*budget = SliceBudget::Unlimited;
|
*budget = SliceBudget::Unlimited;
|
||||||
stats.nonincremental("malloc bytes trigger");
|
stats.nonincremental("malloc bytes trigger");
|
||||||
}
|
}
|
||||||
@ -4982,21 +4895,21 @@ GCRuntime::collect(bool incremental, int64_t budget, JSGCInvocationKind gckind,
|
|||||||
*/
|
*/
|
||||||
if (incrementalState == NO_INCREMENTAL) {
|
if (incrementalState == NO_INCREMENTAL) {
|
||||||
gcstats::AutoPhase ap(stats, gcstats::PHASE_GC_BEGIN);
|
gcstats::AutoPhase ap(stats, gcstats::PHASE_GC_BEGIN);
|
||||||
if (gcCallback.op)
|
if (gcCallback)
|
||||||
gcCallback.op(rt, JSGC_BEGIN, gcCallback.data);
|
gcCallback(rt, JSGC_BEGIN, gcCallbackData);
|
||||||
}
|
}
|
||||||
|
|
||||||
poked = false;
|
poke = false;
|
||||||
bool wasReset = gcCycle(incremental, budget, gckind, reason);
|
bool wasReset = gcCycle(incremental, budget, gckind, reason);
|
||||||
|
|
||||||
if (incrementalState == NO_INCREMENTAL) {
|
if (incrementalState == NO_INCREMENTAL) {
|
||||||
gcstats::AutoPhase ap(stats, gcstats::PHASE_GC_END);
|
gcstats::AutoPhase ap(stats, gcstats::PHASE_GC_END);
|
||||||
if (gcCallback.op)
|
if (gcCallback)
|
||||||
gcCallback.op(rt, JSGC_END, gcCallback.data);
|
gcCallback(rt, JSGC_END, gcCallbackData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Need to re-schedule all zones for GC. */
|
/* Need to re-schedule all zones for GC. */
|
||||||
if (poked && shouldCleanUpEverything)
|
if (poke && shouldCleanUpEverything)
|
||||||
JS::PrepareForFullGC(rt);
|
JS::PrepareForFullGC(rt);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -5022,7 +4935,7 @@ GCRuntime::collect(bool incremental, int64_t budget, JSGCInvocationKind gckind,
|
|||||||
* case) until we can be sure that no additional garbage is created
|
* case) until we can be sure that no additional garbage is created
|
||||||
* (which typically happens if roots are dropped during finalizers).
|
* (which typically happens if roots are dropped during finalizers).
|
||||||
*/
|
*/
|
||||||
repeat = (poked && shouldCleanUpEverything) || wasReset || repeatForDeadZone;
|
repeat = (poke && shouldCleanUpEverything) || wasReset || repeatForDeadZone;
|
||||||
} while (repeat);
|
} while (repeat);
|
||||||
|
|
||||||
if (incrementalState == NO_INCREMENTAL) {
|
if (incrementalState == NO_INCREMENTAL) {
|
||||||
@ -5382,40 +5295,27 @@ GCRuntime::runDebugGC()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GCRuntime::setValidate(bool enabled)
|
gc::SetDeterministicGC(JSContext *cx, bool enabled)
|
||||||
{
|
{
|
||||||
JS_ASSERT(!isHeapMajorCollecting());
|
|
||||||
validate = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
GCRuntime::setFullCompartmentChecks(bool enabled)
|
|
||||||
{
|
|
||||||
JS_ASSERT(!isHeapMajorCollecting());
|
|
||||||
fullCompartmentChecks = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef JS_GC_ZEAL
|
#ifdef JS_GC_ZEAL
|
||||||
bool
|
JSRuntime *rt = cx->runtime();
|
||||||
GCRuntime::selectForMarking(JSObject *object)
|
rt->gc.deterministicOnly = enabled;
|
||||||
{
|
|
||||||
JS_ASSERT(!isHeapMajorCollecting());
|
|
||||||
return selectedForMarking.append(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
GCRuntime::clearSelectedForMarking()
|
|
||||||
{
|
|
||||||
selectedForMarking.clearAndFree();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
GCRuntime::setDeterministic(bool enabled)
|
|
||||||
{
|
|
||||||
JS_ASSERT(!isHeapMajorCollecting());
|
|
||||||
deterministicOnly = enabled;
|
|
||||||
}
|
|
||||||
#endif
|
#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
|
#ifdef DEBUG
|
||||||
|
|
||||||
@ -5474,6 +5374,105 @@ js::ReleaseAllJITCode(FreeOp *fop)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There are three possible PCCount profiling states:
|
||||||
|
*
|
||||||
|
* 1. None: Neither scripts nor the runtime have count information.
|
||||||
|
* 2. Profile: Active scripts have count information, the runtime does not.
|
||||||
|
* 3. Query: Scripts do not have count information, the runtime does.
|
||||||
|
*
|
||||||
|
* When starting to profile scripts, counting begins immediately, with all JIT
|
||||||
|
* code discarded and recompiled with counts as necessary. Active interpreter
|
||||||
|
* frames will not begin profiling until they begin executing another script
|
||||||
|
* (via a call or return).
|
||||||
|
*
|
||||||
|
* The below API functions manage transitions to new states, according
|
||||||
|
* to the table below.
|
||||||
|
*
|
||||||
|
* Old State
|
||||||
|
* -------------------------
|
||||||
|
* Function None Profile Query
|
||||||
|
* --------
|
||||||
|
* StartPCCountProfiling Profile Profile Profile
|
||||||
|
* StopPCCountProfiling None Query Query
|
||||||
|
* PurgePCCounts None None None
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
ReleaseScriptCounts(FreeOp *fop)
|
||||||
|
{
|
||||||
|
JSRuntime *rt = fop->runtime();
|
||||||
|
JS_ASSERT(rt->gc.scriptAndCountsVector);
|
||||||
|
|
||||||
|
ScriptAndCountsVector &vec = *rt->gc.scriptAndCountsVector;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < vec.length(); i++)
|
||||||
|
vec[i].scriptCounts.destroy(fop);
|
||||||
|
|
||||||
|
fop->delete_(rt->gc.scriptAndCountsVector);
|
||||||
|
rt->gc.scriptAndCountsVector = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_FRIEND_API(void)
|
||||||
|
js::StartPCCountProfiling(JSContext *cx)
|
||||||
|
{
|
||||||
|
JSRuntime *rt = cx->runtime();
|
||||||
|
|
||||||
|
if (rt->profilingScripts)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (rt->gc.scriptAndCountsVector)
|
||||||
|
ReleaseScriptCounts(rt->defaultFreeOp());
|
||||||
|
|
||||||
|
ReleaseAllJITCode(rt->defaultFreeOp());
|
||||||
|
|
||||||
|
rt->profilingScripts = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_FRIEND_API(void)
|
||||||
|
js::StopPCCountProfiling(JSContext *cx)
|
||||||
|
{
|
||||||
|
JSRuntime *rt = cx->runtime();
|
||||||
|
|
||||||
|
if (!rt->profilingScripts)
|
||||||
|
return;
|
||||||
|
JS_ASSERT(!rt->gc.scriptAndCountsVector);
|
||||||
|
|
||||||
|
ReleaseAllJITCode(rt->defaultFreeOp());
|
||||||
|
|
||||||
|
ScriptAndCountsVector *vec = cx->new_<ScriptAndCountsVector>(SystemAllocPolicy());
|
||||||
|
if (!vec)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
|
||||||
|
for (ZoneCellIter i(zone, FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||||
|
JSScript *script = i.get<JSScript>();
|
||||||
|
if (script->hasScriptCounts() && script->types) {
|
||||||
|
ScriptAndCounts sac;
|
||||||
|
sac.script = script;
|
||||||
|
sac.scriptCounts.set(script->releaseScriptCounts());
|
||||||
|
if (!vec->append(sac))
|
||||||
|
sac.scriptCounts.destroy(rt->defaultFreeOp());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rt->profilingScripts = false;
|
||||||
|
rt->gc.scriptAndCountsVector = vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_FRIEND_API(void)
|
||||||
|
js::PurgePCCounts(JSContext *cx)
|
||||||
|
{
|
||||||
|
JSRuntime *rt = cx->runtime();
|
||||||
|
|
||||||
|
if (!rt->gc.scriptAndCountsVector)
|
||||||
|
return;
|
||||||
|
JS_ASSERT(!rt->profilingScripts);
|
||||||
|
|
||||||
|
ReleaseScriptCounts(rt->defaultFreeOp());
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
js::PurgeJITCaches(Zone *zone)
|
js::PurgeJITCaches(Zone *zone)
|
||||||
{
|
{
|
||||||
@ -5602,11 +5601,13 @@ JS::AssertGCThingMustBeTenured(JSObject *obj)
|
|||||||
JS_FRIEND_API(void)
|
JS_FRIEND_API(void)
|
||||||
js::gc::AssertGCThingHasType(js::gc::Cell *cell, JSGCTraceKind kind)
|
js::gc::AssertGCThingHasType(js::gc::Cell *cell, JSGCTraceKind kind)
|
||||||
{
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
JS_ASSERT(cell);
|
JS_ASSERT(cell);
|
||||||
if (IsInsideNursery(cell))
|
if (IsInsideNursery(cell))
|
||||||
JS_ASSERT(kind == JSTRACE_OBJECT);
|
JS_ASSERT(kind == JSTRACE_OBJECT);
|
||||||
else
|
else
|
||||||
JS_ASSERT(MapAllocToTraceKind(cell->tenuredGetAllocKind()) == kind);
|
JS_ASSERT(MapAllocToTraceKind(cell->tenuredGetAllocKind()) == kind);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_FRIEND_API(size_t)
|
JS_FRIEND_API(size_t)
|
||||||
@ -5621,7 +5622,7 @@ JS::GetGCNumber()
|
|||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
JS::AutoAssertOnGC::AutoAssertOnGC()
|
JS::AutoAssertOnGC::AutoAssertOnGC()
|
||||||
: gc(nullptr), gcNumber(0)
|
: runtime(nullptr), gcNumber(0)
|
||||||
{
|
{
|
||||||
js::PerThreadData *data = js::TlsPerThreadData.get();
|
js::PerThreadData *data = js::TlsPerThreadData.get();
|
||||||
if (data) {
|
if (data) {
|
||||||
@ -5631,38 +5632,38 @@ JS::AutoAssertOnGC::AutoAssertOnGC()
|
|||||||
* code that works from both threads, however. We also use this to
|
* code that works from both threads, however. We also use this to
|
||||||
* annotate the off thread run loops.
|
* annotate the off thread run loops.
|
||||||
*/
|
*/
|
||||||
JSRuntime *runtime = data->runtimeIfOnOwnerThread();
|
runtime = data->runtimeIfOnOwnerThread();
|
||||||
if (runtime) {
|
if (runtime) {
|
||||||
gc = &runtime->gc;
|
gcNumber = runtime->gc.number;
|
||||||
gcNumber = gc->number;
|
++runtime->gc.inUnsafeRegion;
|
||||||
gc->enterUnsafeRegion();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::AutoAssertOnGC::AutoAssertOnGC(JSRuntime *rt)
|
JS::AutoAssertOnGC::AutoAssertOnGC(JSRuntime *rt)
|
||||||
: gc(&rt->gc), gcNumber(rt->gc.number)
|
: runtime(rt), gcNumber(rt->gc.number)
|
||||||
{
|
{
|
||||||
gc->enterUnsafeRegion();
|
++rt->gc.inUnsafeRegion;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::AutoAssertOnGC::~AutoAssertOnGC()
|
JS::AutoAssertOnGC::~AutoAssertOnGC()
|
||||||
{
|
{
|
||||||
if (gc) {
|
if (runtime) {
|
||||||
gc->leaveUnsafeRegion();
|
--runtime->gc.inUnsafeRegion;
|
||||||
|
MOZ_ASSERT(runtime->gc.inUnsafeRegion >= 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following backstop assertion should never fire: if we bumped the
|
* The following backstop assertion should never fire: if we bumped the
|
||||||
* gcNumber, we should have asserted because inUnsafeRegion was true.
|
* gcNumber, we should have asserted because inUnsafeRegion was true.
|
||||||
*/
|
*/
|
||||||
MOZ_ASSERT(gcNumber == gc->number, "GC ran inside an AutoAssertOnGC scope.");
|
MOZ_ASSERT(gcNumber == runtime->gc.number, "GC ran inside an AutoAssertOnGC scope.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ void
|
/* static */ void
|
||||||
JS::AutoAssertOnGC::VerifyIsSafeToGC(JSRuntime *rt)
|
JS::AutoAssertOnGC::VerifyIsSafeToGC(JSRuntime *rt)
|
||||||
{
|
{
|
||||||
if (rt->gc.isInsideUnsafeRegion())
|
if (rt->gc.inUnsafeRegion > 0)
|
||||||
MOZ_CRASH("[AutoAssertOnGC] possible GC in GC-unsafe region");
|
MOZ_CRASH("[AutoAssertOnGC] possible GC in GC-unsafe region");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -900,6 +900,11 @@ MinorGC(JSRuntime *rt, JS::gcreason::Reason reason);
|
|||||||
extern void
|
extern void
|
||||||
MinorGC(JSContext *cx, JS::gcreason::Reason reason);
|
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. */
|
/* Functions for managing cross compartment gray pointers. */
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
@ -1156,6 +1161,15 @@ GCIfNeeded(JSContext *cx);
|
|||||||
void
|
void
|
||||||
RunDebugGC(JSContext *cx);
|
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. */
|
/* Wait for the background thread to finish sweeping if it is running. */
|
||||||
void
|
void
|
||||||
FinishBackgroundFinalize(JSRuntime *rt);
|
FinishBackgroundFinalize(JSRuntime *rt);
|
||||||
|
@ -76,15 +76,15 @@ GetGCThingTraceKind(const void *thing)
|
|||||||
return MapAllocToTraceKind(cell->tenuredGetAllocKind());
|
return MapAllocToTraceKind(cell->tenuredGetAllocKind());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
static inline void
|
||||||
GCRuntime::poke()
|
GCPoke(JSRuntime *rt)
|
||||||
{
|
{
|
||||||
poked = true;
|
rt->gc.poke = true;
|
||||||
|
|
||||||
#ifdef JS_GC_ZEAL
|
#ifdef JS_GC_ZEAL
|
||||||
/* Schedule a GC to happen "soon" after a GC poke. */
|
/* Schedule a GC to happen "soon" after a GC poke. */
|
||||||
if (zealMode == ZealPokeValue)
|
if (rt->gcZeal() == js::gc::ZealPokeValue)
|
||||||
nextScheduled = 1;
|
rt->gc.nextScheduled = 1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -489,7 +489,7 @@ CheckAllocatorState(ThreadSafeContext *cx, AllocKind kind)
|
|||||||
|
|
||||||
if (allowGC) {
|
if (allowGC) {
|
||||||
#ifdef JS_GC_ZEAL
|
#ifdef JS_GC_ZEAL
|
||||||
if (rt->gc.needZealousGC())
|
if (rt->needZealousGC())
|
||||||
js::gc::RunDebugGC(ncx);
|
js::gc::RunDebugGC(ncx);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -71,12 +71,14 @@ struct RootKind<TaggedProto>
|
|||||||
template <> struct GCMethods<const TaggedProto>
|
template <> struct GCMethods<const TaggedProto>
|
||||||
{
|
{
|
||||||
static TaggedProto initial() { return TaggedProto(); }
|
static TaggedProto initial() { return TaggedProto(); }
|
||||||
|
static ThingRootKind kind() { return THING_ROOT_OBJECT; }
|
||||||
static bool poisoned(const TaggedProto &v) { return IsPoisonedPtr(v.raw()); }
|
static bool poisoned(const TaggedProto &v) { return IsPoisonedPtr(v.raw()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct GCMethods<TaggedProto>
|
template <> struct GCMethods<TaggedProto>
|
||||||
{
|
{
|
||||||
static TaggedProto initial() { return TaggedProto(); }
|
static TaggedProto initial() { return TaggedProto(); }
|
||||||
|
static ThingRootKind kind() { return THING_ROOT_OBJECT; }
|
||||||
static bool poisoned(const TaggedProto &v) { return IsPoisonedPtr(v.raw()); }
|
static bool poisoned(const TaggedProto &v) { return IsPoisonedPtr(v.raw()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1271,6 +1271,7 @@ template <>
|
|||||||
struct GCMethods<const types::Type>
|
struct GCMethods<const types::Type>
|
||||||
{
|
{
|
||||||
static types::Type initial() { return types::Type::UnknownType(); }
|
static types::Type initial() { return types::Type::UnknownType(); }
|
||||||
|
static ThingRootKind kind() { return THING_ROOT_TYPE; }
|
||||||
static bool poisoned(const types::Type &v) {
|
static bool poisoned(const types::Type &v) {
|
||||||
return (v.isTypeObject() && IsPoisonedPtr(v.typeObject()))
|
return (v.isTypeObject() && IsPoisonedPtr(v.typeObject()))
|
||||||
|| (v.isSingleObject() && IsPoisonedPtr(v.singleObject()));
|
|| (v.isSingleObject() && IsPoisonedPtr(v.singleObject()));
|
||||||
@ -1281,6 +1282,7 @@ template <>
|
|||||||
struct GCMethods<types::Type>
|
struct GCMethods<types::Type>
|
||||||
{
|
{
|
||||||
static types::Type initial() { return types::Type::UnknownType(); }
|
static types::Type initial() { return types::Type::UnknownType(); }
|
||||||
|
static ThingRootKind kind() { return THING_ROOT_TYPE; }
|
||||||
static bool poisoned(const types::Type &v) {
|
static bool poisoned(const types::Type &v) {
|
||||||
return (v.isTypeObject() && IsPoisonedPtr(v.typeObject()))
|
return (v.isTypeObject() && IsPoisonedPtr(v.typeObject()))
|
||||||
|| (v.isSingleObject() && IsPoisonedPtr(v.singleObject()));
|
|| (v.isSingleObject() && IsPoisonedPtr(v.singleObject()));
|
||||||
|
@ -5274,7 +5274,7 @@ baseops::DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, bool *succe
|
|||||||
return CallJSDeletePropertyOp(cx, obj->getClass()->delProperty, obj, id, succeeded);
|
return CallJSDeletePropertyOp(cx, obj->getClass()->delProperty, obj, id, succeeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
cx->runtime()->gc.poke();
|
GCPoke(cx->runtime());
|
||||||
|
|
||||||
if (IsImplicitDenseOrTypedArrayElement(shape)) {
|
if (IsImplicitDenseOrTypedArrayElement(shape)) {
|
||||||
if (obj->is<TypedArrayObject>()) {
|
if (obj->is<TypedArrayObject>()) {
|
||||||
|
@ -1936,114 +1936,15 @@ js::IsValidBytecodeOffset(JSContext *cx, JSScript *script, size_t offset)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* There are three possible PCCount profiling states:
|
|
||||||
*
|
|
||||||
* 1. None: Neither scripts nor the runtime have count information.
|
|
||||||
* 2. Profile: Active scripts have count information, the runtime does not.
|
|
||||||
* 3. Query: Scripts do not have count information, the runtime does.
|
|
||||||
*
|
|
||||||
* When starting to profile scripts, counting begins immediately, with all JIT
|
|
||||||
* code discarded and recompiled with counts as necessary. Active interpreter
|
|
||||||
* frames will not begin profiling until they begin executing another script
|
|
||||||
* (via a call or return).
|
|
||||||
*
|
|
||||||
* The below API functions manage transitions to new states, according
|
|
||||||
* to the table below.
|
|
||||||
*
|
|
||||||
* Old State
|
|
||||||
* -------------------------
|
|
||||||
* Function None Profile Query
|
|
||||||
* --------
|
|
||||||
* StartPCCountProfiling Profile Profile Profile
|
|
||||||
* StopPCCountProfiling None Query Query
|
|
||||||
* PurgePCCounts None None None
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
ReleaseScriptCounts(FreeOp *fop)
|
|
||||||
{
|
|
||||||
JSRuntime *rt = fop->runtime();
|
|
||||||
JS_ASSERT(rt->scriptAndCountsVector);
|
|
||||||
|
|
||||||
ScriptAndCountsVector &vec = *rt->scriptAndCountsVector;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < vec.length(); i++)
|
|
||||||
vec[i].scriptCounts.destroy(fop);
|
|
||||||
|
|
||||||
fop->delete_(rt->scriptAndCountsVector);
|
|
||||||
rt->scriptAndCountsVector = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_FRIEND_API(void)
|
|
||||||
js::StartPCCountProfiling(JSContext *cx)
|
|
||||||
{
|
|
||||||
JSRuntime *rt = cx->runtime();
|
|
||||||
|
|
||||||
if (rt->profilingScripts)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (rt->scriptAndCountsVector)
|
|
||||||
ReleaseScriptCounts(rt->defaultFreeOp());
|
|
||||||
|
|
||||||
ReleaseAllJITCode(rt->defaultFreeOp());
|
|
||||||
|
|
||||||
rt->profilingScripts = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_FRIEND_API(void)
|
|
||||||
js::StopPCCountProfiling(JSContext *cx)
|
|
||||||
{
|
|
||||||
JSRuntime *rt = cx->runtime();
|
|
||||||
|
|
||||||
if (!rt->profilingScripts)
|
|
||||||
return;
|
|
||||||
JS_ASSERT(!rt->scriptAndCountsVector);
|
|
||||||
|
|
||||||
ReleaseAllJITCode(rt->defaultFreeOp());
|
|
||||||
|
|
||||||
ScriptAndCountsVector *vec = cx->new_<ScriptAndCountsVector>(SystemAllocPolicy());
|
|
||||||
if (!vec)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
|
|
||||||
for (ZoneCellIter i(zone, FINALIZE_SCRIPT); !i.done(); i.next()) {
|
|
||||||
JSScript *script = i.get<JSScript>();
|
|
||||||
if (script->hasScriptCounts() && script->types) {
|
|
||||||
ScriptAndCounts sac;
|
|
||||||
sac.script = script;
|
|
||||||
sac.scriptCounts.set(script->releaseScriptCounts());
|
|
||||||
if (!vec->append(sac))
|
|
||||||
sac.scriptCounts.destroy(rt->defaultFreeOp());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rt->profilingScripts = false;
|
|
||||||
rt->scriptAndCountsVector = vec;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_FRIEND_API(void)
|
|
||||||
js::PurgePCCounts(JSContext *cx)
|
|
||||||
{
|
|
||||||
JSRuntime *rt = cx->runtime();
|
|
||||||
|
|
||||||
if (!rt->scriptAndCountsVector)
|
|
||||||
return;
|
|
||||||
JS_ASSERT(!rt->profilingScripts);
|
|
||||||
|
|
||||||
ReleaseScriptCounts(rt->defaultFreeOp());
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_FRIEND_API(size_t)
|
JS_FRIEND_API(size_t)
|
||||||
js::GetPCCountScriptCount(JSContext *cx)
|
js::GetPCCountScriptCount(JSContext *cx)
|
||||||
{
|
{
|
||||||
JSRuntime *rt = cx->runtime();
|
JSRuntime *rt = cx->runtime();
|
||||||
|
|
||||||
if (!rt->scriptAndCountsVector)
|
if (!rt->gc.scriptAndCountsVector)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return rt->scriptAndCountsVector->length();
|
return rt->gc.scriptAndCountsVector->length();
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MaybeComma {NO_COMMA, COMMA};
|
enum MaybeComma {NO_COMMA, COMMA};
|
||||||
@ -2078,12 +1979,12 @@ js::GetPCCountScriptSummary(JSContext *cx, size_t index)
|
|||||||
{
|
{
|
||||||
JSRuntime *rt = cx->runtime();
|
JSRuntime *rt = cx->runtime();
|
||||||
|
|
||||||
if (!rt->scriptAndCountsVector || index >= rt->scriptAndCountsVector->length()) {
|
if (!rt->gc.scriptAndCountsVector || index >= rt->gc.scriptAndCountsVector->length()) {
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BUFFER_TOO_SMALL);
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BUFFER_TOO_SMALL);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ScriptAndCounts &sac = (*rt->scriptAndCountsVector)[index];
|
const ScriptAndCounts &sac = (*rt->gc.scriptAndCountsVector)[index];
|
||||||
RootedScript script(cx, sac.script);
|
RootedScript script(cx, sac.script);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2338,12 +2239,12 @@ js::GetPCCountScriptContents(JSContext *cx, size_t index)
|
|||||||
{
|
{
|
||||||
JSRuntime *rt = cx->runtime();
|
JSRuntime *rt = cx->runtime();
|
||||||
|
|
||||||
if (!rt->scriptAndCountsVector || index >= rt->scriptAndCountsVector->length()) {
|
if (!rt->gc.scriptAndCountsVector || index >= rt->gc.scriptAndCountsVector->length()) {
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BUFFER_TOO_SMALL);
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BUFFER_TOO_SMALL);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ScriptAndCounts &sac = (*rt->scriptAndCountsVector)[index];
|
const ScriptAndCounts &sac = (*rt->gc.scriptAndCountsVector)[index];
|
||||||
JSScript *script = sac.script;
|
JSScript *script = sac.script;
|
||||||
|
|
||||||
StringBuffer buf(cx);
|
StringBuffer buf(cx);
|
||||||
|
@ -273,6 +273,7 @@ class Bindings
|
|||||||
template <>
|
template <>
|
||||||
struct GCMethods<Bindings> {
|
struct GCMethods<Bindings> {
|
||||||
static Bindings initial();
|
static Bindings initial();
|
||||||
|
static ThingRootKind kind() { return THING_ROOT_BINDINGS; }
|
||||||
static bool poisoned(const Bindings &bindings) {
|
static bool poisoned(const Bindings &bindings) {
|
||||||
return IsPoisonedPtr(static_cast<Shape *>(bindings.callObjShape()));
|
return IsPoisonedPtr(static_cast<Shape *>(bindings.callObjShape()));
|
||||||
}
|
}
|
||||||
@ -1927,21 +1928,6 @@ SweepScriptData(JSRuntime *rt);
|
|||||||
extern void
|
extern void
|
||||||
FreeScriptData(JSRuntime *rt);
|
FreeScriptData(JSRuntime *rt);
|
||||||
|
|
||||||
struct ScriptAndCounts
|
|
||||||
{
|
|
||||||
/* This structure is stored and marked from the JSRuntime. */
|
|
||||||
JSScript *script;
|
|
||||||
ScriptCounts scriptCounts;
|
|
||||||
|
|
||||||
PCCounts &getPCCounts(jsbytecode *pc) const {
|
|
||||||
return scriptCounts.pcCountsVector[script->pcToOffset(pc)];
|
|
||||||
}
|
|
||||||
|
|
||||||
jit::IonScriptCounts *getIonCounts() const {
|
|
||||||
return scriptCounts.ionCounts;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GSNCache;
|
struct GSNCache;
|
||||||
|
|
||||||
jssrcnote *
|
jssrcnote *
|
||||||
|
@ -336,6 +336,7 @@ namespace js {
|
|||||||
template <>
|
template <>
|
||||||
struct GCMethods<PropDesc> {
|
struct GCMethods<PropDesc> {
|
||||||
static PropDesc initial() { return PropDesc(); }
|
static PropDesc initial() { return PropDesc(); }
|
||||||
|
static ThingRootKind kind() { return THING_ROOT_PROP_DESC; }
|
||||||
static bool poisoned(const PropDesc &desc) {
|
static bool poisoned(const PropDesc &desc) {
|
||||||
return JS::IsPoisonedPtr(desc.descObj_) ||
|
return JS::IsPoisonedPtr(desc.descObj_) ||
|
||||||
(desc.value_.isGCThing() &&
|
(desc.value_.isGCThing() &&
|
||||||
|
@ -56,7 +56,7 @@ NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entry_, js::gc::Initi
|
|||||||
if (type->shouldPreTenure())
|
if (type->shouldPreTenure())
|
||||||
heap = gc::TenuredHeap;
|
heap = gc::TenuredHeap;
|
||||||
|
|
||||||
if (cx->runtime()->gc.upcomingZealousGC())
|
if (cx->runtime()->upcomingZealousGC())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// Trigger an identical allocation to the one that notified us of OOM
|
// Trigger an identical allocation to the one that notified us of OOM
|
||||||
|
@ -181,7 +181,6 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime)
|
|||||||
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
||||||
simulatorRuntime_(nullptr),
|
simulatorRuntime_(nullptr),
|
||||||
#endif
|
#endif
|
||||||
scriptAndCountsVector(nullptr),
|
|
||||||
NaNValue(DoubleNaNValue()),
|
NaNValue(DoubleNaNValue()),
|
||||||
negativeInfinityValue(DoubleValue(NegativeInfinity<double>())),
|
negativeInfinityValue(DoubleValue(NegativeInfinity<double>())),
|
||||||
positiveInfinityValue(DoubleValue(PositiveInfinity<double>())),
|
positiveInfinityValue(DoubleValue(PositiveInfinity<double>())),
|
||||||
@ -695,6 +694,19 @@ JSRuntime::triggerActivityCallback(bool active)
|
|||||||
activityCallback(activityCallbackArg, 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
|
void
|
||||||
JSRuntime::updateMallocCounter(size_t nbytes)
|
JSRuntime::updateMallocCounter(size_t nbytes)
|
||||||
{
|
{
|
||||||
@ -704,7 +716,12 @@ JSRuntime::updateMallocCounter(size_t nbytes)
|
|||||||
void
|
void
|
||||||
JSRuntime::updateMallocCounter(JS::Zone *zone, size_t nbytes)
|
JSRuntime::updateMallocCounter(JS::Zone *zone, size_t nbytes)
|
||||||
{
|
{
|
||||||
gc.updateMallocCounter(zone, 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_FRIEND_API(void)
|
JS_FRIEND_API(void)
|
||||||
@ -712,7 +729,9 @@ JSRuntime::onTooMuchMalloc()
|
|||||||
{
|
{
|
||||||
if (!CurrentThreadCanAccessRuntime(this))
|
if (!CurrentThreadCanAccessRuntime(this))
|
||||||
return;
|
return;
|
||||||
gc.onTooMuchMalloc();
|
|
||||||
|
if (!gc.mallocGCTriggered)
|
||||||
|
gc.mallocGCTriggered = TriggerGC(this, JS::gcreason::TOO_MUCH_MALLOC);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_FRIEND_API(void *)
|
JS_FRIEND_API(void *)
|
||||||
|
@ -134,8 +134,6 @@ struct ScopeCoordinateNameCache {
|
|||||||
void purge();
|
void purge();
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Vector<ScriptAndCounts, 0, SystemAllocPolicy> ScriptAndCountsVector;
|
|
||||||
|
|
||||||
struct EvalCacheEntry
|
struct EvalCacheEntry
|
||||||
{
|
{
|
||||||
JSScript *script;
|
JSScript *script;
|
||||||
@ -955,7 +953,31 @@ struct JSRuntime : public JS::shadow::Runtime,
|
|||||||
bool isHeapMinorCollecting() { return gc.isHeapMinorCollecting(); }
|
bool isHeapMinorCollecting() { return gc.isHeapMinorCollecting(); }
|
||||||
bool isHeapCollecting() { return gc.isHeapCollecting(); }
|
bool isHeapCollecting() { return gc.isHeapCollecting(); }
|
||||||
|
|
||||||
int gcZeal() { return gc.zeal(); }
|
#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
|
||||||
|
|
||||||
void lockGC() {
|
void lockGC() {
|
||||||
assertCanLock(js::GCLock);
|
assertCanLock(js::GCLock);
|
||||||
@ -980,9 +1002,6 @@ struct JSRuntime : public JS::shadow::Runtime,
|
|||||||
void setSimulatorRuntime(js::jit::SimulatorRuntime *srt);
|
void setSimulatorRuntime(js::jit::SimulatorRuntime *srt);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Strong references on scripts held for PCCount profiling API. */
|
|
||||||
js::ScriptAndCountsVector *scriptAndCountsVector;
|
|
||||||
|
|
||||||
/* Well-known numbers held for use by this runtime's contexts. */
|
/* Well-known numbers held for use by this runtime's contexts. */
|
||||||
const js::Value NaNValue;
|
const js::Value NaNValue;
|
||||||
const js::Value negativeInfinityValue;
|
const js::Value negativeInfinityValue;
|
||||||
@ -1257,6 +1276,13 @@ struct JSRuntime : public JS::shadow::Runtime,
|
|||||||
|
|
||||||
JSRuntime *thisFromCtor() { return this; }
|
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
|
* Call this after allocating memory held by GC things, to update memory
|
||||||
* pressure counters or report the OOM error if necessary. If oomError and
|
* pressure counters or report the OOM error if necessary. If oomError and
|
||||||
@ -1270,6 +1296,10 @@ struct JSRuntime : public JS::shadow::Runtime,
|
|||||||
|
|
||||||
void reportAllocationOverflow() { js_ReportAllocationOverflow(nullptr); }
|
void reportAllocationOverflow() { js_ReportAllocationOverflow(nullptr); }
|
||||||
|
|
||||||
|
bool isTooMuchMalloc() const {
|
||||||
|
return gc.mallocBytes <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The function must be called outside the GC lock.
|
* The function must be called outside the GC lock.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user