Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCAPI.h
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- | ||||
* vim: set ts=8 sts=4 et sw=4 tw=99: | * vim: set ts=8 sts=4 et sw=4 tw=99: | ||||
* This Source Code Form is subject to the terms of the Mozilla Public | * This Source Code Form is subject to the terms of the Mozilla Public | ||||
* License, v. 2.0. If a copy of the MPL was not distributed with this | * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||||
#ifndef js_GCAPI_h | #ifndef js_GCAPI_h | ||||
#define js_GCAPI_h | #define js_GCAPI_h | ||||
#include "mozilla/UniquePtr.h" | |||||
#include "mozilla/Vector.h" | #include "mozilla/Vector.h" | ||||
#include "js/GCAnnotations.h" | |||||
#include "js/HeapAPI.h" | #include "js/HeapAPI.h" | ||||
#include "js/UniquePtr.h" | |||||
namespace js { | namespace js { | ||||
namespace gc { | namespace gc { | ||||
class GCRuntime; | class GCRuntime; | ||||
} // namespace gc | } // namespace gc | ||||
namespace gcstats { | namespace gcstats { | ||||
struct Statistics; | struct Statistics; | ||||
} // namespace gcstats | } // namespace gcstats | ||||
} // namespace js | } // namespace js | ||||
typedef enum JSGCMode { | typedef enum JSGCMode { | ||||
/** Perform only global GCs. */ | /** Perform only global GCs. */ | ||||
JSGC_MODE_GLOBAL = 0, | JSGC_MODE_GLOBAL = 0, | ||||
/** Perform per-compartment GCs until too much garbage has accumulated. */ | /** Perform per-zone GCs until too much garbage has accumulated. */ | ||||
JSGC_MODE_COMPARTMENT = 1, | JSGC_MODE_ZONE = 1, | ||||
/** | /** | ||||
* Collect in short time slices rather than all at once. Implies | * Collect in short time slices rather than all at once. Implies | ||||
* JSGC_MODE_COMPARTMENT. | * JSGC_MODE_ZONE. | ||||
*/ | */ | ||||
JSGC_MODE_INCREMENTAL = 2 | JSGC_MODE_INCREMENTAL = 2 | ||||
} JSGCMode; | } JSGCMode; | ||||
/** | /** | ||||
* Kinds of js_GC invocation. | * Kinds of js_GC invocation. | ||||
*/ | */ | ||||
typedef enum JSGCInvocationKind { | typedef enum JSGCInvocationKind { | ||||
/* Normal invocation. */ | /* Normal invocation. */ | ||||
GC_NORMAL = 0, | GC_NORMAL = 0, | ||||
/* Minimize GC triggers and release empty GC chunks right away. */ | /* Minimize GC triggers and release empty GC chunks right away. */ | ||||
GC_SHRINK = 1 | GC_SHRINK = 1 | ||||
} JSGCInvocationKind; | } JSGCInvocationKind; | ||||
namespace JS { | namespace JS { | ||||
using mozilla::UniquePtr; | |||||
#define GCREASONS(D) \ | #define GCREASONS(D) \ | ||||
/* Reasons internal to the JS engine */ \ | /* Reasons internal to the JS engine */ \ | ||||
D(API) \ | D(API) \ | ||||
D(EAGER_ALLOC_TRIGGER) \ | D(EAGER_ALLOC_TRIGGER) \ | ||||
D(DESTROY_RUNTIME) \ | D(DESTROY_RUNTIME) \ | ||||
D(DESTROY_CONTEXT) \ | D(UNUSED0) \ | ||||
D(LAST_DITCH) \ | D(LAST_DITCH) \ | ||||
D(TOO_MUCH_MALLOC) \ | D(TOO_MUCH_MALLOC) \ | ||||
D(ALLOC_TRIGGER) \ | D(ALLOC_TRIGGER) \ | ||||
D(DEBUG_GC) \ | D(DEBUG_GC) \ | ||||
D(COMPARTMENT_REVIVED) \ | D(COMPARTMENT_REVIVED) \ | ||||
D(RESET) \ | D(RESET) \ | ||||
D(OUT_OF_NURSERY) \ | D(OUT_OF_NURSERY) \ | ||||
D(EVICT_NURSERY) \ | D(EVICT_NURSERY) \ | ||||
D(FULL_STORE_BUFFER) \ | D(FULL_STORE_BUFFER) \ | ||||
D(SHARED_MEMORY_LIMIT) \ | D(SHARED_MEMORY_LIMIT) \ | ||||
D(PERIODIC_FULL_GC) \ | D(UNUSED1) \ | ||||
D(INCREMENTAL_TOO_SLOW) \ | D(INCREMENTAL_TOO_SLOW) \ | ||||
D(ABORT_GC) \ | D(ABORT_GC) \ | ||||
\ | \ | ||||
/* These are reserved for future use. */ \ | /* These are reserved for future use. */ \ | ||||
D(RESERVED0) \ | D(RESERVED0) \ | ||||
D(RESERVED1) \ | D(RESERVED1) \ | ||||
D(RESERVED2) \ | D(RESERVED2) \ | ||||
D(RESERVED3) \ | D(RESERVED3) \ | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | #undef MAKE_REASON | ||||
* For telemetry, we want to keep a fixed max bucket size over time so we | * For telemetry, we want to keep a fixed max bucket size over time so we | ||||
* don't have to switch histograms. 100 is conservative; as of this writing | * don't have to switch histograms. 100 is conservative; as of this writing | ||||
* there are 52. But the cost of extra buckets seems to be low while the | * there are 52. But the cost of extra buckets seems to be low while the | ||||
* cost of switching histograms is high. | * cost of switching histograms is high. | ||||
*/ | */ | ||||
NUM_TELEMETRY_REASONS = 100 | NUM_TELEMETRY_REASONS = 100 | ||||
}; | }; | ||||
/** | |||||
* Get a statically allocated C string explaining the given GC reason. | |||||
*/ | |||||
extern JS_PUBLIC_API(const char*) | |||||
ExplainReason(JS::gcreason::Reason reason); | |||||
} /* namespace gcreason */ | } /* namespace gcreason */ | ||||
/* | /* | ||||
* Zone GC: | * Zone GC: | ||||
* | * | ||||
* SpiderMonkey's GC is capable of performing a collection on an arbitrary | * SpiderMonkey's GC is capable of performing a collection on an arbitrary | ||||
* subset of the zones in the system. This allows an embedding to minimize | * subset of the zones in the system. This allows an embedding to minimize | ||||
* collection time by only collecting zones that have run code recently, | * collection time by only collecting zones that have run code recently, | ||||
Show All 10 Lines | |||||
*/ | */ | ||||
extern JS_PUBLIC_API(void) | extern JS_PUBLIC_API(void) | ||||
PrepareZoneForGC(Zone* zone); | PrepareZoneForGC(Zone* zone); | ||||
/** | /** | ||||
* Schedule all zones to be collected in the next GC. | * Schedule all zones to be collected in the next GC. | ||||
*/ | */ | ||||
extern JS_PUBLIC_API(void) | extern JS_PUBLIC_API(void) | ||||
PrepareForFullGC(JSRuntime* rt); | PrepareForFullGC(JSContext* cx); | ||||
/** | /** | ||||
* When performing an incremental GC, the zones that were selected for the | * When performing an incremental GC, the zones that were selected for the | ||||
* previous incremental slice must be selected in subsequent slices as well. | * previous incremental slice must be selected in subsequent slices as well. | ||||
* This function selects those slices automatically. | * This function selects those slices automatically. | ||||
*/ | */ | ||||
extern JS_PUBLIC_API(void) | extern JS_PUBLIC_API(void) | ||||
PrepareForIncrementalGC(JSRuntime* rt); | PrepareForIncrementalGC(JSContext* cx); | ||||
/** | /** | ||||
* Returns true if any zone in the system has been scheduled for GC with one of | * Returns true if any zone in the system has been scheduled for GC with one of | ||||
* the functions above or by the JS engine. | * the functions above or by the JS engine. | ||||
*/ | */ | ||||
extern JS_PUBLIC_API(bool) | extern JS_PUBLIC_API(bool) | ||||
IsGCScheduled(JSRuntime* rt); | IsGCScheduled(JSContext* cx); | ||||
/** | /** | ||||
* Undoes the effect of the Prepare methods above. The given zone will not be | * Undoes the effect of the Prepare methods above. The given zone will not be | ||||
* collected in the next GC. | * collected in the next GC. | ||||
*/ | */ | ||||
extern JS_PUBLIC_API(void) | extern JS_PUBLIC_API(void) | ||||
SkipZoneForGC(Zone* zone); | SkipZoneForGC(Zone* zone); | ||||
/* | /* | ||||
* Non-Incremental GC: | * Non-Incremental GC: | ||||
* | * | ||||
* The following functions perform a non-incremental GC. | * The following functions perform a non-incremental GC. | ||||
*/ | */ | ||||
/** | /** | ||||
* Performs a non-incremental collection of all selected zones. | * Performs a non-incremental collection of all selected zones. | ||||
* | * | ||||
* If the gckind argument is GC_NORMAL, then some objects that are unreachable | * If the gckind argument is GC_NORMAL, then some objects that are unreachable | ||||
* from the program may still be alive afterwards because of internal | * from the program may still be alive afterwards because of internal | ||||
* references; if GC_SHRINK is passed then caches and other temporary references | * references; if GC_SHRINK is passed then caches and other temporary references | ||||
* to objects will be cleared and all unreferenced objects will be removed from | * to objects will be cleared and all unreferenced objects will be removed from | ||||
* the system. | * the system. | ||||
*/ | */ | ||||
extern JS_PUBLIC_API(void) | extern JS_PUBLIC_API(void) | ||||
GCForReason(JSRuntime* rt, JSGCInvocationKind gckind, gcreason::Reason reason); | GCForReason(JSContext* cx, JSGCInvocationKind gckind, gcreason::Reason reason); | ||||
/* | /* | ||||
* Incremental GC: | * Incremental GC: | ||||
* | * | ||||
* Incremental GC divides the full mark-and-sweep collection into multiple | * Incremental GC divides the full mark-and-sweep collection into multiple | ||||
* slices, allowing client JavaScript code to run between each slice. This | * slices, allowing client JavaScript code to run between each slice. This | ||||
* allows interactive apps to avoid long collection pauses. Incremental GC does | * allows interactive apps to avoid long collection pauses. Incremental GC does | ||||
* not make collection take less time, it merely spreads that time out so that | * not make collection take less time, it merely spreads that time out so that | ||||
Show All 9 Lines | |||||
* Note: Even if incremental GC is enabled and working correctly, | * Note: Even if incremental GC is enabled and working correctly, | ||||
* non-incremental collections can still happen when low on memory. | * non-incremental collections can still happen when low on memory. | ||||
*/ | */ | ||||
/** | /** | ||||
* Begin an incremental collection and perform one slice worth of work. When | * Begin an incremental collection and perform one slice worth of work. When | ||||
* this function returns, the collection may not be complete. | * this function returns, the collection may not be complete. | ||||
* IncrementalGCSlice() must be called repeatedly until | * IncrementalGCSlice() must be called repeatedly until | ||||
* !IsIncrementalGCInProgress(rt). | * !IsIncrementalGCInProgress(cx). | ||||
* | * | ||||
* Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or | * Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or | ||||
* shorter than the requested interval. | * shorter than the requested interval. | ||||
*/ | */ | ||||
extern JS_PUBLIC_API(void) | extern JS_PUBLIC_API(void) | ||||
StartIncrementalGC(JSRuntime* rt, JSGCInvocationKind gckind, gcreason::Reason reason, | StartIncrementalGC(JSContext* cx, JSGCInvocationKind gckind, gcreason::Reason reason, | ||||
int64_t millis = 0); | int64_t millis = 0); | ||||
/** | /** | ||||
* Perform a slice of an ongoing incremental collection. When this function | * Perform a slice of an ongoing incremental collection. When this function | ||||
* returns, the collection may not be complete. It must be called repeatedly | * returns, the collection may not be complete. It must be called repeatedly | ||||
* until !IsIncrementalGCInProgress(rt). | * until !IsIncrementalGCInProgress(cx). | ||||
* | * | ||||
* Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or | * Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or | ||||
* shorter than the requested interval. | * shorter than the requested interval. | ||||
*/ | */ | ||||
extern JS_PUBLIC_API(void) | extern JS_PUBLIC_API(void) | ||||
IncrementalGCSlice(JSRuntime* rt, gcreason::Reason reason, int64_t millis = 0); | IncrementalGCSlice(JSContext* cx, gcreason::Reason reason, int64_t millis = 0); | ||||
/** | /** | ||||
* If IsIncrementalGCInProgress(rt), this call finishes the ongoing collection | * If IsIncrementalGCInProgress(cx), this call finishes the ongoing collection | ||||
* by performing an arbitrarily long slice. If !IsIncrementalGCInProgress(rt), | * by performing an arbitrarily long slice. If !IsIncrementalGCInProgress(cx), | ||||
* this is equivalent to GCForReason. When this function returns, | * this is equivalent to GCForReason. When this function returns, | ||||
* IsIncrementalGCInProgress(rt) will always be false. | * IsIncrementalGCInProgress(cx) will always be false. | ||||
*/ | */ | ||||
extern JS_PUBLIC_API(void) | extern JS_PUBLIC_API(void) | ||||
FinishIncrementalGC(JSRuntime* rt, gcreason::Reason reason); | FinishIncrementalGC(JSContext* cx, gcreason::Reason reason); | ||||
/** | /** | ||||
* If IsIncrementalGCInProgress(rt), this call aborts the ongoing collection and | * If IsIncrementalGCInProgress(cx), this call aborts the ongoing collection and | ||||
* performs whatever work needs to be done to return the collector to its idle | * performs whatever work needs to be done to return the collector to its idle | ||||
* state. This may take an arbitrarily long time. When this function returns, | * state. This may take an arbitrarily long time. When this function returns, | ||||
* IsIncrementalGCInProgress(rt) will always be false. | * IsIncrementalGCInProgress(cx) will always be false. | ||||
*/ | */ | ||||
extern JS_PUBLIC_API(void) | extern JS_PUBLIC_API(void) | ||||
AbortIncrementalGC(JSRuntime* rt); | AbortIncrementalGC(JSContext* cx); | ||||
namespace dbg { | namespace dbg { | ||||
// The `JS::dbg::GarbageCollectionEvent` class is essentially a view of the | // The `JS::dbg::GarbageCollectionEvent` class is essentially a view of the | ||||
// `js::gcstats::Statistics` data without the uber implementation-specific bits. | // `js::gcstats::Statistics` data without the uber implementation-specific bits. | ||||
// It should generally be palatable for web developers. | // It should generally be palatable for web developers. | ||||
class GarbageCollectionEvent | class GarbageCollectionEvent | ||||
{ | { | ||||
Show All 25 Lines | class GarbageCollectionEvent | ||||
public: | public: | ||||
explicit GarbageCollectionEvent(uint64_t majorGCNum) | explicit GarbageCollectionEvent(uint64_t majorGCNum) | ||||
: majorGCNumber_(majorGCNum) | : majorGCNumber_(majorGCNum) | ||||
, reason(nullptr) | , reason(nullptr) | ||||
, nonincrementalReason(nullptr) | , nonincrementalReason(nullptr) | ||||
, collections() | , collections() | ||||
{ } | { } | ||||
using Ptr = UniquePtr<GarbageCollectionEvent, DeletePolicy<GarbageCollectionEvent>>; | using Ptr = js::UniquePtr<GarbageCollectionEvent>; | ||||
static Ptr Create(JSRuntime* rt, ::js::gcstats::Statistics& stats, uint64_t majorGCNumber); | static Ptr Create(JSRuntime* rt, ::js::gcstats::Statistics& stats, uint64_t majorGCNumber); | ||||
JSObject* toJSObject(JSContext* cx) const; | JSObject* toJSObject(JSContext* cx) const; | ||||
uint64_t majorGCNumber() const { return majorGCNumber_; } | uint64_t majorGCNumber() const { return majorGCNumber_; } | ||||
}; | }; | ||||
} // namespace dbg | } // namespace dbg | ||||
Show All 11 Lines | enum GCProgress { | ||||
GC_CYCLE_BEGIN, | GC_CYCLE_BEGIN, | ||||
GC_SLICE_BEGIN, | GC_SLICE_BEGIN, | ||||
GC_SLICE_END, | GC_SLICE_END, | ||||
GC_CYCLE_END | GC_CYCLE_END | ||||
}; | }; | ||||
struct JS_PUBLIC_API(GCDescription) { | struct JS_PUBLIC_API(GCDescription) { | ||||
bool isCompartment_; | bool isZone_; | ||||
JSGCInvocationKind invocationKind_; | JSGCInvocationKind invocationKind_; | ||||
gcreason::Reason reason_; | gcreason::Reason reason_; | ||||
GCDescription(bool isCompartment, JSGCInvocationKind kind, gcreason::Reason reason) | GCDescription(bool isZone, JSGCInvocationKind kind, gcreason::Reason reason) | ||||
: isCompartment_(isCompartment), invocationKind_(kind), reason_(reason) {} | : isZone_(isZone), invocationKind_(kind), reason_(reason) {} | ||||
char16_t* formatSliceMessage(JSRuntime* rt) const; | char16_t* formatSliceMessage(JSContext* cx) const; | ||||
char16_t* formatSummaryMessage(JSRuntime* rt) const; | char16_t* formatSummaryMessage(JSContext* cx) const; | ||||
char16_t* formatJSON(JSRuntime* rt, uint64_t timestamp) const; | char16_t* formatJSON(JSContext* cx, uint64_t timestamp) const; | ||||
JS::dbg::GarbageCollectionEvent::Ptr toGCEvent(JSRuntime* rt) const; | JS::dbg::GarbageCollectionEvent::Ptr toGCEvent(JSContext* cx) const; | ||||
}; | }; | ||||
typedef void | typedef void | ||||
(* GCSliceCallback)(JSRuntime* rt, GCProgress progress, const GCDescription& desc); | (* GCSliceCallback)(JSContext* cx, GCProgress progress, const GCDescription& desc); | ||||
/** | /** | ||||
* The GC slice callback is called at the beginning and end of each slice. This | * The GC slice callback is called at the beginning and end of each slice. This | ||||
* callback may be used for GC notifications as well as to perform additional | * callback may be used for GC notifications as well as to perform additional | ||||
* marking. | * marking. | ||||
*/ | */ | ||||
extern JS_PUBLIC_API(GCSliceCallback) | extern JS_PUBLIC_API(GCSliceCallback) | ||||
SetGCSliceCallback(JSRuntime* rt, GCSliceCallback callback); | SetGCSliceCallback(JSContext* cx, GCSliceCallback callback); | ||||
/** | |||||
* Describes the progress of an observed nursery collection. | |||||
*/ | |||||
enum class GCNurseryProgress { | |||||
/** | |||||
* The nursery collection is starting. | |||||
*/ | |||||
GC_NURSERY_COLLECTION_START, | |||||
/** | |||||
* The nursery collection is ending. | |||||
*/ | |||||
GC_NURSERY_COLLECTION_END | |||||
}; | |||||
/** | |||||
* A nursery collection callback receives the progress of the nursery collection | |||||
* and the reason for the collection. | |||||
*/ | |||||
using GCNurseryCollectionCallback = void(*)(JSContext* cx, GCNurseryProgress progress, | |||||
gcreason::Reason reason); | |||||
/** | |||||
* Set the nursery collection callback for the given runtime. When set, it will | |||||
* be called at the start and end of every nursery collection. | |||||
*/ | |||||
extern JS_PUBLIC_API(GCNurseryCollectionCallback) | |||||
SetGCNurseryCollectionCallback(JSContext* cx, GCNurseryCollectionCallback callback); | |||||
typedef void | |||||
(* DoCycleCollectionCallback)(JSContext* cx); | |||||
/** | |||||
* The purge gray callback is called after any COMPARTMENT_REVIVED GC in which | |||||
* the majority of compartments have been marked gray. | |||||
*/ | |||||
extern JS_PUBLIC_API(DoCycleCollectionCallback) | |||||
SetDoCycleCollectionCallback(JSContext* cx, DoCycleCollectionCallback callback); | |||||
/** | /** | ||||
* Incremental GC defaults to enabled, but may be disabled for testing or in | * Incremental GC defaults to enabled, but may be disabled for testing or in | ||||
* embeddings that have not yet implemented barriers on their native classes. | * embeddings that have not yet implemented barriers on their native classes. | ||||
* There is not currently a way to re-enable incremental GC once it has been | * There is not currently a way to re-enable incremental GC once it has been | ||||
* disabled on the runtime. | * disabled on the runtime. | ||||
*/ | */ | ||||
extern JS_PUBLIC_API(void) | extern JS_PUBLIC_API(void) | ||||
DisableIncrementalGC(JSRuntime* rt); | DisableIncrementalGC(JSContext* cx); | ||||
/** | /** | ||||
* Returns true if incremental GC is enabled. Simply having incremental GC | * Returns true if incremental GC is enabled. Simply having incremental GC | ||||
* enabled is not sufficient to ensure incremental collections are happening. | * enabled is not sufficient to ensure incremental collections are happening. | ||||
* See the comment "Incremental GC" above for reasons why incremental GC may be | * See the comment "Incremental GC" above for reasons why incremental GC may be | ||||
* suppressed. Inspection of the "nonincremental reason" field of the | * suppressed. Inspection of the "nonincremental reason" field of the | ||||
* GCDescription returned by GCSliceCallback may help narrow down the cause if | * GCDescription returned by GCSliceCallback may help narrow down the cause if | ||||
* collections are not happening incrementally when expected. | * collections are not happening incrementally when expected. | ||||
*/ | */ | ||||
extern JS_PUBLIC_API(bool) | extern JS_PUBLIC_API(bool) | ||||
IsIncrementalGCEnabled(JSRuntime* rt); | IsIncrementalGCEnabled(JSContext* cx); | ||||
/** | /** | ||||
* Returns true while an incremental GC is ongoing, both when actively | * Returns true while an incremental GC is ongoing, both when actively | ||||
* collecting and between slices. | * collecting and between slices. | ||||
*/ | */ | ||||
extern JS_PUBLIC_API(bool) | extern JS_PUBLIC_API(bool) | ||||
IsIncrementalGCInProgress(JSRuntime* rt); | IsIncrementalGCInProgress(JSContext* cx); | ||||
/* | /* | ||||
* Returns true when writes to GC things must call an incremental (pre) barrier. | * Returns true when writes to GC things must call an incremental (pre) barrier. | ||||
* This is generally only true when running mutator code in-between GC slices. | * This is generally only true when running mutator code in-between GC slices. | ||||
* At other times, the barrier may be elided for performance. | * At other times, the barrier may be elided for performance. | ||||
*/ | */ | ||||
extern JS_PUBLIC_API(bool) | extern JS_PUBLIC_API(bool) | ||||
IsIncrementalBarrierNeeded(JSRuntime* rt); | |||||
extern JS_PUBLIC_API(bool) | |||||
IsIncrementalBarrierNeeded(JSContext* cx); | IsIncrementalBarrierNeeded(JSContext* cx); | ||||
/* | /* | ||||
* Notify the GC that a reference to a GC thing is about to be overwritten. | * Notify the GC that a reference to a GC thing is about to be overwritten. | ||||
* These methods must be called if IsIncrementalBarrierNeeded. | * These methods must be called if IsIncrementalBarrierNeeded. | ||||
*/ | */ | ||||
extern JS_PUBLIC_API(void) | extern JS_PUBLIC_API(void) | ||||
IncrementalReferenceBarrier(GCCellPtr thing); | IncrementalReferenceBarrier(GCCellPtr thing); | ||||
extern JS_PUBLIC_API(void) | extern JS_PUBLIC_API(void) | ||||
IncrementalValueBarrier(const Value& v); | IncrementalValueBarrier(const Value& v); | ||||
extern JS_PUBLIC_API(void) | extern JS_PUBLIC_API(void) | ||||
IncrementalObjectBarrier(JSObject* obj); | IncrementalObjectBarrier(JSObject* obj); | ||||
/** | /** | ||||
* Returns true if the most recent GC ran incrementally. | * Returns true if the most recent GC ran incrementally. | ||||
*/ | */ | ||||
extern JS_PUBLIC_API(bool) | extern JS_PUBLIC_API(bool) | ||||
WasIncrementalGC(JSRuntime* rt); | WasIncrementalGC(JSContext* cx); | ||||
/* | /* | ||||
* Generational GC: | * Generational GC: | ||||
* | * | ||||
* Note: Generational GC is not yet enabled by default. The following class | * Note: Generational GC is not yet enabled by default. The following class | ||||
* is non-functional unless SpiderMonkey was configured with | * is non-functional unless SpiderMonkey was configured with | ||||
* --enable-gcgenerational. | * --enable-gcgenerational. | ||||
*/ | */ | ||||
Show All 19 Lines | |||||
* Returns the GC's "number". This does not correspond directly to the number | * Returns the GC's "number". This does not correspond directly to the number | ||||
* of GCs that have been run, but is guaranteed to be monotonically increasing | * of GCs that have been run, but is guaranteed to be monotonically increasing | ||||
* with GC activity. | * with GC activity. | ||||
*/ | */ | ||||
extern JS_PUBLIC_API(size_t) | extern JS_PUBLIC_API(size_t) | ||||
GetGCNumber(); | GetGCNumber(); | ||||
/** | /** | ||||
* The GC does not immediately return the unused memory freed by a collection | * Pass a subclass of this "abstract" class to callees to require that they | ||||
* back to the system incase it is needed soon afterwards. This call forces the | * never GC. Subclasses can use assertions or the hazard analysis to ensure no | ||||
* GC to return this memory immediately. | * GC happens. | ||||
*/ | */ | ||||
extern JS_PUBLIC_API(void) | class JS_PUBLIC_API(AutoRequireNoGC) | ||||
ShrinkGCBuffers(JSRuntime* rt); | { | ||||
protected: | |||||
AutoRequireNoGC() {} | |||||
~AutoRequireNoGC() {} | |||||
}; | |||||
/** | /** | ||||
* Assert if a GC occurs while this class is live. This class does not disable | * Diagnostic assert (see MOZ_DIAGNOSTIC_ASSERT) that GC cannot occur while this | ||||
* the static rooting hazard analysis. | * class is live. This class does not disable the static rooting hazard | ||||
* analysis. | |||||
* | |||||
* This works by entering a GC unsafe region, which is checked on allocation and | |||||
* on GC. | |||||
*/ | */ | ||||
class JS_PUBLIC_API(AutoAssertOnGC) | class JS_PUBLIC_API(AutoAssertNoGC) : public AutoRequireNoGC | ||||
{ | { | ||||
#ifdef DEBUG | |||||
js::gc::GCRuntime* gc; | js::gc::GCRuntime* gc; | ||||
size_t gcNumber; | size_t gcNumber; | ||||
public: | public: | ||||
AutoAssertOnGC(); | AutoAssertNoGC(); | ||||
explicit AutoAssertOnGC(JSRuntime* rt); | explicit AutoAssertNoGC(JSRuntime* rt); | ||||
~AutoAssertOnGC(); | explicit AutoAssertNoGC(JSContext* cx); | ||||
~AutoAssertNoGC(); | |||||
static void VerifyIsSafeToGC(JSRuntime* rt); | |||||
#else | |||||
public: | |||||
AutoAssertOnGC() {} | |||||
explicit AutoAssertOnGC(JSRuntime* rt) {} | |||||
~AutoAssertOnGC() {} | |||||
static void VerifyIsSafeToGC(JSRuntime* rt) {} | |||||
#endif | |||||
}; | }; | ||||
/** | /** | ||||
* Assert if an allocation of a GC thing occurs while this class is live. This | * Assert if an allocation of a GC thing occurs while this class is live. This | ||||
* class does not disable the static rooting hazard analysis. | * class does not disable the static rooting hazard analysis. | ||||
*/ | */ | ||||
class JS_PUBLIC_API(AutoAssertNoAlloc) | class JS_PUBLIC_API(AutoAssertNoAlloc) | ||||
{ | { | ||||
#ifdef JS_DEBUG | #ifdef JS_DEBUG | ||||
js::gc::GCRuntime* gc; | js::gc::GCRuntime* gc; | ||||
public: | public: | ||||
AutoAssertNoAlloc() : gc(nullptr) {} | AutoAssertNoAlloc() : gc(nullptr) {} | ||||
explicit AutoAssertNoAlloc(JSRuntime* rt); | explicit AutoAssertNoAlloc(JSContext* cx); | ||||
void disallowAlloc(JSRuntime* rt); | void disallowAlloc(JSRuntime* rt); | ||||
~AutoAssertNoAlloc(); | ~AutoAssertNoAlloc(); | ||||
#else | #else | ||||
public: | public: | ||||
AutoAssertNoAlloc() {} | AutoAssertNoAlloc() {} | ||||
explicit AutoAssertNoAlloc(JSRuntime* rt) {} | explicit AutoAssertNoAlloc(JSContext* cx) {} | ||||
void disallowAlloc(JSRuntime* rt) {} | void disallowAlloc(JSRuntime* rt) {} | ||||
#endif | #endif | ||||
}; | }; | ||||
/** | /** | ||||
* Assert if a GC barrier is invoked while this class is live. This class does | |||||
* not disable the static rooting hazard analysis. | |||||
*/ | |||||
class JS_PUBLIC_API(AutoAssertOnBarrier) | |||||
{ | |||||
JSContext* context; | |||||
bool prev; | |||||
public: | |||||
explicit AutoAssertOnBarrier(JSContext* cx); | |||||
~AutoAssertOnBarrier(); | |||||
}; | |||||
/** | |||||
* Disable the static rooting hazard analysis in the live region and assert if | * Disable the static rooting hazard analysis in the live region and assert if | ||||
* any allocation that could potentially trigger a GC occurs while this guard | * any allocation that could potentially trigger a GC occurs while this guard | ||||
* object is live. This is most useful to help the exact rooting hazard analysis | * object is live. This is most useful to help the exact rooting hazard analysis | ||||
* in complex regions, since it cannot understand dataflow. | * in complex regions, since it cannot understand dataflow. | ||||
* | * | ||||
* Note: GC behavior is unpredictable even when deterministic and is generally | * Note: GC behavior is unpredictable even when deterministic and is generally | ||||
* non-deterministic in practice. The fact that this guard has not | * non-deterministic in practice. The fact that this guard has not | ||||
* asserted is not a guarantee that a GC cannot happen in the guarded | * asserted is not a guarantee that a GC cannot happen in the guarded | ||||
* region. As a rule, anyone performing a GC unsafe action should | * region. As a rule, anyone performing a GC unsafe action should | ||||
* understand the GC properties of all code in that region and ensure | * understand the GC properties of all code in that region and ensure | ||||
* that the hazard analysis is correct for that code, rather than relying | * that the hazard analysis is correct for that code, rather than relying | ||||
* on this class. | * on this class. | ||||
*/ | */ | ||||
class JS_PUBLIC_API(AutoSuppressGCAnalysis) : public AutoAssertNoAlloc | class JS_PUBLIC_API(AutoSuppressGCAnalysis) : public AutoAssertNoAlloc | ||||
{ | { | ||||
public: | public: | ||||
AutoSuppressGCAnalysis() : AutoAssertNoAlloc() {} | AutoSuppressGCAnalysis() : AutoAssertNoAlloc() {} | ||||
explicit AutoSuppressGCAnalysis(JSRuntime* rt) : AutoAssertNoAlloc(rt) {} | explicit AutoSuppressGCAnalysis(JSContext* cx) : AutoAssertNoAlloc(cx) {} | ||||
}; | } JS_HAZ_GC_SUPPRESSED; | ||||
/** | /** | ||||
* Assert that code is only ever called from a GC callback, disable the static | * Assert that code is only ever called from a GC callback, disable the static | ||||
* rooting hazard analysis and assert if any allocation that could potentially | * rooting hazard analysis and assert if any allocation that could potentially | ||||
* trigger a GC occurs while this guard object is live. | * trigger a GC occurs while this guard object is live. | ||||
* | * | ||||
* This is useful to make the static analysis ignore code that runs in GC | * This is useful to make the static analysis ignore code that runs in GC | ||||
* callbacks. | * callbacks. | ||||
*/ | */ | ||||
class JS_PUBLIC_API(AutoAssertGCCallback) : public AutoSuppressGCAnalysis | class JS_PUBLIC_API(AutoAssertGCCallback) : public AutoSuppressGCAnalysis | ||||
{ | { | ||||
public: | public: | ||||
explicit AutoAssertGCCallback(JSObject* obj); | explicit AutoAssertGCCallback(JSObject* obj); | ||||
}; | }; | ||||
/** | /** | ||||
* Place AutoCheckCannotGC in scopes that you believe can never GC. These | * Place AutoCheckCannotGC in scopes that you believe can never GC. These | ||||
* annotations will be verified both dynamically via AutoAssertOnGC, and | * annotations will be verified both dynamically via AutoAssertNoGC, and | ||||
* statically with the rooting hazard analysis (implemented by making the | * statically with the rooting hazard analysis (implemented by making the | ||||
* analysis consider AutoCheckCannotGC to be a GC pointer, and therefore | * analysis consider AutoCheckCannotGC to be a GC pointer, and therefore | ||||
* complain if it is live across a GC call.) It is useful when dealing with | * complain if it is live across a GC call.) It is useful when dealing with | ||||
* internal pointers to GC things where the GC thing itself may not be present | * internal pointers to GC things where the GC thing itself may not be present | ||||
* for the static analysis: e.g. acquiring inline chars from a JSString* on the | * for the static analysis: e.g. acquiring inline chars from a JSString* on the | ||||
* heap. | * heap. | ||||
* | |||||
* We only do the assertion checking in DEBUG builds. | |||||
*/ | */ | ||||
class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoAssertOnGC | #ifdef DEBUG | ||||
class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoAssertNoGC | |||||
{ | { | ||||
public: | public: | ||||
AutoCheckCannotGC() : AutoAssertOnGC() {} | AutoCheckCannotGC() : AutoAssertNoGC() {} | ||||
explicit AutoCheckCannotGC(JSRuntime* rt) : AutoAssertOnGC(rt) {} | explicit AutoCheckCannotGC(JSContext* cx) : AutoAssertNoGC(cx) {} | ||||
}; | } JS_HAZ_GC_INVALIDATED; | ||||
#else | |||||
class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoRequireNoGC | |||||
{ | |||||
public: | |||||
AutoCheckCannotGC() {} | |||||
explicit AutoCheckCannotGC(JSContext* cx) {} | |||||
} JS_HAZ_GC_INVALIDATED; | |||||
#endif | |||||
/** | /** | ||||
* Unsets the gray bit for anything reachable from |thing|. |kind| should not be | * Unsets the gray bit for anything reachable from |thing|. |kind| should not be | ||||
* JS::TraceKind::Shape. |thing| should be non-null. | * JS::TraceKind::Shape. |thing| should be non-null. The return value indicates | ||||
* if anything was unmarked. | |||||
*/ | */ | ||||
extern JS_FRIEND_API(bool) | extern JS_FRIEND_API(bool) | ||||
UnmarkGrayGCThingRecursively(GCCellPtr thing); | UnmarkGrayGCThingRecursively(GCCellPtr thing); | ||||
} /* namespace JS */ | } /* namespace JS */ | ||||
namespace js { | namespace js { | ||||
namespace gc { | namespace gc { | ||||
static MOZ_ALWAYS_INLINE void | static MOZ_ALWAYS_INLINE void | ||||
ExposeGCThingToActiveJS(JS::GCCellPtr thing) | ExposeGCThingToActiveJS(JS::GCCellPtr thing) | ||||
{ | { | ||||
MOZ_ASSERT(thing.kind() != JS::TraceKind::Shape); | // GC things residing in the nursery cannot be gray: they have no mark bits. | ||||
// All live objects in the nursery are moved to tenured at the beginning of | |||||
/* | // each GC slice, so the gray marker never sees nursery things. | ||||
* GC things residing in the nursery cannot be gray: they have no mark bits. | |||||
* All live objects in the nursery are moved to tenured at the beginning of | |||||
* each GC slice, so the gray marker never sees nursery things. | |||||
*/ | |||||
if (IsInsideNursery(thing.asCell())) | if (IsInsideNursery(thing.asCell())) | ||||
return; | return; | ||||
JS::shadow::Runtime* rt = detail::GetGCThingRuntime(thing.unsafeAsUIntPtr()); | |||||
// There's nothing to do for permanent GC things that might be owned by | |||||
// another runtime. | |||||
if (thing.mayBeOwnedByOtherRuntime()) | |||||
return; | |||||
JS::shadow::Runtime* rt = detail::GetCellRuntime(thing.asCell()); | |||||
MOZ_DIAGNOSTIC_ASSERT(rt->allowGCBarriers()); | |||||
if (IsIncrementalBarrierNeededOnTenuredGCThing(rt, thing)) | if (IsIncrementalBarrierNeededOnTenuredGCThing(rt, thing)) | ||||
JS::IncrementalReferenceBarrier(thing); | JS::IncrementalReferenceBarrier(thing); | ||||
else if (JS::GCThingIsMarkedGray(thing)) | else if (!thing.mayBeOwnedByOtherRuntime() && js::gc::detail::CellIsMarkedGray(thing.asCell())) | ||||
JS::UnmarkGrayGCThingRecursively(thing); | JS::UnmarkGrayGCThingRecursively(thing); | ||||
} | } | ||||
static MOZ_ALWAYS_INLINE void | static MOZ_ALWAYS_INLINE void | ||||
MarkGCThingAsLive(JSRuntime* aRt, JS::GCCellPtr thing) | MarkGCThingAsLive(JSRuntime* aRt, JS::GCCellPtr thing) | ||||
{ | { | ||||
JS::shadow::Runtime* rt = JS::shadow::Runtime::asShadowRuntime(aRt); | // Any object in the nursery will not be freed during any GC running at that | ||||
/* | // time. | ||||
* Any object in the nursery will not be freed during any GC running at that time. | |||||
*/ | |||||
if (IsInsideNursery(thing.asCell())) | if (IsInsideNursery(thing.asCell())) | ||||
return; | return; | ||||
// There's nothing to do for permanent GC things that might be owned by | |||||
// another runtime. | |||||
if (thing.mayBeOwnedByOtherRuntime()) | |||||
return; | |||||
JS::shadow::Runtime* rt = JS::shadow::Runtime::asShadowRuntime(aRt); | |||||
MOZ_DIAGNOSTIC_ASSERT(rt->allowGCBarriers()); | |||||
if (IsIncrementalBarrierNeededOnTenuredGCThing(rt, thing)) | if (IsIncrementalBarrierNeededOnTenuredGCThing(rt, thing)) | ||||
JS::IncrementalReferenceBarrier(thing); | JS::IncrementalReferenceBarrier(thing); | ||||
} | } | ||||
} /* namespace gc */ | } /* namespace gc */ | ||||
} /* namespace js */ | } /* namespace js */ | ||||
namespace JS { | namespace JS { | ||||
/* | /* | ||||
* This should be called when an object that is marked gray is exposed to the JS | * This should be called when an object that is marked gray is exposed to the JS | ||||
* engine (by handing it to running JS code or writing it into live JS | * engine (by handing it to running JS code or writing it into live JS | ||||
* data). During incremental GC, since the gray bits haven't been computed yet, | * data). During incremental GC, since the gray bits haven't been computed yet, | ||||
* we conservatively mark the object black. | * we conservatively mark the object black. | ||||
*/ | */ | ||||
static MOZ_ALWAYS_INLINE void | static MOZ_ALWAYS_INLINE void | ||||
ExposeObjectToActiveJS(JSObject* obj) | ExposeObjectToActiveJS(JSObject* obj) | ||||
{ | { | ||||
MOZ_ASSERT(obj); | |||||
js::gc::ExposeGCThingToActiveJS(GCCellPtr(obj)); | js::gc::ExposeGCThingToActiveJS(GCCellPtr(obj)); | ||||
} | } | ||||
static MOZ_ALWAYS_INLINE void | static MOZ_ALWAYS_INLINE void | ||||
ExposeScriptToActiveJS(JSScript* script) | ExposeScriptToActiveJS(JSScript* script) | ||||
{ | { | ||||
js::gc::ExposeGCThingToActiveJS(GCCellPtr(script)); | js::gc::ExposeGCThingToActiveJS(GCCellPtr(script)); | ||||
} | } | ||||
Show All 9 Lines | |||||
} | } | ||||
/* | /* | ||||
* Internal to Firefox. | * Internal to Firefox. | ||||
* | * | ||||
* Note: this is not related to the PokeGC in nsJSEnvironment. | * Note: this is not related to the PokeGC in nsJSEnvironment. | ||||
*/ | */ | ||||
extern JS_FRIEND_API(void) | extern JS_FRIEND_API(void) | ||||
PokeGC(JSRuntime* rt); | PokeGC(JSContext* cx); | ||||
/* | /* | ||||
* Internal to Firefox. | * Internal to Firefox. | ||||
*/ | */ | ||||
extern JS_FRIEND_API(void) | extern JS_FRIEND_API(void) | ||||
NotifyDidPaint(JSRuntime* rt); | NotifyDidPaint(JSContext* cx); | ||||
} /* namespace JS */ | } /* namespace JS */ | ||||
#endif /* js_GCAPI_h */ | #endif /* js_GCAPI_h */ |
Wildfire Games · Phabricator