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