mirror of
https://github.com/smallmain/cocos-enhance-kit.git
synced 2025-11-10 15:15:24 +00:00
补充某些必要的文件
This commit is contained in:
723
cocos2d-x/external/mac/include/spidermonkey/js/GCAPI.h
vendored
Normal file
723
cocos2d-x/external/mac/include/spidermonkey/js/GCAPI.h
vendored
Normal file
@@ -0,0 +1,723 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* 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
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef js_GCAPI_h
|
||||
#define js_GCAPI_h
|
||||
|
||||
#include "mozilla/Vector.h"
|
||||
|
||||
#include "js/GCAnnotations.h"
|
||||
#include "js/HeapAPI.h"
|
||||
#include "js/UniquePtr.h"
|
||||
|
||||
namespace js {
|
||||
namespace gc {
|
||||
class GCRuntime;
|
||||
} // namespace gc
|
||||
namespace gcstats {
|
||||
struct Statistics;
|
||||
} // namespace gcstats
|
||||
} // namespace js
|
||||
|
||||
typedef enum JSGCMode {
|
||||
/** Perform only global GCs. */
|
||||
JSGC_MODE_GLOBAL = 0,
|
||||
|
||||
/** Perform per-zone GCs until too much garbage has accumulated. */
|
||||
JSGC_MODE_ZONE = 1,
|
||||
|
||||
/**
|
||||
* Collect in short time slices rather than all at once. Implies
|
||||
* JSGC_MODE_ZONE.
|
||||
*/
|
||||
JSGC_MODE_INCREMENTAL = 2
|
||||
} JSGCMode;
|
||||
|
||||
/**
|
||||
* Kinds of js_GC invocation.
|
||||
*/
|
||||
typedef enum JSGCInvocationKind {
|
||||
/* Normal invocation. */
|
||||
GC_NORMAL = 0,
|
||||
|
||||
/* Minimize GC triggers and release empty GC chunks right away. */
|
||||
GC_SHRINK = 1
|
||||
} JSGCInvocationKind;
|
||||
|
||||
namespace JS {
|
||||
|
||||
#define GCREASONS(D) \
|
||||
/* Reasons internal to the JS engine */ \
|
||||
D(API) \
|
||||
D(EAGER_ALLOC_TRIGGER) \
|
||||
D(DESTROY_RUNTIME) \
|
||||
D(UNUSED0) \
|
||||
D(LAST_DITCH) \
|
||||
D(TOO_MUCH_MALLOC) \
|
||||
D(ALLOC_TRIGGER) \
|
||||
D(DEBUG_GC) \
|
||||
D(COMPARTMENT_REVIVED) \
|
||||
D(RESET) \
|
||||
D(OUT_OF_NURSERY) \
|
||||
D(EVICT_NURSERY) \
|
||||
D(FULL_STORE_BUFFER) \
|
||||
D(SHARED_MEMORY_LIMIT) \
|
||||
D(UNUSED1) \
|
||||
D(INCREMENTAL_TOO_SLOW) \
|
||||
D(ABORT_GC) \
|
||||
\
|
||||
/* These are reserved for future use. */ \
|
||||
D(RESERVED0) \
|
||||
D(RESERVED1) \
|
||||
D(RESERVED2) \
|
||||
D(RESERVED3) \
|
||||
D(RESERVED4) \
|
||||
D(RESERVED5) \
|
||||
D(RESERVED6) \
|
||||
D(RESERVED7) \
|
||||
D(RESERVED8) \
|
||||
D(RESERVED9) \
|
||||
D(RESERVED10) \
|
||||
D(RESERVED11) \
|
||||
D(RESERVED12) \
|
||||
D(RESERVED13) \
|
||||
D(RESERVED14) \
|
||||
D(RESERVED15) \
|
||||
\
|
||||
/* Reasons from Firefox */ \
|
||||
D(DOM_WINDOW_UTILS) \
|
||||
D(COMPONENT_UTILS) \
|
||||
D(MEM_PRESSURE) \
|
||||
D(CC_WAITING) \
|
||||
D(CC_FORCED) \
|
||||
D(LOAD_END) \
|
||||
D(POST_COMPARTMENT) \
|
||||
D(PAGE_HIDE) \
|
||||
D(NSJSCONTEXT_DESTROY) \
|
||||
D(SET_NEW_DOCUMENT) \
|
||||
D(SET_DOC_SHELL) \
|
||||
D(DOM_UTILS) \
|
||||
D(DOM_IPC) \
|
||||
D(DOM_WORKER) \
|
||||
D(INTER_SLICE_GC) \
|
||||
D(REFRESH_FRAME) \
|
||||
D(FULL_GC_TIMER) \
|
||||
D(SHUTDOWN_CC) \
|
||||
D(FINISH_LARGE_EVALUATE) \
|
||||
D(USER_INACTIVE) \
|
||||
D(XPCONNECT_SHUTDOWN)
|
||||
|
||||
namespace gcreason {
|
||||
|
||||
/* GCReasons will end up looking like JSGC_MAYBEGC */
|
||||
enum Reason {
|
||||
#define MAKE_REASON(name) name,
|
||||
GCREASONS(MAKE_REASON)
|
||||
#undef MAKE_REASON
|
||||
NO_REASON,
|
||||
NUM_REASONS,
|
||||
|
||||
/*
|
||||
* 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
|
||||
* there are 52. But the cost of extra buckets seems to be low while the
|
||||
* cost of switching histograms is high.
|
||||
*/
|
||||
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 */
|
||||
|
||||
/*
|
||||
* Zone GC:
|
||||
*
|
||||
* 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
|
||||
* collection time by only collecting zones that have run code recently,
|
||||
* ignoring the parts of the heap that are unlikely to have changed.
|
||||
*
|
||||
* When triggering a GC using one of the functions below, it is first necessary
|
||||
* to select the zones to be collected. To do this, you can call
|
||||
* PrepareZoneForGC on each zone, or you can call PrepareForFullGC to select
|
||||
* all zones. Failing to select any zone is an error.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Schedule the given zone to be collected as part of the next GC.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
PrepareZoneForGC(Zone* zone);
|
||||
|
||||
/**
|
||||
* Schedule all zones to be collected in the next GC.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
PrepareForFullGC(JSContext* cx);
|
||||
|
||||
/**
|
||||
* When performing an incremental GC, the zones that were selected for the
|
||||
* previous incremental slice must be selected in subsequent slices as well.
|
||||
* This function selects those slices automatically.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
PrepareForIncrementalGC(JSContext* cx);
|
||||
|
||||
/**
|
||||
* Returns true if any zone in the system has been scheduled for GC with one of
|
||||
* the functions above or by the JS engine.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
IsGCScheduled(JSContext* cx);
|
||||
|
||||
/**
|
||||
* Undoes the effect of the Prepare methods above. The given zone will not be
|
||||
* collected in the next GC.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
SkipZoneForGC(Zone* zone);
|
||||
|
||||
/*
|
||||
* Non-Incremental GC:
|
||||
*
|
||||
* The following functions perform a non-incremental GC.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Performs a non-incremental collection of all selected zones.
|
||||
*
|
||||
* If the gckind argument is GC_NORMAL, then some objects that are unreachable
|
||||
* from the program may still be alive afterwards because of internal
|
||||
* 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
|
||||
* the system.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
GCForReason(JSContext* cx, JSGCInvocationKind gckind, gcreason::Reason reason);
|
||||
|
||||
/*
|
||||
* Incremental GC:
|
||||
*
|
||||
* Incremental GC divides the full mark-and-sweep collection into multiple
|
||||
* slices, allowing client JavaScript code to run between each slice. This
|
||||
* 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
|
||||
* the pauses are less noticable.
|
||||
*
|
||||
* For a collection to be carried out incrementally the following conditions
|
||||
* must be met:
|
||||
* - The collection must be run by calling JS::IncrementalGC() rather than
|
||||
* JS_GC().
|
||||
* - The GC mode must have been set to JSGC_MODE_INCREMENTAL with
|
||||
* JS_SetGCParameter().
|
||||
*
|
||||
* Note: Even if incremental GC is enabled and working correctly,
|
||||
* non-incremental collections can still happen when low on memory.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Begin an incremental collection and perform one slice worth of work. When
|
||||
* this function returns, the collection may not be complete.
|
||||
* IncrementalGCSlice() must be called repeatedly until
|
||||
* !IsIncrementalGCInProgress(cx).
|
||||
*
|
||||
* Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or
|
||||
* shorter than the requested interval.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
StartIncrementalGC(JSContext* cx, JSGCInvocationKind gckind, gcreason::Reason reason,
|
||||
int64_t millis = 0);
|
||||
|
||||
/**
|
||||
* Perform a slice of an ongoing incremental collection. When this function
|
||||
* returns, the collection may not be complete. It must be called repeatedly
|
||||
* until !IsIncrementalGCInProgress(cx).
|
||||
*
|
||||
* Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or
|
||||
* shorter than the requested interval.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
IncrementalGCSlice(JSContext* cx, gcreason::Reason reason, int64_t millis = 0);
|
||||
|
||||
/**
|
||||
* If IsIncrementalGCInProgress(cx), this call finishes the ongoing collection
|
||||
* by performing an arbitrarily long slice. If !IsIncrementalGCInProgress(cx),
|
||||
* this is equivalent to GCForReason. When this function returns,
|
||||
* IsIncrementalGCInProgress(cx) will always be false.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
FinishIncrementalGC(JSContext* cx, gcreason::Reason reason);
|
||||
|
||||
/**
|
||||
* If IsIncrementalGCInProgress(cx), this call aborts the ongoing collection and
|
||||
* 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,
|
||||
* IsIncrementalGCInProgress(cx) will always be false.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
AbortIncrementalGC(JSContext* cx);
|
||||
|
||||
namespace dbg {
|
||||
|
||||
// The `JS::dbg::GarbageCollectionEvent` class is essentially a view of the
|
||||
// `js::gcstats::Statistics` data without the uber implementation-specific bits.
|
||||
// It should generally be palatable for web developers.
|
||||
class GarbageCollectionEvent
|
||||
{
|
||||
// The major GC number of the GC cycle this data pertains to.
|
||||
uint64_t majorGCNumber_;
|
||||
|
||||
// Reference to a non-owned, statically allocated C string. This is a very
|
||||
// short reason explaining why a GC was triggered.
|
||||
const char* reason;
|
||||
|
||||
// Reference to a nullable, non-owned, statically allocated C string. If the
|
||||
// collection was forced to be non-incremental, this is a short reason of
|
||||
// why the GC could not perform an incremental collection.
|
||||
const char* nonincrementalReason;
|
||||
|
||||
// Represents a single slice of a possibly multi-slice incremental garbage
|
||||
// collection.
|
||||
struct Collection {
|
||||
double startTimestamp;
|
||||
double endTimestamp;
|
||||
};
|
||||
|
||||
// The set of garbage collection slices that made up this GC cycle.
|
||||
mozilla::Vector<Collection> collections;
|
||||
|
||||
GarbageCollectionEvent(const GarbageCollectionEvent& rhs) = delete;
|
||||
GarbageCollectionEvent& operator=(const GarbageCollectionEvent& rhs) = delete;
|
||||
|
||||
public:
|
||||
explicit GarbageCollectionEvent(uint64_t majorGCNum)
|
||||
: majorGCNumber_(majorGCNum)
|
||||
, reason(nullptr)
|
||||
, nonincrementalReason(nullptr)
|
||||
, collections()
|
||||
{ }
|
||||
|
||||
using Ptr = js::UniquePtr<GarbageCollectionEvent>;
|
||||
static Ptr Create(JSRuntime* rt, ::js::gcstats::Statistics& stats, uint64_t majorGCNumber);
|
||||
|
||||
JSObject* toJSObject(JSContext* cx) const;
|
||||
|
||||
uint64_t majorGCNumber() const { return majorGCNumber_; }
|
||||
};
|
||||
|
||||
} // namespace dbg
|
||||
|
||||
enum GCProgress {
|
||||
/*
|
||||
* During non-incremental GC, the GC is bracketed by JSGC_CYCLE_BEGIN/END
|
||||
* callbacks. During an incremental GC, the sequence of callbacks is as
|
||||
* follows:
|
||||
* JSGC_CYCLE_BEGIN, JSGC_SLICE_END (first slice)
|
||||
* JSGC_SLICE_BEGIN, JSGC_SLICE_END (second slice)
|
||||
* ...
|
||||
* JSGC_SLICE_BEGIN, JSGC_CYCLE_END (last slice)
|
||||
*/
|
||||
|
||||
GC_CYCLE_BEGIN,
|
||||
GC_SLICE_BEGIN,
|
||||
GC_SLICE_END,
|
||||
GC_CYCLE_END
|
||||
};
|
||||
|
||||
struct JS_PUBLIC_API(GCDescription) {
|
||||
bool isZone_;
|
||||
JSGCInvocationKind invocationKind_;
|
||||
gcreason::Reason reason_;
|
||||
|
||||
GCDescription(bool isZone, JSGCInvocationKind kind, gcreason::Reason reason)
|
||||
: isZone_(isZone), invocationKind_(kind), reason_(reason) {}
|
||||
|
||||
char16_t* formatSliceMessage(JSContext* cx) const;
|
||||
char16_t* formatSummaryMessage(JSContext* cx) const;
|
||||
char16_t* formatJSON(JSContext* cx, uint64_t timestamp) const;
|
||||
|
||||
JS::dbg::GarbageCollectionEvent::Ptr toGCEvent(JSContext* cx) const;
|
||||
};
|
||||
|
||||
typedef void
|
||||
(* GCSliceCallback)(JSContext* cx, GCProgress progress, const GCDescription& desc);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* marking.
|
||||
*/
|
||||
extern JS_PUBLIC_API(GCSliceCallback)
|
||||
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
|
||||
* 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
|
||||
* disabled on the runtime.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
DisableIncrementalGC(JSContext* cx);
|
||||
|
||||
/**
|
||||
* Returns true if incremental GC is enabled. Simply having incremental GC
|
||||
* enabled is not sufficient to ensure incremental collections are happening.
|
||||
* See the comment "Incremental GC" above for reasons why incremental GC may be
|
||||
* suppressed. Inspection of the "nonincremental reason" field of the
|
||||
* GCDescription returned by GCSliceCallback may help narrow down the cause if
|
||||
* collections are not happening incrementally when expected.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
IsIncrementalGCEnabled(JSContext* cx);
|
||||
|
||||
/**
|
||||
* Returns true while an incremental GC is ongoing, both when actively
|
||||
* collecting and between slices.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
IsIncrementalGCInProgress(JSContext* cx);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* At other times, the barrier may be elided for performance.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
IsIncrementalBarrierNeeded(JSContext* cx);
|
||||
|
||||
/*
|
||||
* Notify the GC that a reference to a GC thing is about to be overwritten.
|
||||
* These methods must be called if IsIncrementalBarrierNeeded.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
IncrementalReferenceBarrier(GCCellPtr thing);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
IncrementalValueBarrier(const Value& v);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
IncrementalObjectBarrier(JSObject* obj);
|
||||
|
||||
/**
|
||||
* Returns true if the most recent GC ran incrementally.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
WasIncrementalGC(JSContext* cx);
|
||||
|
||||
/*
|
||||
* Generational GC:
|
||||
*
|
||||
* Note: Generational GC is not yet enabled by default. The following class
|
||||
* is non-functional unless SpiderMonkey was configured with
|
||||
* --enable-gcgenerational.
|
||||
*/
|
||||
|
||||
/** Ensure that generational GC is disabled within some scope. */
|
||||
class JS_PUBLIC_API(AutoDisableGenerationalGC)
|
||||
{
|
||||
js::gc::GCRuntime* gc;
|
||||
|
||||
public:
|
||||
explicit AutoDisableGenerationalGC(JSRuntime* rt);
|
||||
~AutoDisableGenerationalGC();
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if generational allocation and collection is currently enabled
|
||||
* on the given runtime.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
IsGenerationalGCEnabled(JSRuntime* rt);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* with GC activity.
|
||||
*/
|
||||
extern JS_PUBLIC_API(size_t)
|
||||
GetGCNumber();
|
||||
|
||||
/**
|
||||
* Pass a subclass of this "abstract" class to callees to require that they
|
||||
* never GC. Subclasses can use assertions or the hazard analysis to ensure no
|
||||
* GC happens.
|
||||
*/
|
||||
class JS_PUBLIC_API(AutoRequireNoGC)
|
||||
{
|
||||
protected:
|
||||
AutoRequireNoGC() {}
|
||||
~AutoRequireNoGC() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Diagnostic assert (see MOZ_DIAGNOSTIC_ASSERT) that GC cannot occur while this
|
||||
* 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(AutoAssertNoGC) : public AutoRequireNoGC
|
||||
{
|
||||
js::gc::GCRuntime* gc;
|
||||
size_t gcNumber;
|
||||
|
||||
public:
|
||||
AutoAssertNoGC();
|
||||
explicit AutoAssertNoGC(JSRuntime* rt);
|
||||
explicit AutoAssertNoGC(JSContext* cx);
|
||||
~AutoAssertNoGC();
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 JS_PUBLIC_API(AutoAssertNoAlloc)
|
||||
{
|
||||
#ifdef JS_DEBUG
|
||||
js::gc::GCRuntime* gc;
|
||||
|
||||
public:
|
||||
AutoAssertNoAlloc() : gc(nullptr) {}
|
||||
explicit AutoAssertNoAlloc(JSContext* cx);
|
||||
void disallowAlloc(JSRuntime* rt);
|
||||
~AutoAssertNoAlloc();
|
||||
#else
|
||||
public:
|
||||
AutoAssertNoAlloc() {}
|
||||
explicit AutoAssertNoAlloc(JSContext* cx) {}
|
||||
void disallowAlloc(JSRuntime* rt) {}
|
||||
#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
|
||||
* 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
|
||||
* in complex regions, since it cannot understand dataflow.
|
||||
*
|
||||
* Note: GC behavior is unpredictable even when deterministic and is generally
|
||||
* non-deterministic in practice. The fact that this guard has not
|
||||
* asserted is not a guarantee that a GC cannot happen in the guarded
|
||||
* region. As a rule, anyone performing a GC unsafe action should
|
||||
* understand the GC properties of all code in that region and ensure
|
||||
* that the hazard analysis is correct for that code, rather than relying
|
||||
* on this class.
|
||||
*/
|
||||
class JS_PUBLIC_API(AutoSuppressGCAnalysis) : public AutoAssertNoAlloc
|
||||
{
|
||||
public:
|
||||
AutoSuppressGCAnalysis() : AutoAssertNoAlloc() {}
|
||||
explicit AutoSuppressGCAnalysis(JSContext* cx) : AutoAssertNoAlloc(cx) {}
|
||||
} JS_HAZ_GC_SUPPRESSED;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* trigger a GC occurs while this guard object is live.
|
||||
*
|
||||
* This is useful to make the static analysis ignore code that runs in GC
|
||||
* callbacks.
|
||||
*/
|
||||
class JS_PUBLIC_API(AutoAssertGCCallback) : public AutoSuppressGCAnalysis
|
||||
{
|
||||
public:
|
||||
explicit AutoAssertGCCallback(JSObject* obj);
|
||||
};
|
||||
|
||||
/**
|
||||
* Place AutoCheckCannotGC in scopes that you believe can never GC. These
|
||||
* annotations will be verified both dynamically via AutoAssertNoGC, and
|
||||
* statically with the rooting hazard analysis (implemented by making the
|
||||
* 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
|
||||
* 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
|
||||
* heap.
|
||||
*
|
||||
* We only do the assertion checking in DEBUG builds.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoAssertNoGC
|
||||
{
|
||||
public:
|
||||
AutoCheckCannotGC() : AutoAssertNoGC() {}
|
||||
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
|
||||
* JS::TraceKind::Shape. |thing| should be non-null. The return value indicates
|
||||
* if anything was unmarked.
|
||||
*/
|
||||
extern JS_FRIEND_API(bool)
|
||||
UnmarkGrayGCThingRecursively(GCCellPtr thing);
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
namespace js {
|
||||
namespace gc {
|
||||
|
||||
static MOZ_ALWAYS_INLINE void
|
||||
ExposeGCThingToActiveJS(JS::GCCellPtr thing)
|
||||
{
|
||||
// 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()))
|
||||
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 = detail::GetCellRuntime(thing.asCell());
|
||||
MOZ_DIAGNOSTIC_ASSERT(rt->allowGCBarriers());
|
||||
|
||||
if (IsIncrementalBarrierNeededOnTenuredGCThing(rt, thing))
|
||||
JS::IncrementalReferenceBarrier(thing);
|
||||
else if (!thing.mayBeOwnedByOtherRuntime() && js::gc::detail::CellIsMarkedGray(thing.asCell()))
|
||||
JS::UnmarkGrayGCThingRecursively(thing);
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE void
|
||||
MarkGCThingAsLive(JSRuntime* aRt, JS::GCCellPtr thing)
|
||||
{
|
||||
// Any object in the nursery will not be freed during any GC running at that
|
||||
// time.
|
||||
if (IsInsideNursery(thing.asCell()))
|
||||
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))
|
||||
JS::IncrementalReferenceBarrier(thing);
|
||||
}
|
||||
|
||||
} /* namespace gc */
|
||||
} /* namespace js */
|
||||
|
||||
namespace 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
|
||||
* data). During incremental GC, since the gray bits haven't been computed yet,
|
||||
* we conservatively mark the object black.
|
||||
*/
|
||||
static MOZ_ALWAYS_INLINE void
|
||||
ExposeObjectToActiveJS(JSObject* obj)
|
||||
{
|
||||
MOZ_ASSERT(obj);
|
||||
js::gc::ExposeGCThingToActiveJS(GCCellPtr(obj));
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE void
|
||||
ExposeScriptToActiveJS(JSScript* script)
|
||||
{
|
||||
js::gc::ExposeGCThingToActiveJS(GCCellPtr(script));
|
||||
}
|
||||
|
||||
/*
|
||||
* If a GC is currently marking, mark the string black.
|
||||
*/
|
||||
static MOZ_ALWAYS_INLINE void
|
||||
MarkStringAsLive(Zone* zone, JSString* string)
|
||||
{
|
||||
JSRuntime* rt = JS::shadow::Zone::asShadowZone(zone)->runtimeFromMainThread();
|
||||
js::gc::MarkGCThingAsLive(rt, GCCellPtr(string));
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal to Firefox.
|
||||
*
|
||||
* Note: this is not related to the PokeGC in nsJSEnvironment.
|
||||
*/
|
||||
extern JS_FRIEND_API(void)
|
||||
PokeGC(JSContext* cx);
|
||||
|
||||
/*
|
||||
* Internal to Firefox.
|
||||
*/
|
||||
extern JS_FRIEND_API(void)
|
||||
NotifyDidPaint(JSContext* cx);
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
#endif /* js_GCAPI_h */
|
||||
Reference in New Issue
Block a user