LCOV - code coverage report
Current view: top level - js/public - GCAPI.h (source / functions) Hit Total Coverage
Test: output.info Lines: 31 45 68.9 %
Date: 2017-07-14 16:53:18 Functions: 12 18 66.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef js_GCAPI_h
       8             : #define js_GCAPI_h
       9             : 
      10             : #include "mozilla/TimeStamp.h"
      11             : #include "mozilla/Vector.h"
      12             : 
      13             : #include "js/GCAnnotations.h"
      14             : #include "js/HeapAPI.h"
      15             : #include "js/UniquePtr.h"
      16             : #include "js/Utility.h"
      17             : 
      18             : namespace js {
      19             : namespace gc {
      20             : class GCRuntime;
      21             : } // namespace gc
      22             : namespace gcstats {
      23             : struct Statistics;
      24             : } // namespace gcstats
      25             : } // namespace js
      26             : 
      27             : typedef enum JSGCMode {
      28             :     /** Perform only global GCs. */
      29             :     JSGC_MODE_GLOBAL = 0,
      30             : 
      31             :     /** Perform per-zone GCs until too much garbage has accumulated. */
      32             :     JSGC_MODE_ZONE = 1,
      33             : 
      34             :     /**
      35             :      * Collect in short time slices rather than all at once. Implies
      36             :      * JSGC_MODE_ZONE.
      37             :      */
      38             :     JSGC_MODE_INCREMENTAL = 2
      39             : } JSGCMode;
      40             : 
      41             : /**
      42             :  * Kinds of js_GC invocation.
      43             :  */
      44             : typedef enum JSGCInvocationKind {
      45             :     /* Normal invocation. */
      46             :     GC_NORMAL = 0,
      47             : 
      48             :     /* Minimize GC triggers and release empty GC chunks right away. */
      49             :     GC_SHRINK = 1
      50             : } JSGCInvocationKind;
      51             : 
      52             : namespace JS {
      53             : 
      54             : #define GCREASONS(D)                            \
      55             :     /* Reasons internal to the JS engine */     \
      56             :     D(API)                                      \
      57             :     D(EAGER_ALLOC_TRIGGER)                      \
      58             :     D(DESTROY_RUNTIME)                          \
      59             :     D(ROOTS_REMOVED)                            \
      60             :     D(LAST_DITCH)                               \
      61             :     D(TOO_MUCH_MALLOC)                          \
      62             :     D(ALLOC_TRIGGER)                            \
      63             :     D(DEBUG_GC)                                 \
      64             :     D(COMPARTMENT_REVIVED)                      \
      65             :     D(RESET)                                    \
      66             :     D(OUT_OF_NURSERY)                           \
      67             :     D(EVICT_NURSERY)                            \
      68             :     D(FULL_STORE_BUFFER)                        \
      69             :     D(SHARED_MEMORY_LIMIT)                      \
      70             :     D(UNUSED1)                                  \
      71             :     D(INCREMENTAL_TOO_SLOW)                     \
      72             :     D(ABORT_GC)                                 \
      73             :                                                 \
      74             :     /* These are reserved for future use. */    \
      75             :     D(RESERVED0)                                \
      76             :     D(RESERVED1)                                \
      77             :     D(RESERVED2)                                \
      78             :     D(RESERVED3)                                \
      79             :     D(RESERVED4)                                \
      80             :     D(RESERVED5)                                \
      81             :     D(RESERVED6)                                \
      82             :     D(RESERVED7)                                \
      83             :     D(RESERVED8)                                \
      84             :     D(RESERVED9)                                \
      85             :     D(RESERVED10)                               \
      86             :     D(RESERVED11)                               \
      87             :     D(RESERVED12)                               \
      88             :     D(RESERVED13)                               \
      89             :     D(RESERVED14)                               \
      90             :     D(RESERVED15)                               \
      91             :                                                 \
      92             :     /* Reasons from Firefox */                  \
      93             :     D(DOM_WINDOW_UTILS)                         \
      94             :     D(COMPONENT_UTILS)                          \
      95             :     D(MEM_PRESSURE)                             \
      96             :     D(CC_WAITING)                               \
      97             :     D(CC_FORCED)                                \
      98             :     D(LOAD_END)                                 \
      99             :     D(POST_COMPARTMENT)                         \
     100             :     D(PAGE_HIDE)                                \
     101             :     D(NSJSCONTEXT_DESTROY)                      \
     102             :     D(SET_NEW_DOCUMENT)                         \
     103             :     D(SET_DOC_SHELL)                            \
     104             :     D(DOM_UTILS)                                \
     105             :     D(DOM_IPC)                                  \
     106             :     D(DOM_WORKER)                               \
     107             :     D(INTER_SLICE_GC)                           \
     108             :     D(REFRESH_FRAME)                            \
     109             :     D(FULL_GC_TIMER)                            \
     110             :     D(SHUTDOWN_CC)                              \
     111             :     D(UNUSED2)                                  \
     112             :     D(USER_INACTIVE)                            \
     113             :     D(XPCONNECT_SHUTDOWN)
     114             : 
     115             : namespace gcreason {
     116             : 
     117             : /* GCReasons will end up looking like JSGC_MAYBEGC */
     118             : enum Reason {
     119             : #define MAKE_REASON(name) name,
     120             :     GCREASONS(MAKE_REASON)
     121             : #undef MAKE_REASON
     122             :     NO_REASON,
     123             :     NUM_REASONS,
     124             : 
     125             :     /*
     126             :      * For telemetry, we want to keep a fixed max bucket size over time so we
     127             :      * don't have to switch histograms. 100 is conservative; as of this writing
     128             :      * there are 52. But the cost of extra buckets seems to be low while the
     129             :      * cost of switching histograms is high.
     130             :      */
     131             :     NUM_TELEMETRY_REASONS = 100
     132             : };
     133             : 
     134             : /**
     135             :  * Get a statically allocated C string explaining the given GC reason.
     136             :  */
     137             : extern JS_PUBLIC_API(const char*)
     138             : ExplainReason(JS::gcreason::Reason reason);
     139             : 
     140             : } /* namespace gcreason */
     141             : 
     142             : /*
     143             :  * Zone GC:
     144             :  *
     145             :  * SpiderMonkey's GC is capable of performing a collection on an arbitrary
     146             :  * subset of the zones in the system. This allows an embedding to minimize
     147             :  * collection time by only collecting zones that have run code recently,
     148             :  * ignoring the parts of the heap that are unlikely to have changed.
     149             :  *
     150             :  * When triggering a GC using one of the functions below, it is first necessary
     151             :  * to select the zones to be collected. To do this, you can call
     152             :  * PrepareZoneForGC on each zone, or you can call PrepareForFullGC to select
     153             :  * all zones. Failing to select any zone is an error.
     154             :  */
     155             : 
     156             : /**
     157             :  * Schedule the given zone to be collected as part of the next GC.
     158             :  */
     159             : extern JS_PUBLIC_API(void)
     160             : PrepareZoneForGC(Zone* zone);
     161             : 
     162             : /**
     163             :  * Schedule all zones to be collected in the next GC.
     164             :  */
     165             : extern JS_PUBLIC_API(void)
     166             : PrepareForFullGC(JSContext* cx);
     167             : 
     168             : /**
     169             :  * When performing an incremental GC, the zones that were selected for the
     170             :  * previous incremental slice must be selected in subsequent slices as well.
     171             :  * This function selects those slices automatically.
     172             :  */
     173             : extern JS_PUBLIC_API(void)
     174             : PrepareForIncrementalGC(JSContext* cx);
     175             : 
     176             : /**
     177             :  * Returns true if any zone in the system has been scheduled for GC with one of
     178             :  * the functions above or by the JS engine.
     179             :  */
     180             : extern JS_PUBLIC_API(bool)
     181             : IsGCScheduled(JSContext* cx);
     182             : 
     183             : /**
     184             :  * Undoes the effect of the Prepare methods above. The given zone will not be
     185             :  * collected in the next GC.
     186             :  */
     187             : extern JS_PUBLIC_API(void)
     188             : SkipZoneForGC(Zone* zone);
     189             : 
     190             : /*
     191             :  * Non-Incremental GC:
     192             :  *
     193             :  * The following functions perform a non-incremental GC.
     194             :  */
     195             : 
     196             : /**
     197             :  * Performs a non-incremental collection of all selected zones.
     198             :  *
     199             :  * If the gckind argument is GC_NORMAL, then some objects that are unreachable
     200             :  * from the program may still be alive afterwards because of internal
     201             :  * references; if GC_SHRINK is passed then caches and other temporary references
     202             :  * to objects will be cleared and all unreferenced objects will be removed from
     203             :  * the system.
     204             :  */
     205             : extern JS_PUBLIC_API(void)
     206             : GCForReason(JSContext* cx, JSGCInvocationKind gckind, gcreason::Reason reason);
     207             : 
     208             : /*
     209             :  * Incremental GC:
     210             :  *
     211             :  * Incremental GC divides the full mark-and-sweep collection into multiple
     212             :  * slices, allowing client JavaScript code to run between each slice. This
     213             :  * allows interactive apps to avoid long collection pauses. Incremental GC does
     214             :  * not make collection take less time, it merely spreads that time out so that
     215             :  * the pauses are less noticable.
     216             :  *
     217             :  * For a collection to be carried out incrementally the following conditions
     218             :  * must be met:
     219             :  *  - The collection must be run by calling JS::IncrementalGC() rather than
     220             :  *    JS_GC().
     221             :  *  - The GC mode must have been set to JSGC_MODE_INCREMENTAL with
     222             :  *    JS_SetGCParameter().
     223             :  *
     224             :  * Note: Even if incremental GC is enabled and working correctly,
     225             :  *       non-incremental collections can still happen when low on memory.
     226             :  */
     227             : 
     228             : /**
     229             :  * Begin an incremental collection and perform one slice worth of work. When
     230             :  * this function returns, the collection may not be complete.
     231             :  * IncrementalGCSlice() must be called repeatedly until
     232             :  * !IsIncrementalGCInProgress(cx).
     233             :  *
     234             :  * Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or
     235             :  *       shorter than the requested interval.
     236             :  */
     237             : extern JS_PUBLIC_API(void)
     238             : StartIncrementalGC(JSContext* cx, JSGCInvocationKind gckind, gcreason::Reason reason,
     239             :                    int64_t millis = 0);
     240             : 
     241             : /**
     242             :  * Perform a slice of an ongoing incremental collection. When this function
     243             :  * returns, the collection may not be complete. It must be called repeatedly
     244             :  * until !IsIncrementalGCInProgress(cx).
     245             :  *
     246             :  * Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or
     247             :  *       shorter than the requested interval.
     248             :  */
     249             : extern JS_PUBLIC_API(void)
     250             : IncrementalGCSlice(JSContext* cx, gcreason::Reason reason, int64_t millis = 0);
     251             : 
     252             : /**
     253             :  * If IsIncrementalGCInProgress(cx), this call finishes the ongoing collection
     254             :  * by performing an arbitrarily long slice. If !IsIncrementalGCInProgress(cx),
     255             :  * this is equivalent to GCForReason. When this function returns,
     256             :  * IsIncrementalGCInProgress(cx) will always be false.
     257             :  */
     258             : extern JS_PUBLIC_API(void)
     259             : FinishIncrementalGC(JSContext* cx, gcreason::Reason reason);
     260             : 
     261             : /**
     262             :  * If IsIncrementalGCInProgress(cx), this call aborts the ongoing collection and
     263             :  * performs whatever work needs to be done to return the collector to its idle
     264             :  * state. This may take an arbitrarily long time. When this function returns,
     265             :  * IsIncrementalGCInProgress(cx) will always be false.
     266             :  */
     267             : extern JS_PUBLIC_API(void)
     268             : AbortIncrementalGC(JSContext* cx);
     269             : 
     270             : namespace dbg {
     271             : 
     272             : // The `JS::dbg::GarbageCollectionEvent` class is essentially a view of the
     273             : // `js::gcstats::Statistics` data without the uber implementation-specific bits.
     274             : // It should generally be palatable for web developers.
     275           0 : class GarbageCollectionEvent
     276             : {
     277             :     // The major GC number of the GC cycle this data pertains to.
     278             :     uint64_t majorGCNumber_;
     279             : 
     280             :     // Reference to a non-owned, statically allocated C string. This is a very
     281             :     // short reason explaining why a GC was triggered.
     282             :     const char* reason;
     283             : 
     284             :     // Reference to a nullable, non-owned, statically allocated C string. If the
     285             :     // collection was forced to be non-incremental, this is a short reason of
     286             :     // why the GC could not perform an incremental collection.
     287             :     const char* nonincrementalReason;
     288             : 
     289             :     // Represents a single slice of a possibly multi-slice incremental garbage
     290             :     // collection.
     291           0 :     struct Collection {
     292             :         mozilla::TimeStamp startTimestamp;
     293             :         mozilla::TimeStamp endTimestamp;
     294             :     };
     295             : 
     296             :     // The set of garbage collection slices that made up this GC cycle.
     297             :     mozilla::Vector<Collection> collections;
     298             : 
     299             :     GarbageCollectionEvent(const GarbageCollectionEvent& rhs) = delete;
     300             :     GarbageCollectionEvent& operator=(const GarbageCollectionEvent& rhs) = delete;
     301             : 
     302             :   public:
     303           0 :     explicit GarbageCollectionEvent(uint64_t majorGCNum)
     304           0 :         : majorGCNumber_(majorGCNum)
     305             :         , reason(nullptr)
     306             :         , nonincrementalReason(nullptr)
     307           0 :         , collections()
     308           0 :     { }
     309             : 
     310             :     using Ptr = js::UniquePtr<GarbageCollectionEvent>;
     311             :     static Ptr Create(JSRuntime* rt, ::js::gcstats::Statistics& stats, uint64_t majorGCNumber);
     312             : 
     313             :     JSObject* toJSObject(JSContext* cx) const;
     314             : 
     315           0 :     uint64_t majorGCNumber() const { return majorGCNumber_; }
     316             : };
     317             : 
     318             : } // namespace dbg
     319             : 
     320             : enum GCProgress {
     321             :     /*
     322             :      * During GC, the GC is bracketed by GC_CYCLE_BEGIN/END callbacks. Each
     323             :      * slice between those (whether an incremental or the sole non-incremental
     324             :      * slice) is bracketed by GC_SLICE_BEGIN/GC_SLICE_END.
     325             :      */
     326             : 
     327             :     GC_CYCLE_BEGIN,
     328             :     GC_SLICE_BEGIN,
     329             :     GC_SLICE_END,
     330             :     GC_CYCLE_END
     331             : };
     332             : 
     333             : struct JS_PUBLIC_API(GCDescription) {
     334             :     bool isZone_;
     335             :     bool isComplete_;
     336             :     JSGCInvocationKind invocationKind_;
     337             :     gcreason::Reason reason_;
     338             : 
     339           6 :     GCDescription(bool isZone, bool isComplete, JSGCInvocationKind kind, gcreason::Reason reason)
     340           6 :       : isZone_(isZone), isComplete_(isComplete), invocationKind_(kind), reason_(reason) {}
     341             : 
     342             :     char16_t* formatSliceMessage(JSContext* cx) const;
     343             :     char16_t* formatSummaryMessage(JSContext* cx) const;
     344             :     char16_t* formatJSON(JSContext* cx, uint64_t timestamp) const;
     345             : 
     346             :     mozilla::TimeStamp startTime(JSContext* cx) const;
     347             :     mozilla::TimeStamp endTime(JSContext* cx) const;
     348             :     mozilla::TimeStamp lastSliceStart(JSContext* cx) const;
     349             :     mozilla::TimeStamp lastSliceEnd(JSContext* cx) const;
     350             : 
     351             :     JS::UniqueChars sliceToJSON(JSContext* cx) const;
     352             :     JS::UniqueChars summaryToJSON(JSContext* cx) const;
     353             : 
     354             :     JS::dbg::GarbageCollectionEvent::Ptr toGCEvent(JSContext* cx) const;
     355             : };
     356             : 
     357             : extern JS_PUBLIC_API(UniqueChars)
     358             : MinorGcToJSON(JSContext* cx);
     359             : 
     360             : typedef void
     361             : (* GCSliceCallback)(JSContext* cx, GCProgress progress, const GCDescription& desc);
     362             : 
     363             : /**
     364             :  * The GC slice callback is called at the beginning and end of each slice. This
     365             :  * callback may be used for GC notifications as well as to perform additional
     366             :  * marking.
     367             :  */
     368             : extern JS_PUBLIC_API(GCSliceCallback)
     369             : SetGCSliceCallback(JSContext* cx, GCSliceCallback callback);
     370             : 
     371             : /**
     372             :  * Describes the progress of an observed nursery collection.
     373             :  */
     374             : enum class GCNurseryProgress {
     375             :     /**
     376             :      * The nursery collection is starting.
     377             :      */
     378             :     GC_NURSERY_COLLECTION_START,
     379             :     /**
     380             :      * The nursery collection is ending.
     381             :      */
     382             :     GC_NURSERY_COLLECTION_END
     383             : };
     384             : 
     385             : /**
     386             :  * A nursery collection callback receives the progress of the nursery collection
     387             :  * and the reason for the collection.
     388             :  */
     389             : using GCNurseryCollectionCallback = void(*)(JSContext* cx, GCNurseryProgress progress,
     390             :                                             gcreason::Reason reason);
     391             : 
     392             : /**
     393             :  * Set the nursery collection callback for the given runtime. When set, it will
     394             :  * be called at the start and end of every nursery collection.
     395             :  */
     396             : extern JS_PUBLIC_API(GCNurseryCollectionCallback)
     397             : SetGCNurseryCollectionCallback(JSContext* cx, GCNurseryCollectionCallback callback);
     398             : 
     399             : typedef void
     400             : (* DoCycleCollectionCallback)(JSContext* cx);
     401             : 
     402             : /**
     403             :  * The purge gray callback is called after any COMPARTMENT_REVIVED GC in which
     404             :  * the majority of compartments have been marked gray.
     405             :  */
     406             : extern JS_PUBLIC_API(DoCycleCollectionCallback)
     407             : SetDoCycleCollectionCallback(JSContext* cx, DoCycleCollectionCallback callback);
     408             : 
     409             : /**
     410             :  * Incremental GC defaults to enabled, but may be disabled for testing or in
     411             :  * embeddings that have not yet implemented barriers on their native classes.
     412             :  * There is not currently a way to re-enable incremental GC once it has been
     413             :  * disabled on the runtime.
     414             :  */
     415             : extern JS_PUBLIC_API(void)
     416             : DisableIncrementalGC(JSContext* cx);
     417             : 
     418             : /**
     419             :  * Returns true if incremental GC is enabled. Simply having incremental GC
     420             :  * enabled is not sufficient to ensure incremental collections are happening.
     421             :  * See the comment "Incremental GC" above for reasons why incremental GC may be
     422             :  * suppressed. Inspection of the "nonincremental reason" field of the
     423             :  * GCDescription returned by GCSliceCallback may help narrow down the cause if
     424             :  * collections are not happening incrementally when expected.
     425             :  */
     426             : extern JS_PUBLIC_API(bool)
     427             : IsIncrementalGCEnabled(JSContext* cx);
     428             : 
     429             : /**
     430             :  * Returns true while an incremental GC is ongoing, both when actively
     431             :  * collecting and between slices.
     432             :  */
     433             : extern JS_PUBLIC_API(bool)
     434             : IsIncrementalGCInProgress(JSContext* cx);
     435             : 
     436             : /**
     437             :  * Returns true while an incremental GC is ongoing, both when actively
     438             :  * collecting and between slices.
     439             :  */
     440             : extern JS_PUBLIC_API(bool)
     441             : IsIncrementalGCInProgress(JSRuntime* rt);
     442             : 
     443             : /*
     444             :  * Returns true when writes to GC thing pointers (and reads from weak pointers)
     445             :  * must call an incremental barrier. This is generally only true when running
     446             :  * mutator code in-between GC slices. At other times, the barrier may be elided
     447             :  * for performance.
     448             :  */
     449             : extern JS_PUBLIC_API(bool)
     450             : IsIncrementalBarrierNeeded(JSContext* cx);
     451             : 
     452             : /*
     453             :  * Notify the GC that a reference to a JSObject is about to be overwritten.
     454             :  * This method must be called if IsIncrementalBarrierNeeded.
     455             :  */
     456             : extern JS_PUBLIC_API(void)
     457             : IncrementalPreWriteBarrier(JSObject* obj);
     458             : 
     459             : /*
     460             :  * Notify the GC that a weak reference to a GC thing has been read.
     461             :  * This method must be called if IsIncrementalBarrierNeeded.
     462             :  */
     463             : extern JS_PUBLIC_API(void)
     464             : IncrementalReadBarrier(GCCellPtr thing);
     465             : 
     466             : /**
     467             :  * Returns true if the most recent GC ran incrementally.
     468             :  */
     469             : extern JS_PUBLIC_API(bool)
     470             : WasIncrementalGC(JSRuntime* rt);
     471             : 
     472             : /*
     473             :  * Generational GC:
     474             :  *
     475             :  * Note: Generational GC is not yet enabled by default. The following class
     476             :  *       is non-functional unless SpiderMonkey was configured with
     477             :  *       --enable-gcgenerational.
     478             :  */
     479             : 
     480             : /** Ensure that generational GC is disabled within some scope. */
     481             : class JS_PUBLIC_API(AutoDisableGenerationalGC)
     482             : {
     483             :     JSContext* cx;
     484             : 
     485             :   public:
     486             :     explicit AutoDisableGenerationalGC(JSContext* cx);
     487             :     ~AutoDisableGenerationalGC();
     488             : };
     489             : 
     490             : /**
     491             :  * Returns true if generational allocation and collection is currently enabled
     492             :  * on the given runtime.
     493             :  */
     494             : extern JS_PUBLIC_API(bool)
     495             : IsGenerationalGCEnabled(JSRuntime* rt);
     496             : 
     497             : /**
     498             :  * Returns the GC's "number". This does not correspond directly to the number
     499             :  * of GCs that have been run, but is guaranteed to be monotonically increasing
     500             :  * with GC activity.
     501             :  */
     502             : extern JS_PUBLIC_API(size_t)
     503             : GetGCNumber();
     504             : 
     505             : /**
     506             :  * Pass a subclass of this "abstract" class to callees to require that they
     507             :  * never GC. Subclasses can use assertions or the hazard analysis to ensure no
     508             :  * GC happens.
     509             :  */
     510             : class JS_PUBLIC_API(AutoRequireNoGC)
     511             : {
     512             :   protected:
     513     3346583 :     AutoRequireNoGC() {}
     514     3347429 :     ~AutoRequireNoGC() {}
     515             : };
     516             : 
     517             : /**
     518             :  * Diagnostic assert (see MOZ_DIAGNOSTIC_ASSERT) that GC cannot occur while this
     519             :  * class is live. This class does not disable the static rooting hazard
     520             :  * analysis.
     521             :  *
     522             :  * This works by entering a GC unsafe region, which is checked on allocation and
     523             :  * on GC.
     524             :  */
     525             : class JS_PUBLIC_API(AutoAssertNoGC) : public AutoRequireNoGC
     526             : {
     527             :     JSContext* cx_;
     528             : 
     529             :   public:
     530             :     explicit AutoAssertNoGC(JSContext* cx = nullptr);
     531             :     ~AutoAssertNoGC();
     532             : };
     533             : 
     534             : /**
     535             :  * Assert if an allocation of a GC thing occurs while this class is live. This
     536             :  * class does not disable the static rooting hazard analysis.
     537             :  */
     538             : class JS_PUBLIC_API(AutoAssertNoAlloc)
     539             : {
     540             : #ifdef JS_DEBUG
     541             :     js::gc::GCRuntime* gc;
     542             : 
     543             :   public:
     544      670075 :     AutoAssertNoAlloc() : gc(nullptr) {}
     545             :     explicit AutoAssertNoAlloc(JSContext* cx);
     546             :     void disallowAlloc(JSRuntime* rt);
     547             :     ~AutoAssertNoAlloc();
     548             : #else
     549             :   public:
     550             :     AutoAssertNoAlloc() {}
     551             :     explicit AutoAssertNoAlloc(JSContext* cx) {}
     552             :     void disallowAlloc(JSRuntime* rt) {}
     553             : #endif
     554             : };
     555             : 
     556             : /**
     557             :  * Disable the static rooting hazard analysis in the live region and assert if
     558             :  * any allocation that could potentially trigger a GC occurs while this guard
     559             :  * object is live. This is most useful to help the exact rooting hazard analysis
     560             :  * in complex regions, since it cannot understand dataflow.
     561             :  *
     562             :  * Note: GC behavior is unpredictable even when deterministic and is generally
     563             :  *       non-deterministic in practice. The fact that this guard has not
     564             :  *       asserted is not a guarantee that a GC cannot happen in the guarded
     565             :  *       region. As a rule, anyone performing a GC unsafe action should
     566             :  *       understand the GC properties of all code in that region and ensure
     567             :  *       that the hazard analysis is correct for that code, rather than relying
     568             :  *       on this class.
     569             :  */
     570      670042 : class JS_PUBLIC_API(AutoSuppressGCAnalysis) : public AutoAssertNoAlloc
     571             : {
     572             :   public:
     573      670074 :     AutoSuppressGCAnalysis() : AutoAssertNoAlloc() {}
     574           0 :     explicit AutoSuppressGCAnalysis(JSContext* cx) : AutoAssertNoAlloc(cx) {}
     575             : } JS_HAZ_GC_SUPPRESSED;
     576             : 
     577             : /**
     578             :  * Assert that code is only ever called from a GC callback, disable the static
     579             :  * rooting hazard analysis and assert if any allocation that could potentially
     580             :  * trigger a GC occurs while this guard object is live.
     581             :  *
     582             :  * This is useful to make the static analysis ignore code that runs in GC
     583             :  * callbacks.
     584             :  */
     585          61 : class JS_PUBLIC_API(AutoAssertGCCallback) : public AutoSuppressGCAnalysis
     586             : {
     587             :   public:
     588             : #ifdef DEBUG
     589             :     AutoAssertGCCallback();
     590             : #else
     591             :     AutoAssertGCCallback() {}
     592             : #endif
     593             : };
     594             : 
     595             : /**
     596             :  * Place AutoCheckCannotGC in scopes that you believe can never GC. These
     597             :  * annotations will be verified both dynamically via AutoAssertNoGC, and
     598             :  * statically with the rooting hazard analysis (implemented by making the
     599             :  * analysis consider AutoCheckCannotGC to be a GC pointer, and therefore
     600             :  * complain if it is live across a GC call.) It is useful when dealing with
     601             :  * internal pointers to GC things where the GC thing itself may not be present
     602             :  * for the static analysis: e.g. acquiring inline chars from a JSString* on the
     603             :  * heap.
     604             :  *
     605             :  * We only do the assertion checking in DEBUG builds.
     606             :  */
     607             : #ifdef DEBUG
     608     3372741 : class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoAssertNoGC
     609             : {
     610             :   public:
     611     3372469 :     explicit AutoCheckCannotGC(JSContext* cx = nullptr) : AutoAssertNoGC(cx) {}
     612             : } JS_HAZ_GC_INVALIDATED;
     613             : #else
     614             : class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoRequireNoGC
     615             : {
     616             :   public:
     617             :     explicit AutoCheckCannotGC(JSContext* cx = nullptr) {}
     618             : } JS_HAZ_GC_INVALIDATED;
     619             : #endif
     620             : 
     621             : /**
     622             :  * Unsets the gray bit for anything reachable from |thing|. |kind| should not be
     623             :  * JS::TraceKind::Shape. |thing| should be non-null. The return value indicates
     624             :  * if anything was unmarked.
     625             :  */
     626             : extern JS_FRIEND_API(bool)
     627             : UnmarkGrayGCThingRecursively(GCCellPtr thing);
     628             : 
     629             : } /* namespace JS */
     630             : 
     631             : namespace js {
     632             : namespace gc {
     633             : 
     634             : static MOZ_ALWAYS_INLINE void
     635      254077 : ExposeGCThingToActiveJS(JS::GCCellPtr thing)
     636             : {
     637             :     // GC things residing in the nursery cannot be gray: they have no mark bits.
     638             :     // All live objects in the nursery are moved to tenured at the beginning of
     639             :     // each GC slice, so the gray marker never sees nursery things.
     640      254077 :     if (IsInsideNursery(thing.asCell()))
     641       21107 :         return;
     642             : 
     643             :     // There's nothing to do for permanent GC things that might be owned by
     644             :     // another runtime.
     645      232970 :     if (thing.mayBeOwnedByOtherRuntime())
     646           3 :         return;
     647             : 
     648      232967 :     if (IsIncrementalBarrierNeededOnTenuredGCThing(thing))
     649        3277 :         JS::IncrementalReadBarrier(thing);
     650      229691 :     else if (js::gc::detail::TenuredCellIsMarkedGray(thing.asCell()))
     651           0 :         JS::UnmarkGrayGCThingRecursively(thing);
     652             : 
     653      232968 :     MOZ_ASSERT(!js::gc::detail::TenuredCellIsMarkedGray(thing.asCell()));
     654             : }
     655             : 
     656             : template <typename T>
     657             : extern JS_PUBLIC_API(bool)
     658             : EdgeNeedsSweepUnbarrieredSlow(T* thingp);
     659             : 
     660             : static MOZ_ALWAYS_INLINE bool
     661       27970 : EdgeNeedsSweepUnbarriered(JSObject** objp)
     662             : {
     663             :     // This function does not handle updating nursery pointers. Raw JSObject
     664             :     // pointers should be updated separately or replaced with
     665             :     // JS::Heap<JSObject*> which handles this automatically.
     666       27970 :     MOZ_ASSERT(!JS::CurrentThreadIsHeapMinorCollecting());
     667       27971 :     if (IsInsideNursery(reinterpret_cast<Cell*>(*objp)))
     668         363 :         return false;
     669             : 
     670       27608 :     auto zone = JS::shadow::Zone::asShadowZone(detail::GetGCThingZone(uintptr_t(*objp)));
     671       27608 :     if (!zone->isGCSweepingOrCompacting())
     672       27608 :         return false;
     673             : 
     674           0 :     return EdgeNeedsSweepUnbarrieredSlow(objp);
     675             : }
     676             : 
     677             : } /* namespace gc */
     678             : } /* namespace js */
     679             : 
     680             : namespace JS {
     681             : 
     682             : /*
     683             :  * This should be called when an object that is marked gray is exposed to the JS
     684             :  * engine (by handing it to running JS code or writing it into live JS
     685             :  * data). During incremental GC, since the gray bits haven't been computed yet,
     686             :  * we conservatively mark the object black.
     687             :  */
     688             : static MOZ_ALWAYS_INLINE void
     689      197281 : ExposeObjectToActiveJS(JSObject* obj)
     690             : {
     691      197281 :     MOZ_ASSERT(obj);
     692      197281 :     MOZ_ASSERT(!js::gc::EdgeNeedsSweepUnbarrieredSlow(&obj));
     693      197280 :     js::gc::ExposeGCThingToActiveJS(GCCellPtr(obj));
     694      197281 : }
     695             : 
     696             : static MOZ_ALWAYS_INLINE void
     697           0 : ExposeScriptToActiveJS(JSScript* script)
     698             : {
     699           0 :     MOZ_ASSERT(!js::gc::EdgeNeedsSweepUnbarrieredSlow(&script));
     700           0 :     js::gc::ExposeGCThingToActiveJS(GCCellPtr(script));
     701           0 : }
     702             : 
     703             : /*
     704             :  * Internal to Firefox.
     705             :  */
     706             : extern JS_FRIEND_API(void)
     707             : NotifyGCRootsRemoved(JSContext* cx);
     708             : 
     709             : /*
     710             :  * Internal to Firefox.
     711             :  */
     712             : extern JS_FRIEND_API(void)
     713             : NotifyDidPaint(JSContext* cx);
     714             : 
     715             : } /* namespace JS */
     716             : 
     717             : #endif /* js_GCAPI_h */

Generated by: LCOV version 1.13