1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/public/GCAPI.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,525 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef js_GCAPI_h 1.11 +#define js_GCAPI_h 1.12 + 1.13 +#include "mozilla/NullPtr.h" 1.14 + 1.15 +#include "js/HeapAPI.h" 1.16 +#include "js/RootingAPI.h" 1.17 +#include "js/Value.h" 1.18 + 1.19 +typedef enum JSGCMode { 1.20 + /* Perform only global GCs. */ 1.21 + JSGC_MODE_GLOBAL = 0, 1.22 + 1.23 + /* Perform per-compartment GCs until too much garbage has accumulated. */ 1.24 + JSGC_MODE_COMPARTMENT = 1, 1.25 + 1.26 + /* 1.27 + * Collect in short time slices rather than all at once. Implies 1.28 + * JSGC_MODE_COMPARTMENT. 1.29 + */ 1.30 + JSGC_MODE_INCREMENTAL = 2 1.31 +} JSGCMode; 1.32 + 1.33 +namespace JS { 1.34 + 1.35 +#define GCREASONS(D) \ 1.36 + /* Reasons internal to the JS engine */ \ 1.37 + D(API) \ 1.38 + D(MAYBEGC) \ 1.39 + D(DESTROY_RUNTIME) \ 1.40 + D(DESTROY_CONTEXT) \ 1.41 + D(LAST_DITCH) \ 1.42 + D(TOO_MUCH_MALLOC) \ 1.43 + D(ALLOC_TRIGGER) \ 1.44 + D(DEBUG_GC) \ 1.45 + D(TRANSPLANT) \ 1.46 + D(RESET) \ 1.47 + D(OUT_OF_NURSERY) \ 1.48 + D(EVICT_NURSERY) \ 1.49 + D(FULL_STORE_BUFFER) \ 1.50 + \ 1.51 + /* These are reserved for future use. */ \ 1.52 + D(RESERVED0) \ 1.53 + D(RESERVED1) \ 1.54 + D(RESERVED2) \ 1.55 + D(RESERVED3) \ 1.56 + D(RESERVED4) \ 1.57 + D(RESERVED5) \ 1.58 + D(RESERVED6) \ 1.59 + D(RESERVED7) \ 1.60 + D(RESERVED8) \ 1.61 + D(RESERVED9) \ 1.62 + D(RESERVED10) \ 1.63 + D(RESERVED11) \ 1.64 + D(RESERVED12) \ 1.65 + D(RESERVED13) \ 1.66 + D(RESERVED14) \ 1.67 + D(RESERVED15) \ 1.68 + D(RESERVED16) \ 1.69 + D(RESERVED17) \ 1.70 + D(RESERVED18) \ 1.71 + D(RESERVED19) \ 1.72 + \ 1.73 + /* Reasons from Firefox */ \ 1.74 + D(DOM_WINDOW_UTILS) \ 1.75 + D(COMPONENT_UTILS) \ 1.76 + D(MEM_PRESSURE) \ 1.77 + D(CC_WAITING) \ 1.78 + D(CC_FORCED) \ 1.79 + D(LOAD_END) \ 1.80 + D(POST_COMPARTMENT) \ 1.81 + D(PAGE_HIDE) \ 1.82 + D(NSJSCONTEXT_DESTROY) \ 1.83 + D(SET_NEW_DOCUMENT) \ 1.84 + D(SET_DOC_SHELL) \ 1.85 + D(DOM_UTILS) \ 1.86 + D(DOM_IPC) \ 1.87 + D(DOM_WORKER) \ 1.88 + D(INTER_SLICE_GC) \ 1.89 + D(REFRESH_FRAME) \ 1.90 + D(FULL_GC_TIMER) \ 1.91 + D(SHUTDOWN_CC) \ 1.92 + D(FINISH_LARGE_EVALUTE) 1.93 + 1.94 +namespace gcreason { 1.95 + 1.96 +/* GCReasons will end up looking like JSGC_MAYBEGC */ 1.97 +enum Reason { 1.98 +#define MAKE_REASON(name) name, 1.99 + GCREASONS(MAKE_REASON) 1.100 +#undef MAKE_REASON 1.101 + NO_REASON, 1.102 + NUM_REASONS, 1.103 + 1.104 + /* 1.105 + * For telemetry, we want to keep a fixed max bucket size over time so we 1.106 + * don't have to switch histograms. 100 is conservative; as of this writing 1.107 + * there are 26. But the cost of extra buckets seems to be low while the 1.108 + * cost of switching histograms is high. 1.109 + */ 1.110 + NUM_TELEMETRY_REASONS = 100 1.111 +}; 1.112 + 1.113 +} /* namespace gcreason */ 1.114 + 1.115 +/* 1.116 + * Zone GC: 1.117 + * 1.118 + * SpiderMonkey's GC is capable of performing a collection on an arbitrary 1.119 + * subset of the zones in the system. This allows an embedding to minimize 1.120 + * collection time by only collecting zones that have run code recently, 1.121 + * ignoring the parts of the heap that are unlikely to have changed. 1.122 + * 1.123 + * When triggering a GC using one of the functions below, it is first necessary 1.124 + * to select the zones to be collected. To do this, you can call 1.125 + * PrepareZoneForGC on each zone, or you can call PrepareForFullGC to select 1.126 + * all zones. Failing to select any zone is an error. 1.127 + */ 1.128 + 1.129 +/* 1.130 + * Schedule the given zone to be collected as part of the next GC. 1.131 + */ 1.132 +extern JS_FRIEND_API(void) 1.133 +PrepareZoneForGC(Zone *zone); 1.134 + 1.135 +/* 1.136 + * Schedule all zones to be collected in the next GC. 1.137 + */ 1.138 +extern JS_FRIEND_API(void) 1.139 +PrepareForFullGC(JSRuntime *rt); 1.140 + 1.141 +/* 1.142 + * When performing an incremental GC, the zones that were selected for the 1.143 + * previous incremental slice must be selected in subsequent slices as well. 1.144 + * This function selects those slices automatically. 1.145 + */ 1.146 +extern JS_FRIEND_API(void) 1.147 +PrepareForIncrementalGC(JSRuntime *rt); 1.148 + 1.149 +/* 1.150 + * Returns true if any zone in the system has been scheduled for GC with one of 1.151 + * the functions above or by the JS engine. 1.152 + */ 1.153 +extern JS_FRIEND_API(bool) 1.154 +IsGCScheduled(JSRuntime *rt); 1.155 + 1.156 +/* 1.157 + * Undoes the effect of the Prepare methods above. The given zone will not be 1.158 + * collected in the next GC. 1.159 + */ 1.160 +extern JS_FRIEND_API(void) 1.161 +SkipZoneForGC(Zone *zone); 1.162 + 1.163 +/* 1.164 + * Non-Incremental GC: 1.165 + * 1.166 + * The following functions perform a non-incremental GC. 1.167 + */ 1.168 + 1.169 +/* 1.170 + * Performs a non-incremental collection of all selected zones. Some objects 1.171 + * that are unreachable from the program may still be alive afterwards because 1.172 + * of internal references. 1.173 + */ 1.174 +extern JS_FRIEND_API(void) 1.175 +GCForReason(JSRuntime *rt, gcreason::Reason reason); 1.176 + 1.177 +/* 1.178 + * Perform a non-incremental collection after clearing caches and other 1.179 + * temporary references to objects. This will remove all unreferenced objects 1.180 + * in the system. 1.181 + */ 1.182 +extern JS_FRIEND_API(void) 1.183 +ShrinkingGC(JSRuntime *rt, gcreason::Reason reason); 1.184 + 1.185 +/* 1.186 + * Incremental GC: 1.187 + * 1.188 + * Incremental GC divides the full mark-and-sweep collection into multiple 1.189 + * slices, allowing client JavaScript code to run between each slice. This 1.190 + * allows interactive apps to avoid long collection pauses. Incremental GC does 1.191 + * not make collection take less time, it merely spreads that time out so that 1.192 + * the pauses are less noticable. 1.193 + * 1.194 + * For a collection to be carried out incrementally the following conditions 1.195 + * must be met: 1.196 + * - The collection must be run by calling JS::IncrementalGC() rather than 1.197 + * JS_GC(). 1.198 + * - The GC mode must have been set to JSGC_MODE_INCREMENTAL with 1.199 + * JS_SetGCParameter(). 1.200 + * - All native objects that have their own trace hook must indicate that they 1.201 + * implement read and write barriers with the JSCLASS_IMPLEMENTS_BARRIERS 1.202 + * flag. 1.203 + * 1.204 + * Note: Even if incremental GC is enabled and working correctly, 1.205 + * non-incremental collections can still happen when low on memory. 1.206 + */ 1.207 + 1.208 +/* 1.209 + * Begin an incremental collection and perform one slice worth of work or 1.210 + * perform a slice of an ongoing incremental collection. When this function 1.211 + * returns, the collection is not complete. This function must be called 1.212 + * repeatedly until !IsIncrementalGCInProgress(rt). 1.213 + * 1.214 + * Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or 1.215 + * shorter than the requested interval. 1.216 + */ 1.217 +extern JS_FRIEND_API(void) 1.218 +IncrementalGC(JSRuntime *rt, gcreason::Reason reason, int64_t millis = 0); 1.219 + 1.220 +/* 1.221 + * If IsIncrementalGCInProgress(rt), this call finishes the ongoing collection 1.222 + * by performing an arbitrarily long slice. If !IsIncrementalGCInProgress(rt), 1.223 + * this is equivalent to GCForReason. When this function returns, 1.224 + * IsIncrementalGCInProgress(rt) will always be false. 1.225 + */ 1.226 +extern JS_FRIEND_API(void) 1.227 +FinishIncrementalGC(JSRuntime *rt, gcreason::Reason reason); 1.228 + 1.229 +enum GCProgress { 1.230 + /* 1.231 + * During non-incremental GC, the GC is bracketed by JSGC_CYCLE_BEGIN/END 1.232 + * callbacks. During an incremental GC, the sequence of callbacks is as 1.233 + * follows: 1.234 + * JSGC_CYCLE_BEGIN, JSGC_SLICE_END (first slice) 1.235 + * JSGC_SLICE_BEGIN, JSGC_SLICE_END (second slice) 1.236 + * ... 1.237 + * JSGC_SLICE_BEGIN, JSGC_CYCLE_END (last slice) 1.238 + */ 1.239 + 1.240 + GC_CYCLE_BEGIN, 1.241 + GC_SLICE_BEGIN, 1.242 + GC_SLICE_END, 1.243 + GC_CYCLE_END 1.244 +}; 1.245 + 1.246 +struct JS_FRIEND_API(GCDescription) { 1.247 + bool isCompartment_; 1.248 + 1.249 + GCDescription(bool isCompartment) 1.250 + : isCompartment_(isCompartment) {} 1.251 + 1.252 + jschar *formatMessage(JSRuntime *rt) const; 1.253 + jschar *formatJSON(JSRuntime *rt, uint64_t timestamp) const; 1.254 +}; 1.255 + 1.256 +typedef void 1.257 +(* GCSliceCallback)(JSRuntime *rt, GCProgress progress, const GCDescription &desc); 1.258 + 1.259 +/* 1.260 + * The GC slice callback is called at the beginning and end of each slice. This 1.261 + * callback may be used for GC notifications as well as to perform additional 1.262 + * marking. 1.263 + */ 1.264 +extern JS_FRIEND_API(GCSliceCallback) 1.265 +SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback); 1.266 + 1.267 +/* 1.268 + * Incremental GC defaults to enabled, but may be disabled for testing or in 1.269 + * embeddings that have not yet implemented barriers on their native classes. 1.270 + * There is not currently a way to re-enable incremental GC once it has been 1.271 + * disabled on the runtime. 1.272 + */ 1.273 +extern JS_FRIEND_API(void) 1.274 +DisableIncrementalGC(JSRuntime *rt); 1.275 + 1.276 +/* 1.277 + * Returns true if incremental GC is enabled. Simply having incremental GC 1.278 + * enabled is not sufficient to ensure incremental collections are happening. 1.279 + * See the comment "Incremental GC" above for reasons why incremental GC may be 1.280 + * suppressed. Inspection of the "nonincremental reason" field of the 1.281 + * GCDescription returned by GCSliceCallback may help narrow down the cause if 1.282 + * collections are not happening incrementally when expected. 1.283 + */ 1.284 +extern JS_FRIEND_API(bool) 1.285 +IsIncrementalGCEnabled(JSRuntime *rt); 1.286 + 1.287 +/* 1.288 + * Returns true while an incremental GC is ongoing, both when actively 1.289 + * collecting and between slices. 1.290 + */ 1.291 +JS_FRIEND_API(bool) 1.292 +IsIncrementalGCInProgress(JSRuntime *rt); 1.293 + 1.294 +/* 1.295 + * Returns true when writes to GC things must call an incremental (pre) barrier. 1.296 + * This is generally only true when running mutator code in-between GC slices. 1.297 + * At other times, the barrier may be elided for performance. 1.298 + */ 1.299 +extern JS_FRIEND_API(bool) 1.300 +IsIncrementalBarrierNeeded(JSRuntime *rt); 1.301 + 1.302 +extern JS_FRIEND_API(bool) 1.303 +IsIncrementalBarrierNeeded(JSContext *cx); 1.304 + 1.305 +/* 1.306 + * Notify the GC that a reference to a GC thing is about to be overwritten. 1.307 + * These methods must be called if IsIncrementalBarrierNeeded. 1.308 + */ 1.309 +extern JS_FRIEND_API(void) 1.310 +IncrementalReferenceBarrier(void *ptr, JSGCTraceKind kind); 1.311 + 1.312 +extern JS_FRIEND_API(void) 1.313 +IncrementalValueBarrier(const Value &v); 1.314 + 1.315 +extern JS_FRIEND_API(void) 1.316 +IncrementalObjectBarrier(JSObject *obj); 1.317 + 1.318 +/* 1.319 + * Returns true if the most recent GC ran incrementally. 1.320 + */ 1.321 +extern JS_FRIEND_API(bool) 1.322 +WasIncrementalGC(JSRuntime *rt); 1.323 + 1.324 +/* 1.325 + * Generational GC: 1.326 + * 1.327 + * Note: Generational GC is not yet enabled by default. The following class 1.328 + * is non-functional unless SpiderMonkey was configured with 1.329 + * --enable-gcgenerational. 1.330 + */ 1.331 + 1.332 +/* Ensure that generational GC is disabled within some scope. */ 1.333 +class JS_FRIEND_API(AutoDisableGenerationalGC) 1.334 +{ 1.335 + JSRuntime *runtime; 1.336 +#if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL) 1.337 + bool restartVerifier; 1.338 +#endif 1.339 + 1.340 + public: 1.341 + AutoDisableGenerationalGC(JSRuntime *rt); 1.342 + ~AutoDisableGenerationalGC(); 1.343 +}; 1.344 + 1.345 +/* 1.346 + * Returns true if generational allocation and collection is currently enabled 1.347 + * on the given runtime. 1.348 + */ 1.349 +extern JS_FRIEND_API(bool) 1.350 +IsGenerationalGCEnabled(JSRuntime *rt); 1.351 + 1.352 +/* 1.353 + * Returns the GC's "number". This does not correspond directly to the number 1.354 + * of GCs that have been run, but is guaranteed to be monotonically increasing 1.355 + * with GC activity. 1.356 + */ 1.357 +extern JS_FRIEND_API(size_t) 1.358 +GetGCNumber(); 1.359 + 1.360 +/* 1.361 + * The GC does not immediately return the unused memory freed by a collection 1.362 + * back to the system incase it is needed soon afterwards. This call forces the 1.363 + * GC to return this memory immediately. 1.364 + */ 1.365 +extern JS_FRIEND_API(void) 1.366 +ShrinkGCBuffers(JSRuntime *rt); 1.367 + 1.368 +/* 1.369 + * Assert if any GC occured while this guard object was live. This is most 1.370 + * useful to help the exact rooting hazard analysis in complex regions, since 1.371 + * it cannot understand dataflow. 1.372 + * 1.373 + * Note: GC behavior is unpredictable even when deterministice and is generally 1.374 + * non-deterministic in practice. The fact that this guard has not 1.375 + * asserted is not a guarantee that a GC cannot happen in the guarded 1.376 + * region. As a rule, anyone performing a GC unsafe action should 1.377 + * understand the GC properties of all code in that region and ensure 1.378 + * that the hazard analysis is correct for that code, rather than relying 1.379 + * on this class. 1.380 + */ 1.381 +class JS_PUBLIC_API(AutoAssertNoGC) 1.382 +{ 1.383 +#ifdef JS_DEBUG 1.384 + JSRuntime *runtime; 1.385 + size_t gcNumber; 1.386 + 1.387 + public: 1.388 + AutoAssertNoGC(); 1.389 + AutoAssertNoGC(JSRuntime *rt); 1.390 + ~AutoAssertNoGC(); 1.391 +#else 1.392 + public: 1.393 + /* Prevent unreferenced local warnings in opt builds. */ 1.394 + AutoAssertNoGC() {} 1.395 + AutoAssertNoGC(JSRuntime *) {} 1.396 +#endif 1.397 +}; 1.398 + 1.399 +class JS_PUBLIC_API(ObjectPtr) 1.400 +{ 1.401 + Heap<JSObject *> value; 1.402 + 1.403 + public: 1.404 + ObjectPtr() : value(nullptr) {} 1.405 + 1.406 + ObjectPtr(JSObject *obj) : value(obj) {} 1.407 + 1.408 + /* Always call finalize before the destructor. */ 1.409 + ~ObjectPtr() { MOZ_ASSERT(!value); } 1.410 + 1.411 + void finalize(JSRuntime *rt) { 1.412 + if (IsIncrementalBarrierNeeded(rt)) 1.413 + IncrementalObjectBarrier(value); 1.414 + value = nullptr; 1.415 + } 1.416 + 1.417 + void init(JSObject *obj) { value = obj; } 1.418 + 1.419 + JSObject *get() const { return value; } 1.420 + 1.421 + void writeBarrierPre(JSRuntime *rt) { 1.422 + IncrementalObjectBarrier(value); 1.423 + } 1.424 + 1.425 + bool isAboutToBeFinalized(); 1.426 + 1.427 + ObjectPtr &operator=(JSObject *obj) { 1.428 + IncrementalObjectBarrier(value); 1.429 + value = obj; 1.430 + return *this; 1.431 + } 1.432 + 1.433 + void trace(JSTracer *trc, const char *name); 1.434 + 1.435 + JSObject &operator*() const { return *value; } 1.436 + JSObject *operator->() const { return value; } 1.437 + operator JSObject *() const { return value; } 1.438 +}; 1.439 + 1.440 +/* 1.441 + * Unsets the gray bit for anything reachable from |thing|. |kind| should not be 1.442 + * JSTRACE_SHAPE. |thing| should be non-null. 1.443 + */ 1.444 +extern JS_FRIEND_API(bool) 1.445 +UnmarkGrayGCThingRecursively(void *thing, JSGCTraceKind kind); 1.446 + 1.447 +/* 1.448 + * This should be called when an object that is marked gray is exposed to the JS 1.449 + * engine (by handing it to running JS code or writing it into live JS 1.450 + * data). During incremental GC, since the gray bits haven't been computed yet, 1.451 + * we conservatively mark the object black. 1.452 + */ 1.453 +static MOZ_ALWAYS_INLINE void 1.454 +ExposeGCThingToActiveJS(void *thing, JSGCTraceKind kind) 1.455 +{ 1.456 + MOZ_ASSERT(kind != JSTRACE_SHAPE); 1.457 + 1.458 + shadow::Runtime *rt = js::gc::GetGCThingRuntime(thing); 1.459 +#ifdef JSGC_GENERATIONAL 1.460 + /* 1.461 + * GC things residing in the nursery cannot be gray: they have no mark bits. 1.462 + * All live objects in the nursery are moved to tenured at the beginning of 1.463 + * each GC slice, so the gray marker never sees nursery things. 1.464 + */ 1.465 + if (js::gc::IsInsideNursery(rt, thing)) 1.466 + return; 1.467 +#endif 1.468 + if (IsIncrementalBarrierNeededOnGCThing(rt, thing, kind)) 1.469 + IncrementalReferenceBarrier(thing, kind); 1.470 + else if (GCThingIsMarkedGray(thing)) 1.471 + UnmarkGrayGCThingRecursively(thing, kind); 1.472 +} 1.473 + 1.474 +static MOZ_ALWAYS_INLINE void 1.475 +ExposeValueToActiveJS(const Value &v) 1.476 +{ 1.477 + if (v.isMarkable()) 1.478 + ExposeGCThingToActiveJS(v.toGCThing(), v.gcKind()); 1.479 +} 1.480 + 1.481 +static MOZ_ALWAYS_INLINE void 1.482 +ExposeObjectToActiveJS(JSObject *obj) 1.483 +{ 1.484 + ExposeGCThingToActiveJS(obj, JSTRACE_OBJECT); 1.485 +} 1.486 + 1.487 +/* 1.488 + * If a GC is currently marking, mark the object black. 1.489 + */ 1.490 +static MOZ_ALWAYS_INLINE void 1.491 +MarkGCThingAsLive(JSRuntime *rt_, void *thing, JSGCTraceKind kind) 1.492 +{ 1.493 + shadow::Runtime *rt = shadow::Runtime::asShadowRuntime(rt_); 1.494 +#ifdef JSGC_GENERATIONAL 1.495 + /* 1.496 + * Any object in the nursery will not be freed during any GC running at that time. 1.497 + */ 1.498 + if (js::gc::IsInsideNursery(rt, thing)) 1.499 + return; 1.500 +#endif 1.501 + if (IsIncrementalBarrierNeededOnGCThing(rt, thing, kind)) 1.502 + IncrementalReferenceBarrier(thing, kind); 1.503 +} 1.504 + 1.505 +static MOZ_ALWAYS_INLINE void 1.506 +MarkStringAsLive(Zone *zone, JSString *string) 1.507 +{ 1.508 + JSRuntime *rt = JS::shadow::Zone::asShadowZone(zone)->runtimeFromMainThread(); 1.509 + MarkGCThingAsLive(rt, string, JSTRACE_STRING); 1.510 +} 1.511 + 1.512 +/* 1.513 + * Internal to Firefox. 1.514 + * 1.515 + * Note: this is not related to the PokeGC in nsJSEnvironment. 1.516 + */ 1.517 +extern JS_FRIEND_API(void) 1.518 +PokeGC(JSRuntime *rt); 1.519 + 1.520 +/* 1.521 + * Internal to Firefox. 1.522 + */ 1.523 +extern JS_FRIEND_API(void) 1.524 +NotifyDidPaint(JSRuntime *rt); 1.525 + 1.526 +} /* namespace JS */ 1.527 + 1.528 +#endif /* js_GCAPI_h */