js/public/GCAPI.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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/. */
     7 #ifndef js_GCAPI_h
     8 #define js_GCAPI_h
    10 #include "mozilla/NullPtr.h"
    12 #include "js/HeapAPI.h"
    13 #include "js/RootingAPI.h"
    14 #include "js/Value.h"
    16 typedef enum JSGCMode {
    17     /* Perform only global GCs. */
    18     JSGC_MODE_GLOBAL = 0,
    20     /* Perform per-compartment GCs until too much garbage has accumulated. */
    21     JSGC_MODE_COMPARTMENT = 1,
    23     /*
    24      * Collect in short time slices rather than all at once. Implies
    25      * JSGC_MODE_COMPARTMENT.
    26      */
    27     JSGC_MODE_INCREMENTAL = 2
    28 } JSGCMode;
    30 namespace JS {
    32 #define GCREASONS(D)                            \
    33     /* Reasons internal to the JS engine */     \
    34     D(API)                                      \
    35     D(MAYBEGC)                                  \
    36     D(DESTROY_RUNTIME)                          \
    37     D(DESTROY_CONTEXT)                          \
    38     D(LAST_DITCH)                               \
    39     D(TOO_MUCH_MALLOC)                          \
    40     D(ALLOC_TRIGGER)                            \
    41     D(DEBUG_GC)                                 \
    42     D(TRANSPLANT)                               \
    43     D(RESET)                                    \
    44     D(OUT_OF_NURSERY)                           \
    45     D(EVICT_NURSERY)                            \
    46     D(FULL_STORE_BUFFER)                        \
    47                                                 \
    48     /* These are reserved for future use. */    \
    49     D(RESERVED0)                                \
    50     D(RESERVED1)                                \
    51     D(RESERVED2)                                \
    52     D(RESERVED3)                                \
    53     D(RESERVED4)                                \
    54     D(RESERVED5)                                \
    55     D(RESERVED6)                                \
    56     D(RESERVED7)                                \
    57     D(RESERVED8)                                \
    58     D(RESERVED9)                                \
    59     D(RESERVED10)                               \
    60     D(RESERVED11)                               \
    61     D(RESERVED12)                               \
    62     D(RESERVED13)                               \
    63     D(RESERVED14)                               \
    64     D(RESERVED15)                               \
    65     D(RESERVED16)                               \
    66     D(RESERVED17)                               \
    67     D(RESERVED18)                               \
    68     D(RESERVED19)                               \
    69                                                 \
    70     /* Reasons from Firefox */                  \
    71     D(DOM_WINDOW_UTILS)                         \
    72     D(COMPONENT_UTILS)                          \
    73     D(MEM_PRESSURE)                             \
    74     D(CC_WAITING)                               \
    75     D(CC_FORCED)                                \
    76     D(LOAD_END)                                 \
    77     D(POST_COMPARTMENT)                         \
    78     D(PAGE_HIDE)                                \
    79     D(NSJSCONTEXT_DESTROY)                      \
    80     D(SET_NEW_DOCUMENT)                         \
    81     D(SET_DOC_SHELL)                            \
    82     D(DOM_UTILS)                                \
    83     D(DOM_IPC)                                  \
    84     D(DOM_WORKER)                               \
    85     D(INTER_SLICE_GC)                           \
    86     D(REFRESH_FRAME)                            \
    87     D(FULL_GC_TIMER)                            \
    88     D(SHUTDOWN_CC)                              \
    89     D(FINISH_LARGE_EVALUTE)
    91 namespace gcreason {
    93 /* GCReasons will end up looking like JSGC_MAYBEGC */
    94 enum Reason {
    95 #define MAKE_REASON(name) name,
    96     GCREASONS(MAKE_REASON)
    97 #undef MAKE_REASON
    98     NO_REASON,
    99     NUM_REASONS,
   101     /*
   102      * For telemetry, we want to keep a fixed max bucket size over time so we
   103      * don't have to switch histograms. 100 is conservative; as of this writing
   104      * there are 26. But the cost of extra buckets seems to be low while the
   105      * cost of switching histograms is high.
   106      */
   107     NUM_TELEMETRY_REASONS = 100
   108 };
   110 } /* namespace gcreason */
   112 /*
   113  * Zone GC:
   114  *
   115  * SpiderMonkey's GC is capable of performing a collection on an arbitrary
   116  * subset of the zones in the system. This allows an embedding to minimize
   117  * collection time by only collecting zones that have run code recently,
   118  * ignoring the parts of the heap that are unlikely to have changed.
   119  *
   120  * When triggering a GC using one of the functions below, it is first necessary
   121  * to select the zones to be collected. To do this, you can call
   122  * PrepareZoneForGC on each zone, or you can call PrepareForFullGC to select
   123  * all zones. Failing to select any zone is an error.
   124  */
   126 /*
   127  * Schedule the given zone to be collected as part of the next GC.
   128  */
   129 extern JS_FRIEND_API(void)
   130 PrepareZoneForGC(Zone *zone);
   132 /*
   133  * Schedule all zones to be collected in the next GC.
   134  */
   135 extern JS_FRIEND_API(void)
   136 PrepareForFullGC(JSRuntime *rt);
   138 /*
   139  * When performing an incremental GC, the zones that were selected for the
   140  * previous incremental slice must be selected in subsequent slices as well.
   141  * This function selects those slices automatically.
   142  */
   143 extern JS_FRIEND_API(void)
   144 PrepareForIncrementalGC(JSRuntime *rt);
   146 /*
   147  * Returns true if any zone in the system has been scheduled for GC with one of
   148  * the functions above or by the JS engine.
   149  */
   150 extern JS_FRIEND_API(bool)
   151 IsGCScheduled(JSRuntime *rt);
   153 /*
   154  * Undoes the effect of the Prepare methods above. The given zone will not be
   155  * collected in the next GC.
   156  */
   157 extern JS_FRIEND_API(void)
   158 SkipZoneForGC(Zone *zone);
   160 /*
   161  * Non-Incremental GC:
   162  *
   163  * The following functions perform a non-incremental GC.
   164  */
   166 /*
   167  * Performs a non-incremental collection of all selected zones. Some objects
   168  * that are unreachable from the program may still be alive afterwards because
   169  * of internal references.
   170  */
   171 extern JS_FRIEND_API(void)
   172 GCForReason(JSRuntime *rt, gcreason::Reason reason);
   174 /*
   175  * Perform a non-incremental collection after clearing caches and other
   176  * temporary references to objects. This will remove all unreferenced objects
   177  * in the system.
   178  */
   179 extern JS_FRIEND_API(void)
   180 ShrinkingGC(JSRuntime *rt, gcreason::Reason reason);
   182 /*
   183  * Incremental GC:
   184  *
   185  * Incremental GC divides the full mark-and-sweep collection into multiple
   186  * slices, allowing client JavaScript code to run between each slice. This
   187  * allows interactive apps to avoid long collection pauses. Incremental GC does
   188  * not make collection take less time, it merely spreads that time out so that
   189  * the pauses are less noticable.
   190  *
   191  * For a collection to be carried out incrementally the following conditions
   192  * must be met:
   193  *  - The collection must be run by calling JS::IncrementalGC() rather than
   194  *    JS_GC().
   195  *  - The GC mode must have been set to JSGC_MODE_INCREMENTAL with
   196  *    JS_SetGCParameter().
   197  *  - All native objects that have their own trace hook must indicate that they
   198  *    implement read and write barriers with the JSCLASS_IMPLEMENTS_BARRIERS
   199  *    flag.
   200  *
   201  * Note: Even if incremental GC is enabled and working correctly,
   202  *       non-incremental collections can still happen when low on memory.
   203  */
   205 /*
   206  * Begin an incremental collection and perform one slice worth of work or
   207  * perform a slice of an ongoing incremental collection. When this function
   208  * returns, the collection is not complete. This function must be called
   209  * repeatedly until !IsIncrementalGCInProgress(rt).
   210  *
   211  * Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or
   212  *       shorter than the requested interval.
   213  */
   214 extern JS_FRIEND_API(void)
   215 IncrementalGC(JSRuntime *rt, gcreason::Reason reason, int64_t millis = 0);
   217 /*
   218  * If IsIncrementalGCInProgress(rt), this call finishes the ongoing collection
   219  * by performing an arbitrarily long slice. If !IsIncrementalGCInProgress(rt),
   220  * this is equivalent to GCForReason. When this function returns,
   221  * IsIncrementalGCInProgress(rt) will always be false.
   222  */
   223 extern JS_FRIEND_API(void)
   224 FinishIncrementalGC(JSRuntime *rt, gcreason::Reason reason);
   226 enum GCProgress {
   227     /*
   228      * During non-incremental GC, the GC is bracketed by JSGC_CYCLE_BEGIN/END
   229      * callbacks. During an incremental GC, the sequence of callbacks is as
   230      * follows:
   231      *   JSGC_CYCLE_BEGIN, JSGC_SLICE_END  (first slice)
   232      *   JSGC_SLICE_BEGIN, JSGC_SLICE_END  (second slice)
   233      *   ...
   234      *   JSGC_SLICE_BEGIN, JSGC_CYCLE_END  (last slice)
   235      */
   237     GC_CYCLE_BEGIN,
   238     GC_SLICE_BEGIN,
   239     GC_SLICE_END,
   240     GC_CYCLE_END
   241 };
   243 struct JS_FRIEND_API(GCDescription) {
   244     bool isCompartment_;
   246     GCDescription(bool isCompartment)
   247       : isCompartment_(isCompartment) {}
   249     jschar *formatMessage(JSRuntime *rt) const;
   250     jschar *formatJSON(JSRuntime *rt, uint64_t timestamp) const;
   251 };
   253 typedef void
   254 (* GCSliceCallback)(JSRuntime *rt, GCProgress progress, const GCDescription &desc);
   256 /*
   257  * The GC slice callback is called at the beginning and end of each slice. This
   258  * callback may be used for GC notifications as well as to perform additional
   259  * marking.
   260  */
   261 extern JS_FRIEND_API(GCSliceCallback)
   262 SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback);
   264 /*
   265  * Incremental GC defaults to enabled, but may be disabled for testing or in
   266  * embeddings that have not yet implemented barriers on their native classes.
   267  * There is not currently a way to re-enable incremental GC once it has been
   268  * disabled on the runtime.
   269  */
   270 extern JS_FRIEND_API(void)
   271 DisableIncrementalGC(JSRuntime *rt);
   273 /*
   274  * Returns true if incremental GC is enabled. Simply having incremental GC
   275  * enabled is not sufficient to ensure incremental collections are happening.
   276  * See the comment "Incremental GC" above for reasons why incremental GC may be
   277  * suppressed. Inspection of the "nonincremental reason" field of the
   278  * GCDescription returned by GCSliceCallback may help narrow down the cause if
   279  * collections are not happening incrementally when expected.
   280  */
   281 extern JS_FRIEND_API(bool)
   282 IsIncrementalGCEnabled(JSRuntime *rt);
   284 /*
   285  * Returns true while an incremental GC is ongoing, both when actively
   286  * collecting and between slices.
   287  */
   288 JS_FRIEND_API(bool)
   289 IsIncrementalGCInProgress(JSRuntime *rt);
   291 /*
   292  * Returns true when writes to GC things must call an incremental (pre) barrier.
   293  * This is generally only true when running mutator code in-between GC slices.
   294  * At other times, the barrier may be elided for performance.
   295  */
   296 extern JS_FRIEND_API(bool)
   297 IsIncrementalBarrierNeeded(JSRuntime *rt);
   299 extern JS_FRIEND_API(bool)
   300 IsIncrementalBarrierNeeded(JSContext *cx);
   302 /*
   303  * Notify the GC that a reference to a GC thing is about to be overwritten.
   304  * These methods must be called if IsIncrementalBarrierNeeded.
   305  */
   306 extern JS_FRIEND_API(void)
   307 IncrementalReferenceBarrier(void *ptr, JSGCTraceKind kind);
   309 extern JS_FRIEND_API(void)
   310 IncrementalValueBarrier(const Value &v);
   312 extern JS_FRIEND_API(void)
   313 IncrementalObjectBarrier(JSObject *obj);
   315 /*
   316  * Returns true if the most recent GC ran incrementally.
   317  */
   318 extern JS_FRIEND_API(bool)
   319 WasIncrementalGC(JSRuntime *rt);
   321 /*
   322  * Generational GC:
   323  *
   324  * Note: Generational GC is not yet enabled by default. The following class
   325  *       is non-functional unless SpiderMonkey was configured with
   326  *       --enable-gcgenerational.
   327  */
   329 /* Ensure that generational GC is disabled within some scope. */
   330 class JS_FRIEND_API(AutoDisableGenerationalGC)
   331 {
   332     JSRuntime *runtime;
   333 #if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL)
   334     bool restartVerifier;
   335 #endif
   337   public:
   338     AutoDisableGenerationalGC(JSRuntime *rt);
   339     ~AutoDisableGenerationalGC();
   340 };
   342 /*
   343  * Returns true if generational allocation and collection is currently enabled
   344  * on the given runtime.
   345  */
   346 extern JS_FRIEND_API(bool)
   347 IsGenerationalGCEnabled(JSRuntime *rt);
   349 /*
   350  * Returns the GC's "number". This does not correspond directly to the number
   351  * of GCs that have been run, but is guaranteed to be monotonically increasing
   352  * with GC activity.
   353  */
   354 extern JS_FRIEND_API(size_t)
   355 GetGCNumber();
   357 /*
   358  * The GC does not immediately return the unused memory freed by a collection
   359  * back to the system incase it is needed soon afterwards. This call forces the
   360  * GC to return this memory immediately.
   361  */
   362 extern JS_FRIEND_API(void)
   363 ShrinkGCBuffers(JSRuntime *rt);
   365 /*
   366  * Assert if any GC occured while this guard object was live. This is most
   367  * useful to help the exact rooting hazard analysis in complex regions, since
   368  * it cannot understand dataflow.
   369  *
   370  * Note: GC behavior is unpredictable even when deterministice and is generally
   371  *       non-deterministic in practice. The fact that this guard has not
   372  *       asserted is not a guarantee that a GC cannot happen in the guarded
   373  *       region. As a rule, anyone performing a GC unsafe action should
   374  *       understand the GC properties of all code in that region and ensure
   375  *       that the hazard analysis is correct for that code, rather than relying
   376  *       on this class.
   377  */
   378 class JS_PUBLIC_API(AutoAssertNoGC)
   379 {
   380 #ifdef JS_DEBUG
   381     JSRuntime *runtime;
   382     size_t gcNumber;
   384   public:
   385     AutoAssertNoGC();
   386     AutoAssertNoGC(JSRuntime *rt);
   387     ~AutoAssertNoGC();
   388 #else
   389   public:
   390     /* Prevent unreferenced local warnings in opt builds. */
   391     AutoAssertNoGC() {}
   392     AutoAssertNoGC(JSRuntime *) {}
   393 #endif
   394 };
   396 class JS_PUBLIC_API(ObjectPtr)
   397 {
   398     Heap<JSObject *> value;
   400   public:
   401     ObjectPtr() : value(nullptr) {}
   403     ObjectPtr(JSObject *obj) : value(obj) {}
   405     /* Always call finalize before the destructor. */
   406     ~ObjectPtr() { MOZ_ASSERT(!value); }
   408     void finalize(JSRuntime *rt) {
   409         if (IsIncrementalBarrierNeeded(rt))
   410             IncrementalObjectBarrier(value);
   411         value = nullptr;
   412     }
   414     void init(JSObject *obj) { value = obj; }
   416     JSObject *get() const { return value; }
   418     void writeBarrierPre(JSRuntime *rt) {
   419         IncrementalObjectBarrier(value);
   420     }
   422     bool isAboutToBeFinalized();
   424     ObjectPtr &operator=(JSObject *obj) {
   425         IncrementalObjectBarrier(value);
   426         value = obj;
   427         return *this;
   428     }
   430     void trace(JSTracer *trc, const char *name);
   432     JSObject &operator*() const { return *value; }
   433     JSObject *operator->() const { return value; }
   434     operator JSObject *() const { return value; }
   435 };
   437 /*
   438  * Unsets the gray bit for anything reachable from |thing|. |kind| should not be
   439  * JSTRACE_SHAPE. |thing| should be non-null.
   440  */
   441 extern JS_FRIEND_API(bool)
   442 UnmarkGrayGCThingRecursively(void *thing, JSGCTraceKind kind);
   444 /*
   445  * This should be called when an object that is marked gray is exposed to the JS
   446  * engine (by handing it to running JS code or writing it into live JS
   447  * data). During incremental GC, since the gray bits haven't been computed yet,
   448  * we conservatively mark the object black.
   449  */
   450 static MOZ_ALWAYS_INLINE void
   451 ExposeGCThingToActiveJS(void *thing, JSGCTraceKind kind)
   452 {
   453     MOZ_ASSERT(kind != JSTRACE_SHAPE);
   455     shadow::Runtime *rt = js::gc::GetGCThingRuntime(thing);
   456 #ifdef JSGC_GENERATIONAL
   457     /*
   458      * GC things residing in the nursery cannot be gray: they have no mark bits.
   459      * All live objects in the nursery are moved to tenured at the beginning of
   460      * each GC slice, so the gray marker never sees nursery things.
   461      */
   462     if (js::gc::IsInsideNursery(rt, thing))
   463         return;
   464 #endif
   465     if (IsIncrementalBarrierNeededOnGCThing(rt, thing, kind))
   466         IncrementalReferenceBarrier(thing, kind);
   467     else if (GCThingIsMarkedGray(thing))
   468         UnmarkGrayGCThingRecursively(thing, kind);
   469 }
   471 static MOZ_ALWAYS_INLINE void
   472 ExposeValueToActiveJS(const Value &v)
   473 {
   474     if (v.isMarkable())
   475         ExposeGCThingToActiveJS(v.toGCThing(), v.gcKind());
   476 }
   478 static MOZ_ALWAYS_INLINE void
   479 ExposeObjectToActiveJS(JSObject *obj)
   480 {
   481     ExposeGCThingToActiveJS(obj, JSTRACE_OBJECT);
   482 }
   484 /*
   485  * If a GC is currently marking, mark the object black.
   486  */
   487 static MOZ_ALWAYS_INLINE void
   488 MarkGCThingAsLive(JSRuntime *rt_, void *thing, JSGCTraceKind kind)
   489 {
   490     shadow::Runtime *rt = shadow::Runtime::asShadowRuntime(rt_);
   491 #ifdef JSGC_GENERATIONAL
   492     /*
   493      * Any object in the nursery will not be freed during any GC running at that time.
   494      */
   495     if (js::gc::IsInsideNursery(rt, thing))
   496         return;
   497 #endif
   498     if (IsIncrementalBarrierNeededOnGCThing(rt, thing, kind))
   499         IncrementalReferenceBarrier(thing, kind);
   500 }
   502 static MOZ_ALWAYS_INLINE void
   503 MarkStringAsLive(Zone *zone, JSString *string)
   504 {
   505     JSRuntime *rt = JS::shadow::Zone::asShadowZone(zone)->runtimeFromMainThread();
   506     MarkGCThingAsLive(rt, string, JSTRACE_STRING);
   507 }
   509 /*
   510  * Internal to Firefox.
   511  *
   512  * Note: this is not related to the PokeGC in nsJSEnvironment.
   513  */
   514 extern JS_FRIEND_API(void)
   515 PokeGC(JSRuntime *rt);
   517 /*
   518  * Internal to Firefox.
   519  */
   520 extern JS_FRIEND_API(void)
   521 NotifyDidPaint(JSRuntime *rt);
   523 } /* namespace JS */
   525 #endif /* js_GCAPI_h */

mercurial