1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jsgc.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1149 @@ 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 +/* JS Garbage Collector. */ 1.11 + 1.12 +#ifndef jsgc_h 1.13 +#define jsgc_h 1.14 + 1.15 +#include "mozilla/DebugOnly.h" 1.16 +#include "mozilla/MemoryReporting.h" 1.17 + 1.18 +#include "jslock.h" 1.19 +#include "jsobj.h" 1.20 + 1.21 +#include "js/GCAPI.h" 1.22 +#include "js/SliceBudget.h" 1.23 +#include "js/Vector.h" 1.24 + 1.25 +class JSAtom; 1.26 +struct JSCompartment; 1.27 +class JSFlatString; 1.28 +class JSLinearString; 1.29 + 1.30 +namespace js { 1.31 + 1.32 +class ArgumentsObject; 1.33 +class ArrayBufferObject; 1.34 +class ArrayBufferViewObject; 1.35 +class SharedArrayBufferObject; 1.36 +class BaseShape; 1.37 +class DebugScopeObject; 1.38 +class GCHelperThread; 1.39 +class GlobalObject; 1.40 +class LazyScript; 1.41 +class Nursery; 1.42 +class PropertyName; 1.43 +class ScopeObject; 1.44 +class Shape; 1.45 +class UnownedBaseShape; 1.46 + 1.47 +unsigned GetCPUCount(); 1.48 + 1.49 +enum HeapState { 1.50 + Idle, // doing nothing with the GC heap 1.51 + Tracing, // tracing the GC heap without collecting, e.g. IterateCompartments() 1.52 + MajorCollecting, // doing a GC of the major heap 1.53 + MinorCollecting // doing a GC of the minor heap (nursery) 1.54 +}; 1.55 + 1.56 +namespace jit { 1.57 + class JitCode; 1.58 +} 1.59 + 1.60 +namespace gc { 1.61 + 1.62 +enum State { 1.63 + NO_INCREMENTAL, 1.64 + MARK_ROOTS, 1.65 + MARK, 1.66 + SWEEP, 1.67 + INVALID 1.68 +}; 1.69 + 1.70 +class ChunkPool { 1.71 + Chunk *emptyChunkListHead; 1.72 + size_t emptyCount; 1.73 + 1.74 + public: 1.75 + ChunkPool() 1.76 + : emptyChunkListHead(nullptr), 1.77 + emptyCount(0) { } 1.78 + 1.79 + size_t getEmptyCount() const { 1.80 + return emptyCount; 1.81 + } 1.82 + 1.83 + inline bool wantBackgroundAllocation(JSRuntime *rt) const; 1.84 + 1.85 + /* Must be called with the GC lock taken. */ 1.86 + inline Chunk *get(JSRuntime *rt); 1.87 + 1.88 + /* Must be called either during the GC or with the GC lock taken. */ 1.89 + inline void put(Chunk *chunk); 1.90 + 1.91 + /* 1.92 + * Return the list of chunks that can be released outside the GC lock. 1.93 + * Must be called either during the GC or with the GC lock taken. 1.94 + */ 1.95 + Chunk *expire(JSRuntime *rt, bool releaseAll); 1.96 + 1.97 + /* Must be called with the GC lock taken. */ 1.98 + void expireAndFree(JSRuntime *rt, bool releaseAll); 1.99 +}; 1.100 + 1.101 +static inline JSGCTraceKind 1.102 +MapAllocToTraceKind(AllocKind kind) 1.103 +{ 1.104 + static const JSGCTraceKind map[] = { 1.105 + JSTRACE_OBJECT, /* FINALIZE_OBJECT0 */ 1.106 + JSTRACE_OBJECT, /* FINALIZE_OBJECT0_BACKGROUND */ 1.107 + JSTRACE_OBJECT, /* FINALIZE_OBJECT2 */ 1.108 + JSTRACE_OBJECT, /* FINALIZE_OBJECT2_BACKGROUND */ 1.109 + JSTRACE_OBJECT, /* FINALIZE_OBJECT4 */ 1.110 + JSTRACE_OBJECT, /* FINALIZE_OBJECT4_BACKGROUND */ 1.111 + JSTRACE_OBJECT, /* FINALIZE_OBJECT8 */ 1.112 + JSTRACE_OBJECT, /* FINALIZE_OBJECT8_BACKGROUND */ 1.113 + JSTRACE_OBJECT, /* FINALIZE_OBJECT12 */ 1.114 + JSTRACE_OBJECT, /* FINALIZE_OBJECT12_BACKGROUND */ 1.115 + JSTRACE_OBJECT, /* FINALIZE_OBJECT16 */ 1.116 + JSTRACE_OBJECT, /* FINALIZE_OBJECT16_BACKGROUND */ 1.117 + JSTRACE_SCRIPT, /* FINALIZE_SCRIPT */ 1.118 + JSTRACE_LAZY_SCRIPT,/* FINALIZE_LAZY_SCRIPT */ 1.119 + JSTRACE_SHAPE, /* FINALIZE_SHAPE */ 1.120 + JSTRACE_BASE_SHAPE, /* FINALIZE_BASE_SHAPE */ 1.121 + JSTRACE_TYPE_OBJECT,/* FINALIZE_TYPE_OBJECT */ 1.122 + JSTRACE_STRING, /* FINALIZE_FAT_INLINE_STRING */ 1.123 + JSTRACE_STRING, /* FINALIZE_STRING */ 1.124 + JSTRACE_STRING, /* FINALIZE_EXTERNAL_STRING */ 1.125 + JSTRACE_JITCODE, /* FINALIZE_JITCODE */ 1.126 + }; 1.127 + JS_STATIC_ASSERT(JS_ARRAY_LENGTH(map) == FINALIZE_LIMIT); 1.128 + return map[kind]; 1.129 +} 1.130 + 1.131 +template <typename T> struct MapTypeToTraceKind {}; 1.132 +template <> struct MapTypeToTraceKind<ObjectImpl> { static const JSGCTraceKind kind = JSTRACE_OBJECT; }; 1.133 +template <> struct MapTypeToTraceKind<JSObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; }; 1.134 +template <> struct MapTypeToTraceKind<JSFunction> { static const JSGCTraceKind kind = JSTRACE_OBJECT; }; 1.135 +template <> struct MapTypeToTraceKind<ArgumentsObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; }; 1.136 +template <> struct MapTypeToTraceKind<ArrayBufferObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; }; 1.137 +template <> struct MapTypeToTraceKind<ArrayBufferViewObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; }; 1.138 +template <> struct MapTypeToTraceKind<SharedArrayBufferObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; }; 1.139 +template <> struct MapTypeToTraceKind<DebugScopeObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; }; 1.140 +template <> struct MapTypeToTraceKind<GlobalObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; }; 1.141 +template <> struct MapTypeToTraceKind<ScopeObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; }; 1.142 +template <> struct MapTypeToTraceKind<JSScript> { static const JSGCTraceKind kind = JSTRACE_SCRIPT; }; 1.143 +template <> struct MapTypeToTraceKind<LazyScript> { static const JSGCTraceKind kind = JSTRACE_LAZY_SCRIPT; }; 1.144 +template <> struct MapTypeToTraceKind<Shape> { static const JSGCTraceKind kind = JSTRACE_SHAPE; }; 1.145 +template <> struct MapTypeToTraceKind<BaseShape> { static const JSGCTraceKind kind = JSTRACE_BASE_SHAPE; }; 1.146 +template <> struct MapTypeToTraceKind<UnownedBaseShape> { static const JSGCTraceKind kind = JSTRACE_BASE_SHAPE; }; 1.147 +template <> struct MapTypeToTraceKind<types::TypeObject>{ static const JSGCTraceKind kind = JSTRACE_TYPE_OBJECT; }; 1.148 +template <> struct MapTypeToTraceKind<JSAtom> { static const JSGCTraceKind kind = JSTRACE_STRING; }; 1.149 +template <> struct MapTypeToTraceKind<JSString> { static const JSGCTraceKind kind = JSTRACE_STRING; }; 1.150 +template <> struct MapTypeToTraceKind<JSFlatString> { static const JSGCTraceKind kind = JSTRACE_STRING; }; 1.151 +template <> struct MapTypeToTraceKind<JSLinearString> { static const JSGCTraceKind kind = JSTRACE_STRING; }; 1.152 +template <> struct MapTypeToTraceKind<PropertyName> { static const JSGCTraceKind kind = JSTRACE_STRING; }; 1.153 +template <> struct MapTypeToTraceKind<jit::JitCode> { static const JSGCTraceKind kind = JSTRACE_JITCODE; }; 1.154 + 1.155 +/* Map from C++ type to finalize kind. JSObject does not have a 1:1 mapping, so must use Arena::thingSize. */ 1.156 +template <typename T> struct MapTypeToFinalizeKind {}; 1.157 +template <> struct MapTypeToFinalizeKind<JSScript> { static const AllocKind kind = FINALIZE_SCRIPT; }; 1.158 +template <> struct MapTypeToFinalizeKind<LazyScript> { static const AllocKind kind = FINALIZE_LAZY_SCRIPT; }; 1.159 +template <> struct MapTypeToFinalizeKind<Shape> { static const AllocKind kind = FINALIZE_SHAPE; }; 1.160 +template <> struct MapTypeToFinalizeKind<BaseShape> { static const AllocKind kind = FINALIZE_BASE_SHAPE; }; 1.161 +template <> struct MapTypeToFinalizeKind<types::TypeObject> { static const AllocKind kind = FINALIZE_TYPE_OBJECT; }; 1.162 +template <> struct MapTypeToFinalizeKind<JSFatInlineString> { static const AllocKind kind = FINALIZE_FAT_INLINE_STRING; }; 1.163 +template <> struct MapTypeToFinalizeKind<JSString> { static const AllocKind kind = FINALIZE_STRING; }; 1.164 +template <> struct MapTypeToFinalizeKind<JSExternalString> { static const AllocKind kind = FINALIZE_EXTERNAL_STRING; }; 1.165 +template <> struct MapTypeToFinalizeKind<jit::JitCode> { static const AllocKind kind = FINALIZE_JITCODE; }; 1.166 + 1.167 +#if defined(JSGC_GENERATIONAL) || defined(DEBUG) 1.168 +static inline bool 1.169 +IsNurseryAllocable(AllocKind kind) 1.170 +{ 1.171 + JS_ASSERT(kind >= 0 && unsigned(kind) < FINALIZE_LIMIT); 1.172 + static const bool map[] = { 1.173 + false, /* FINALIZE_OBJECT0 */ 1.174 + true, /* FINALIZE_OBJECT0_BACKGROUND */ 1.175 + false, /* FINALIZE_OBJECT2 */ 1.176 + true, /* FINALIZE_OBJECT2_BACKGROUND */ 1.177 + false, /* FINALIZE_OBJECT4 */ 1.178 + true, /* FINALIZE_OBJECT4_BACKGROUND */ 1.179 + false, /* FINALIZE_OBJECT8 */ 1.180 + true, /* FINALIZE_OBJECT8_BACKGROUND */ 1.181 + false, /* FINALIZE_OBJECT12 */ 1.182 + true, /* FINALIZE_OBJECT12_BACKGROUND */ 1.183 + false, /* FINALIZE_OBJECT16 */ 1.184 + true, /* FINALIZE_OBJECT16_BACKGROUND */ 1.185 + false, /* FINALIZE_SCRIPT */ 1.186 + false, /* FINALIZE_LAZY_SCRIPT */ 1.187 + false, /* FINALIZE_SHAPE */ 1.188 + false, /* FINALIZE_BASE_SHAPE */ 1.189 + false, /* FINALIZE_TYPE_OBJECT */ 1.190 + false, /* FINALIZE_FAT_INLINE_STRING */ 1.191 + false, /* FINALIZE_STRING */ 1.192 + false, /* FINALIZE_EXTERNAL_STRING */ 1.193 + false, /* FINALIZE_JITCODE */ 1.194 + }; 1.195 + JS_STATIC_ASSERT(JS_ARRAY_LENGTH(map) == FINALIZE_LIMIT); 1.196 + return map[kind]; 1.197 +} 1.198 +#endif 1.199 + 1.200 +static inline bool 1.201 +IsBackgroundFinalized(AllocKind kind) 1.202 +{ 1.203 + JS_ASSERT(kind >= 0 && unsigned(kind) < FINALIZE_LIMIT); 1.204 + static const bool map[] = { 1.205 + false, /* FINALIZE_OBJECT0 */ 1.206 + true, /* FINALIZE_OBJECT0_BACKGROUND */ 1.207 + false, /* FINALIZE_OBJECT2 */ 1.208 + true, /* FINALIZE_OBJECT2_BACKGROUND */ 1.209 + false, /* FINALIZE_OBJECT4 */ 1.210 + true, /* FINALIZE_OBJECT4_BACKGROUND */ 1.211 + false, /* FINALIZE_OBJECT8 */ 1.212 + true, /* FINALIZE_OBJECT8_BACKGROUND */ 1.213 + false, /* FINALIZE_OBJECT12 */ 1.214 + true, /* FINALIZE_OBJECT12_BACKGROUND */ 1.215 + false, /* FINALIZE_OBJECT16 */ 1.216 + true, /* FINALIZE_OBJECT16_BACKGROUND */ 1.217 + false, /* FINALIZE_SCRIPT */ 1.218 + false, /* FINALIZE_LAZY_SCRIPT */ 1.219 + true, /* FINALIZE_SHAPE */ 1.220 + true, /* FINALIZE_BASE_SHAPE */ 1.221 + true, /* FINALIZE_TYPE_OBJECT */ 1.222 + true, /* FINALIZE_FAT_INLINE_STRING */ 1.223 + true, /* FINALIZE_STRING */ 1.224 + false, /* FINALIZE_EXTERNAL_STRING */ 1.225 + false, /* FINALIZE_JITCODE */ 1.226 + }; 1.227 + JS_STATIC_ASSERT(JS_ARRAY_LENGTH(map) == FINALIZE_LIMIT); 1.228 + return map[kind]; 1.229 +} 1.230 + 1.231 +static inline bool 1.232 +CanBeFinalizedInBackground(gc::AllocKind kind, const Class *clasp) 1.233 +{ 1.234 + JS_ASSERT(kind <= gc::FINALIZE_OBJECT_LAST); 1.235 + /* If the class has no finalizer or a finalizer that is safe to call on 1.236 + * a different thread, we change the finalize kind. For example, 1.237 + * FINALIZE_OBJECT0 calls the finalizer on the main thread, 1.238 + * FINALIZE_OBJECT0_BACKGROUND calls the finalizer on the gcHelperThread. 1.239 + * IsBackgroundFinalized is called to prevent recursively incrementing 1.240 + * the finalize kind; kind may already be a background finalize kind. 1.241 + */ 1.242 + return (!gc::IsBackgroundFinalized(kind) && 1.243 + (!clasp->finalize || (clasp->flags & JSCLASS_BACKGROUND_FINALIZE))); 1.244 +} 1.245 + 1.246 +inline JSGCTraceKind 1.247 +GetGCThingTraceKind(const void *thing); 1.248 + 1.249 +/* Capacity for slotsToThingKind */ 1.250 +const size_t SLOTS_TO_THING_KIND_LIMIT = 17; 1.251 + 1.252 +extern const AllocKind slotsToThingKind[]; 1.253 + 1.254 +/* Get the best kind to use when making an object with the given slot count. */ 1.255 +static inline AllocKind 1.256 +GetGCObjectKind(size_t numSlots) 1.257 +{ 1.258 + if (numSlots >= SLOTS_TO_THING_KIND_LIMIT) 1.259 + return FINALIZE_OBJECT16; 1.260 + return slotsToThingKind[numSlots]; 1.261 +} 1.262 + 1.263 +/* As for GetGCObjectKind, but for dense array allocation. */ 1.264 +static inline AllocKind 1.265 +GetGCArrayKind(size_t numSlots) 1.266 +{ 1.267 + /* 1.268 + * Dense arrays can use their fixed slots to hold their elements array 1.269 + * (less two Values worth of ObjectElements header), but if more than the 1.270 + * maximum number of fixed slots is needed then the fixed slots will be 1.271 + * unused. 1.272 + */ 1.273 + JS_STATIC_ASSERT(ObjectElements::VALUES_PER_HEADER == 2); 1.274 + if (numSlots > JSObject::NELEMENTS_LIMIT || numSlots + 2 >= SLOTS_TO_THING_KIND_LIMIT) 1.275 + return FINALIZE_OBJECT2; 1.276 + return slotsToThingKind[numSlots + 2]; 1.277 +} 1.278 + 1.279 +static inline AllocKind 1.280 +GetGCObjectFixedSlotsKind(size_t numFixedSlots) 1.281 +{ 1.282 + JS_ASSERT(numFixedSlots < SLOTS_TO_THING_KIND_LIMIT); 1.283 + return slotsToThingKind[numFixedSlots]; 1.284 +} 1.285 + 1.286 +static inline AllocKind 1.287 +GetBackgroundAllocKind(AllocKind kind) 1.288 +{ 1.289 + JS_ASSERT(!IsBackgroundFinalized(kind)); 1.290 + JS_ASSERT(kind <= FINALIZE_OBJECT_LAST); 1.291 + return (AllocKind) (kind + 1); 1.292 +} 1.293 + 1.294 +/* 1.295 + * Try to get the next larger size for an object, keeping BACKGROUND 1.296 + * consistent. 1.297 + */ 1.298 +static inline bool 1.299 +TryIncrementAllocKind(AllocKind *kindp) 1.300 +{ 1.301 + size_t next = size_t(*kindp) + 2; 1.302 + if (next >= size_t(FINALIZE_OBJECT_LIMIT)) 1.303 + return false; 1.304 + *kindp = AllocKind(next); 1.305 + return true; 1.306 +} 1.307 + 1.308 +/* Get the number of fixed slots and initial capacity associated with a kind. */ 1.309 +static inline size_t 1.310 +GetGCKindSlots(AllocKind thingKind) 1.311 +{ 1.312 + /* Using a switch in hopes that thingKind will usually be a compile-time constant. */ 1.313 + switch (thingKind) { 1.314 + case FINALIZE_OBJECT0: 1.315 + case FINALIZE_OBJECT0_BACKGROUND: 1.316 + return 0; 1.317 + case FINALIZE_OBJECT2: 1.318 + case FINALIZE_OBJECT2_BACKGROUND: 1.319 + return 2; 1.320 + case FINALIZE_OBJECT4: 1.321 + case FINALIZE_OBJECT4_BACKGROUND: 1.322 + return 4; 1.323 + case FINALIZE_OBJECT8: 1.324 + case FINALIZE_OBJECT8_BACKGROUND: 1.325 + return 8; 1.326 + case FINALIZE_OBJECT12: 1.327 + case FINALIZE_OBJECT12_BACKGROUND: 1.328 + return 12; 1.329 + case FINALIZE_OBJECT16: 1.330 + case FINALIZE_OBJECT16_BACKGROUND: 1.331 + return 16; 1.332 + default: 1.333 + MOZ_ASSUME_UNREACHABLE("Bad object finalize kind"); 1.334 + } 1.335 +} 1.336 + 1.337 +static inline size_t 1.338 +GetGCKindSlots(AllocKind thingKind, const Class *clasp) 1.339 +{ 1.340 + size_t nslots = GetGCKindSlots(thingKind); 1.341 + 1.342 + /* An object's private data uses the space taken by its last fixed slot. */ 1.343 + if (clasp->flags & JSCLASS_HAS_PRIVATE) { 1.344 + JS_ASSERT(nslots > 0); 1.345 + nslots--; 1.346 + } 1.347 + 1.348 + /* 1.349 + * Functions have a larger finalize kind than FINALIZE_OBJECT to reserve 1.350 + * space for the extra fields in JSFunction, but have no fixed slots. 1.351 + */ 1.352 + if (clasp == FunctionClassPtr) 1.353 + nslots = 0; 1.354 + 1.355 + return nslots; 1.356 +} 1.357 + 1.358 +/* 1.359 + * ArenaList::head points to the start of the list. Normally cursor points 1.360 + * to the first arena in the list with some free things and all arenas 1.361 + * before cursor are fully allocated. However, as the arena currently being 1.362 + * allocated from is considered full while its list of free spans is moved 1.363 + * into the freeList, during the GC or cell enumeration, when an 1.364 + * unallocated freeList is moved back to the arena, we can see an arena 1.365 + * with some free cells before the cursor. The cursor is an indirect 1.366 + * pointer to allow for efficient list insertion at the cursor point and 1.367 + * other list manipulations. 1.368 + */ 1.369 +struct ArenaList { 1.370 + ArenaHeader *head; 1.371 + ArenaHeader **cursor; 1.372 + 1.373 + ArenaList() { 1.374 + clear(); 1.375 + } 1.376 + 1.377 + void clear() { 1.378 + head = nullptr; 1.379 + cursor = &head; 1.380 + } 1.381 + 1.382 + void insert(ArenaHeader *arena); 1.383 +}; 1.384 + 1.385 +class ArenaLists 1.386 +{ 1.387 + /* 1.388 + * For each arena kind its free list is represented as the first span with 1.389 + * free things. Initially all the spans are initialized as empty. After we 1.390 + * find a new arena with available things we move its first free span into 1.391 + * the list and set the arena as fully allocated. way we do not need to 1.392 + * update the arena header after the initial allocation. When starting the 1.393 + * GC we only move the head of the of the list of spans back to the arena 1.394 + * only for the arena that was not fully allocated. 1.395 + */ 1.396 + FreeSpan freeLists[FINALIZE_LIMIT]; 1.397 + 1.398 + ArenaList arenaLists[FINALIZE_LIMIT]; 1.399 + 1.400 + /* 1.401 + * The background finalization adds the finalized arenas to the list at 1.402 + * the *cursor position. backgroundFinalizeState controls the interaction 1.403 + * between the GC lock and the access to the list from the allocation 1.404 + * thread. 1.405 + * 1.406 + * BFS_DONE indicates that the finalizations is not running or cannot 1.407 + * affect this arena list. The allocation thread can access the list 1.408 + * outside the GC lock. 1.409 + * 1.410 + * In BFS_RUN and BFS_JUST_FINISHED the allocation thread must take the 1.411 + * lock. The former indicates that the finalization still runs. The latter 1.412 + * signals that finalization just added to the list finalized arenas. In 1.413 + * that case the lock effectively serves as a read barrier to ensure that 1.414 + * the allocation thread see all the writes done during finalization. 1.415 + */ 1.416 + enum BackgroundFinalizeState { 1.417 + BFS_DONE, 1.418 + BFS_RUN, 1.419 + BFS_JUST_FINISHED 1.420 + }; 1.421 + 1.422 + volatile uintptr_t backgroundFinalizeState[FINALIZE_LIMIT]; 1.423 + 1.424 + public: 1.425 + /* For each arena kind, a list of arenas remaining to be swept. */ 1.426 + ArenaHeader *arenaListsToSweep[FINALIZE_LIMIT]; 1.427 + 1.428 + /* Shape arenas to be swept in the foreground. */ 1.429 + ArenaHeader *gcShapeArenasToSweep; 1.430 + 1.431 + public: 1.432 + ArenaLists() { 1.433 + for (size_t i = 0; i != FINALIZE_LIMIT; ++i) 1.434 + freeLists[i].initAsEmpty(); 1.435 + for (size_t i = 0; i != FINALIZE_LIMIT; ++i) 1.436 + backgroundFinalizeState[i] = BFS_DONE; 1.437 + for (size_t i = 0; i != FINALIZE_LIMIT; ++i) 1.438 + arenaListsToSweep[i] = nullptr; 1.439 + gcShapeArenasToSweep = nullptr; 1.440 + } 1.441 + 1.442 + ~ArenaLists() { 1.443 + for (size_t i = 0; i != FINALIZE_LIMIT; ++i) { 1.444 + /* 1.445 + * We can only call this during the shutdown after the last GC when 1.446 + * the background finalization is disabled. 1.447 + */ 1.448 + JS_ASSERT(backgroundFinalizeState[i] == BFS_DONE); 1.449 + ArenaHeader **headp = &arenaLists[i].head; 1.450 + while (ArenaHeader *aheader = *headp) { 1.451 + *headp = aheader->next; 1.452 + aheader->chunk()->releaseArena(aheader); 1.453 + } 1.454 + } 1.455 + } 1.456 + 1.457 + static uintptr_t getFreeListOffset(AllocKind thingKind) { 1.458 + uintptr_t offset = offsetof(ArenaLists, freeLists); 1.459 + return offset + thingKind * sizeof(FreeSpan); 1.460 + } 1.461 + 1.462 + const FreeSpan *getFreeList(AllocKind thingKind) const { 1.463 + return &freeLists[thingKind]; 1.464 + } 1.465 + 1.466 + ArenaHeader *getFirstArena(AllocKind thingKind) const { 1.467 + return arenaLists[thingKind].head; 1.468 + } 1.469 + 1.470 + ArenaHeader *getFirstArenaToSweep(AllocKind thingKind) const { 1.471 + return arenaListsToSweep[thingKind]; 1.472 + } 1.473 + 1.474 + bool arenaListsAreEmpty() const { 1.475 + for (size_t i = 0; i != FINALIZE_LIMIT; ++i) { 1.476 + /* 1.477 + * The arena cannot be empty if the background finalization is not yet 1.478 + * done. 1.479 + */ 1.480 + if (backgroundFinalizeState[i] != BFS_DONE) 1.481 + return false; 1.482 + if (arenaLists[i].head) 1.483 + return false; 1.484 + } 1.485 + return true; 1.486 + } 1.487 + 1.488 + bool arenasAreFull(AllocKind thingKind) const { 1.489 + return !*arenaLists[thingKind].cursor; 1.490 + } 1.491 + 1.492 + void unmarkAll() { 1.493 + for (size_t i = 0; i != FINALIZE_LIMIT; ++i) { 1.494 + /* The background finalization must have stopped at this point. */ 1.495 + JS_ASSERT(backgroundFinalizeState[i] == BFS_DONE || 1.496 + backgroundFinalizeState[i] == BFS_JUST_FINISHED); 1.497 + for (ArenaHeader *aheader = arenaLists[i].head; aheader; aheader = aheader->next) { 1.498 + uintptr_t *word = aheader->chunk()->bitmap.arenaBits(aheader); 1.499 + memset(word, 0, ArenaBitmapWords * sizeof(uintptr_t)); 1.500 + } 1.501 + } 1.502 + } 1.503 + 1.504 + bool doneBackgroundFinalize(AllocKind kind) const { 1.505 + return backgroundFinalizeState[kind] == BFS_DONE || 1.506 + backgroundFinalizeState[kind] == BFS_JUST_FINISHED; 1.507 + } 1.508 + 1.509 + bool needBackgroundFinalizeWait(AllocKind kind) const { 1.510 + return backgroundFinalizeState[kind] != BFS_DONE; 1.511 + } 1.512 + 1.513 + /* 1.514 + * Return the free list back to the arena so the GC finalization will not 1.515 + * run the finalizers over unitialized bytes from free things. 1.516 + */ 1.517 + void purge() { 1.518 + for (size_t i = 0; i != FINALIZE_LIMIT; ++i) 1.519 + purge(AllocKind(i)); 1.520 + } 1.521 + 1.522 + void purge(AllocKind i) { 1.523 + FreeSpan *headSpan = &freeLists[i]; 1.524 + if (!headSpan->isEmpty()) { 1.525 + ArenaHeader *aheader = headSpan->arenaHeader(); 1.526 + aheader->setFirstFreeSpan(headSpan); 1.527 + headSpan->initAsEmpty(); 1.528 + } 1.529 + } 1.530 + 1.531 + inline void prepareForIncrementalGC(JSRuntime *rt); 1.532 + 1.533 + /* 1.534 + * Temporarily copy the free list heads to the arenas so the code can see 1.535 + * the proper value in ArenaHeader::freeList when accessing the latter 1.536 + * outside the GC. 1.537 + */ 1.538 + void copyFreeListsToArenas() { 1.539 + for (size_t i = 0; i != FINALIZE_LIMIT; ++i) 1.540 + copyFreeListToArena(AllocKind(i)); 1.541 + } 1.542 + 1.543 + void copyFreeListToArena(AllocKind thingKind) { 1.544 + FreeSpan *headSpan = &freeLists[thingKind]; 1.545 + if (!headSpan->isEmpty()) { 1.546 + ArenaHeader *aheader = headSpan->arenaHeader(); 1.547 + JS_ASSERT(!aheader->hasFreeThings()); 1.548 + aheader->setFirstFreeSpan(headSpan); 1.549 + } 1.550 + } 1.551 + 1.552 + /* 1.553 + * Clear the free lists in arenas that were temporarily set there using 1.554 + * copyToArenas. 1.555 + */ 1.556 + void clearFreeListsInArenas() { 1.557 + for (size_t i = 0; i != FINALIZE_LIMIT; ++i) 1.558 + clearFreeListInArena(AllocKind(i)); 1.559 + } 1.560 + 1.561 + 1.562 + void clearFreeListInArena(AllocKind kind) { 1.563 + FreeSpan *headSpan = &freeLists[kind]; 1.564 + if (!headSpan->isEmpty()) { 1.565 + ArenaHeader *aheader = headSpan->arenaHeader(); 1.566 + JS_ASSERT(aheader->getFirstFreeSpan().isSameNonEmptySpan(headSpan)); 1.567 + aheader->setAsFullyUsed(); 1.568 + } 1.569 + } 1.570 + 1.571 + /* 1.572 + * Check that the free list is either empty or were synchronized with the 1.573 + * arena using copyToArena(). 1.574 + */ 1.575 + bool isSynchronizedFreeList(AllocKind kind) { 1.576 + FreeSpan *headSpan = &freeLists[kind]; 1.577 + if (headSpan->isEmpty()) 1.578 + return true; 1.579 + ArenaHeader *aheader = headSpan->arenaHeader(); 1.580 + if (aheader->hasFreeThings()) { 1.581 + /* 1.582 + * If the arena has a free list, it must be the same as one in 1.583 + * lists. 1.584 + */ 1.585 + JS_ASSERT(aheader->getFirstFreeSpan().isSameNonEmptySpan(headSpan)); 1.586 + return true; 1.587 + } 1.588 + return false; 1.589 + } 1.590 + 1.591 + MOZ_ALWAYS_INLINE void *allocateFromFreeList(AllocKind thingKind, size_t thingSize) { 1.592 + return freeLists[thingKind].allocate(thingSize); 1.593 + } 1.594 + 1.595 + template <AllowGC allowGC> 1.596 + static void *refillFreeList(ThreadSafeContext *cx, AllocKind thingKind); 1.597 + 1.598 + /* 1.599 + * Moves all arenas from |fromArenaLists| into |this|. In 1.600 + * parallel blocks, we temporarily create one ArenaLists per 1.601 + * parallel thread. When the parallel block ends, we move 1.602 + * whatever allocations may have been performed back into the 1.603 + * compartment's main arena list using this function. 1.604 + */ 1.605 + void adoptArenas(JSRuntime *runtime, ArenaLists *fromArenaLists); 1.606 + 1.607 + /* True if the ArenaHeader in question is found in this ArenaLists */ 1.608 + bool containsArena(JSRuntime *runtime, ArenaHeader *arenaHeader); 1.609 + 1.610 + void checkEmptyFreeLists() { 1.611 +#ifdef DEBUG 1.612 + for (size_t i = 0; i < mozilla::ArrayLength(freeLists); ++i) 1.613 + JS_ASSERT(freeLists[i].isEmpty()); 1.614 +#endif 1.615 + } 1.616 + 1.617 + void checkEmptyFreeList(AllocKind kind) { 1.618 + JS_ASSERT(freeLists[kind].isEmpty()); 1.619 + } 1.620 + 1.621 + void queueObjectsForSweep(FreeOp *fop); 1.622 + void queueStringsForSweep(FreeOp *fop); 1.623 + void queueShapesForSweep(FreeOp *fop); 1.624 + void queueScriptsForSweep(FreeOp *fop); 1.625 + void queueJitCodeForSweep(FreeOp *fop); 1.626 + 1.627 + bool foregroundFinalize(FreeOp *fop, AllocKind thingKind, SliceBudget &sliceBudget); 1.628 + static void backgroundFinalize(FreeOp *fop, ArenaHeader *listHead, bool onBackgroundThread); 1.629 + 1.630 + void wipeDuringParallelExecution(JSRuntime *rt); 1.631 + 1.632 + private: 1.633 + inline void finalizeNow(FreeOp *fop, AllocKind thingKind); 1.634 + inline void forceFinalizeNow(FreeOp *fop, AllocKind thingKind); 1.635 + inline void queueForForegroundSweep(FreeOp *fop, AllocKind thingKind); 1.636 + inline void queueForBackgroundSweep(FreeOp *fop, AllocKind thingKind); 1.637 + 1.638 + void *allocateFromArena(JS::Zone *zone, AllocKind thingKind); 1.639 + inline void *allocateFromArenaInline(JS::Zone *zone, AllocKind thingKind); 1.640 + 1.641 + inline void normalizeBackgroundFinalizeState(AllocKind thingKind); 1.642 + 1.643 + friend class js::Nursery; 1.644 +}; 1.645 + 1.646 +/* 1.647 + * Initial allocation size for data structures holding chunks is set to hold 1.648 + * chunks with total capacity of 16MB to avoid buffer resizes during browser 1.649 + * startup. 1.650 + */ 1.651 +const size_t INITIAL_CHUNK_CAPACITY = 16 * 1024 * 1024 / ChunkSize; 1.652 + 1.653 +/* The number of GC cycles an empty chunk can survive before been released. */ 1.654 +const size_t MAX_EMPTY_CHUNK_AGE = 4; 1.655 + 1.656 +} /* namespace gc */ 1.657 + 1.658 +typedef enum JSGCRootType { 1.659 + JS_GC_ROOT_VALUE_PTR, 1.660 + JS_GC_ROOT_STRING_PTR, 1.661 + JS_GC_ROOT_OBJECT_PTR, 1.662 + JS_GC_ROOT_SCRIPT_PTR 1.663 +} JSGCRootType; 1.664 + 1.665 +struct RootInfo { 1.666 + RootInfo() {} 1.667 + RootInfo(const char *name, JSGCRootType type) : name(name), type(type) {} 1.668 + const char *name; 1.669 + JSGCRootType type; 1.670 +}; 1.671 + 1.672 +typedef js::HashMap<void *, 1.673 + RootInfo, 1.674 + js::DefaultHasher<void *>, 1.675 + js::SystemAllocPolicy> RootedValueMap; 1.676 + 1.677 +extern bool 1.678 +AddValueRoot(JSContext *cx, js::Value *vp, const char *name); 1.679 + 1.680 +extern bool 1.681 +AddValueRootRT(JSRuntime *rt, js::Value *vp, const char *name); 1.682 + 1.683 +extern bool 1.684 +AddStringRoot(JSContext *cx, JSString **rp, const char *name); 1.685 + 1.686 +extern bool 1.687 +AddObjectRoot(JSContext *cx, JSObject **rp, const char *name); 1.688 + 1.689 +extern bool 1.690 +AddObjectRoot(JSRuntime *rt, JSObject **rp, const char *name); 1.691 + 1.692 +extern bool 1.693 +AddScriptRoot(JSContext *cx, JSScript **rp, const char *name); 1.694 + 1.695 +extern void 1.696 +RemoveRoot(JSRuntime *rt, void *rp); 1.697 + 1.698 +} /* namespace js */ 1.699 + 1.700 +extern bool 1.701 +js_InitGC(JSRuntime *rt, uint32_t maxbytes); 1.702 + 1.703 +extern void 1.704 +js_FinishGC(JSRuntime *rt); 1.705 + 1.706 +namespace js { 1.707 + 1.708 +class InterpreterFrame; 1.709 + 1.710 +extern void 1.711 +MarkCompartmentActive(js::InterpreterFrame *fp); 1.712 + 1.713 +extern void 1.714 +TraceRuntime(JSTracer *trc); 1.715 + 1.716 +/* Must be called with GC lock taken. */ 1.717 +extern bool 1.718 +TriggerGC(JSRuntime *rt, JS::gcreason::Reason reason); 1.719 + 1.720 +/* Must be called with GC lock taken. */ 1.721 +extern bool 1.722 +TriggerZoneGC(Zone *zone, JS::gcreason::Reason reason); 1.723 + 1.724 +extern void 1.725 +MaybeGC(JSContext *cx); 1.726 + 1.727 +extern void 1.728 +ReleaseAllJITCode(FreeOp *op); 1.729 + 1.730 +/* 1.731 + * Kinds of js_GC invocation. 1.732 + */ 1.733 +typedef enum JSGCInvocationKind { 1.734 + /* Normal invocation. */ 1.735 + GC_NORMAL = 0, 1.736 + 1.737 + /* Minimize GC triggers and release empty GC chunks right away. */ 1.738 + GC_SHRINK = 1 1.739 +} JSGCInvocationKind; 1.740 + 1.741 +extern void 1.742 +GC(JSRuntime *rt, JSGCInvocationKind gckind, JS::gcreason::Reason reason); 1.743 + 1.744 +extern void 1.745 +GCSlice(JSRuntime *rt, JSGCInvocationKind gckind, JS::gcreason::Reason reason, int64_t millis = 0); 1.746 + 1.747 +extern void 1.748 +GCFinalSlice(JSRuntime *rt, JSGCInvocationKind gckind, JS::gcreason::Reason reason); 1.749 + 1.750 +extern void 1.751 +GCDebugSlice(JSRuntime *rt, bool limit, int64_t objCount); 1.752 + 1.753 +extern void 1.754 +PrepareForDebugGC(JSRuntime *rt); 1.755 + 1.756 +extern void 1.757 +MinorGC(JSRuntime *rt, JS::gcreason::Reason reason); 1.758 + 1.759 +extern void 1.760 +MinorGC(JSContext *cx, JS::gcreason::Reason reason); 1.761 + 1.762 +#ifdef JS_GC_ZEAL 1.763 +extern void 1.764 +SetGCZeal(JSRuntime *rt, uint8_t zeal, uint32_t frequency); 1.765 +#endif 1.766 + 1.767 +/* Functions for managing cross compartment gray pointers. */ 1.768 + 1.769 +extern void 1.770 +DelayCrossCompartmentGrayMarking(JSObject *src); 1.771 + 1.772 +extern void 1.773 +NotifyGCNukeWrapper(JSObject *o); 1.774 + 1.775 +extern unsigned 1.776 +NotifyGCPreSwap(JSObject *a, JSObject *b); 1.777 + 1.778 +extern void 1.779 +NotifyGCPostSwap(JSObject *a, JSObject *b, unsigned preResult); 1.780 + 1.781 +/* 1.782 + * Helper that implements sweeping and allocation for kinds that can be swept 1.783 + * and allocated off the main thread. 1.784 + * 1.785 + * In non-threadsafe builds, all actual sweeping and allocation is performed 1.786 + * on the main thread, but GCHelperThread encapsulates this from clients as 1.787 + * much as possible. 1.788 + */ 1.789 +class GCHelperThread { 1.790 + enum State { 1.791 + IDLE, 1.792 + SWEEPING, 1.793 + ALLOCATING, 1.794 + CANCEL_ALLOCATION, 1.795 + SHUTDOWN 1.796 + }; 1.797 + 1.798 + /* 1.799 + * During the finalization we do not free immediately. Rather we add the 1.800 + * corresponding pointers to a buffer which we later release on a 1.801 + * separated thread. 1.802 + * 1.803 + * The buffer is implemented as a vector of 64K arrays of pointers, not as 1.804 + * a simple vector, to avoid realloc calls during the vector growth and to 1.805 + * not bloat the binary size of the inlined freeLater method. Any OOM 1.806 + * during buffer growth results in the pointer being freed immediately. 1.807 + */ 1.808 + static const size_t FREE_ARRAY_SIZE = size_t(1) << 16; 1.809 + static const size_t FREE_ARRAY_LENGTH = FREE_ARRAY_SIZE / sizeof(void *); 1.810 + 1.811 + JSRuntime *const rt; 1.812 + PRThread *thread; 1.813 + PRCondVar *wakeup; 1.814 + PRCondVar *done; 1.815 + volatile State state; 1.816 + 1.817 + void wait(PRCondVar *which); 1.818 + 1.819 + bool sweepFlag; 1.820 + bool shrinkFlag; 1.821 + 1.822 + Vector<void **, 16, js::SystemAllocPolicy> freeVector; 1.823 + void **freeCursor; 1.824 + void **freeCursorEnd; 1.825 + 1.826 + bool backgroundAllocation; 1.827 + 1.828 + friend class js::gc::ArenaLists; 1.829 + 1.830 + void 1.831 + replenishAndFreeLater(void *ptr); 1.832 + 1.833 + static void freeElementsAndArray(void **array, void **end) { 1.834 + JS_ASSERT(array <= end); 1.835 + for (void **p = array; p != end; ++p) 1.836 + js_free(*p); 1.837 + js_free(array); 1.838 + } 1.839 + 1.840 + static void threadMain(void* arg); 1.841 + void threadLoop(); 1.842 + 1.843 + /* Must be called with the GC lock taken. */ 1.844 + void doSweep(); 1.845 + 1.846 + public: 1.847 + GCHelperThread(JSRuntime *rt) 1.848 + : rt(rt), 1.849 + thread(nullptr), 1.850 + wakeup(nullptr), 1.851 + done(nullptr), 1.852 + state(IDLE), 1.853 + sweepFlag(false), 1.854 + shrinkFlag(false), 1.855 + freeCursor(nullptr), 1.856 + freeCursorEnd(nullptr), 1.857 + backgroundAllocation(true) 1.858 + { } 1.859 + 1.860 + bool init(); 1.861 + void finish(); 1.862 + 1.863 + /* Must be called with the GC lock taken. */ 1.864 + void startBackgroundSweep(bool shouldShrink); 1.865 + 1.866 + /* Must be called with the GC lock taken. */ 1.867 + void startBackgroundShrink(); 1.868 + 1.869 + /* Must be called without the GC lock taken. */ 1.870 + void waitBackgroundSweepEnd(); 1.871 + 1.872 + /* Must be called without the GC lock taken. */ 1.873 + void waitBackgroundSweepOrAllocEnd(); 1.874 + 1.875 + /* Must be called with the GC lock taken. */ 1.876 + inline void startBackgroundAllocationIfIdle(); 1.877 + 1.878 + bool canBackgroundAllocate() const { 1.879 + return backgroundAllocation; 1.880 + } 1.881 + 1.882 + void disableBackgroundAllocation() { 1.883 + backgroundAllocation = false; 1.884 + } 1.885 + 1.886 + PRThread *getThread() const { 1.887 + return thread; 1.888 + } 1.889 + 1.890 + bool onBackgroundThread(); 1.891 + 1.892 + /* 1.893 + * Outside the GC lock may give true answer when in fact the sweeping has 1.894 + * been done. 1.895 + */ 1.896 + bool sweeping() const { 1.897 + return state == SWEEPING; 1.898 + } 1.899 + 1.900 + bool shouldShrink() const { 1.901 + JS_ASSERT(sweeping()); 1.902 + return shrinkFlag; 1.903 + } 1.904 + 1.905 + void freeLater(void *ptr) { 1.906 + JS_ASSERT(!sweeping()); 1.907 + if (freeCursor != freeCursorEnd) 1.908 + *freeCursor++ = ptr; 1.909 + else 1.910 + replenishAndFreeLater(ptr); 1.911 + } 1.912 +}; 1.913 + 1.914 +struct GCChunkHasher { 1.915 + typedef gc::Chunk *Lookup; 1.916 + 1.917 + /* 1.918 + * Strip zeros for better distribution after multiplying by the golden 1.919 + * ratio. 1.920 + */ 1.921 + static HashNumber hash(gc::Chunk *chunk) { 1.922 + JS_ASSERT(!(uintptr_t(chunk) & gc::ChunkMask)); 1.923 + return HashNumber(uintptr_t(chunk) >> gc::ChunkShift); 1.924 + } 1.925 + 1.926 + static bool match(gc::Chunk *k, gc::Chunk *l) { 1.927 + JS_ASSERT(!(uintptr_t(k) & gc::ChunkMask)); 1.928 + JS_ASSERT(!(uintptr_t(l) & gc::ChunkMask)); 1.929 + return k == l; 1.930 + } 1.931 +}; 1.932 + 1.933 +typedef HashSet<js::gc::Chunk *, GCChunkHasher, SystemAllocPolicy> GCChunkSet; 1.934 + 1.935 +struct GrayRoot { 1.936 + void *thing; 1.937 + JSGCTraceKind kind; 1.938 +#ifdef DEBUG 1.939 + JSTraceNamePrinter debugPrinter; 1.940 + const void *debugPrintArg; 1.941 + size_t debugPrintIndex; 1.942 +#endif 1.943 + 1.944 + GrayRoot(void *thing, JSGCTraceKind kind) 1.945 + : thing(thing), kind(kind) {} 1.946 +}; 1.947 + 1.948 +void 1.949 +MarkStackRangeConservatively(JSTracer *trc, Value *begin, Value *end); 1.950 + 1.951 +typedef void (*IterateChunkCallback)(JSRuntime *rt, void *data, gc::Chunk *chunk); 1.952 +typedef void (*IterateZoneCallback)(JSRuntime *rt, void *data, JS::Zone *zone); 1.953 +typedef void (*IterateArenaCallback)(JSRuntime *rt, void *data, gc::Arena *arena, 1.954 + JSGCTraceKind traceKind, size_t thingSize); 1.955 +typedef void (*IterateCellCallback)(JSRuntime *rt, void *data, void *thing, 1.956 + JSGCTraceKind traceKind, size_t thingSize); 1.957 + 1.958 +/* 1.959 + * This function calls |zoneCallback| on every zone, |compartmentCallback| on 1.960 + * every compartment, |arenaCallback| on every in-use arena, and |cellCallback| 1.961 + * on every in-use cell in the GC heap. 1.962 + */ 1.963 +extern void 1.964 +IterateZonesCompartmentsArenasCells(JSRuntime *rt, void *data, 1.965 + IterateZoneCallback zoneCallback, 1.966 + JSIterateCompartmentCallback compartmentCallback, 1.967 + IterateArenaCallback arenaCallback, 1.968 + IterateCellCallback cellCallback); 1.969 + 1.970 +/* 1.971 + * This function is like IterateZonesCompartmentsArenasCells, but does it for a 1.972 + * single zone. 1.973 + */ 1.974 +extern void 1.975 +IterateZoneCompartmentsArenasCells(JSRuntime *rt, Zone *zone, void *data, 1.976 + IterateZoneCallback zoneCallback, 1.977 + JSIterateCompartmentCallback compartmentCallback, 1.978 + IterateArenaCallback arenaCallback, 1.979 + IterateCellCallback cellCallback); 1.980 + 1.981 +/* 1.982 + * Invoke chunkCallback on every in-use chunk. 1.983 + */ 1.984 +extern void 1.985 +IterateChunks(JSRuntime *rt, void *data, IterateChunkCallback chunkCallback); 1.986 + 1.987 +typedef void (*IterateScriptCallback)(JSRuntime *rt, void *data, JSScript *script); 1.988 + 1.989 +/* 1.990 + * Invoke scriptCallback on every in-use script for 1.991 + * the given compartment or for all compartments if it is null. 1.992 + */ 1.993 +extern void 1.994 +IterateScripts(JSRuntime *rt, JSCompartment *compartment, 1.995 + void *data, IterateScriptCallback scriptCallback); 1.996 + 1.997 +} /* namespace js */ 1.998 + 1.999 +extern void 1.1000 +js_FinalizeStringRT(JSRuntime *rt, JSString *str); 1.1001 + 1.1002 +namespace js { 1.1003 + 1.1004 +JSCompartment * 1.1005 +NewCompartment(JSContext *cx, JS::Zone *zone, JSPrincipals *principals, 1.1006 + const JS::CompartmentOptions &options); 1.1007 + 1.1008 +namespace gc { 1.1009 + 1.1010 +extern void 1.1011 +GCIfNeeded(JSContext *cx); 1.1012 + 1.1013 +/* Tries to run a GC no matter what (used for GC zeal). */ 1.1014 +void 1.1015 +RunDebugGC(JSContext *cx); 1.1016 + 1.1017 +void 1.1018 +SetDeterministicGC(JSContext *cx, bool enabled); 1.1019 + 1.1020 +void 1.1021 +SetValidateGC(JSContext *cx, bool enabled); 1.1022 + 1.1023 +void 1.1024 +SetFullCompartmentChecks(JSContext *cx, bool enabled); 1.1025 + 1.1026 +/* Wait for the background thread to finish sweeping if it is running. */ 1.1027 +void 1.1028 +FinishBackgroundFinalize(JSRuntime *rt); 1.1029 + 1.1030 +/* 1.1031 + * Merge all contents of source into target. This can only be used if source is 1.1032 + * the only compartment in its zone. 1.1033 + */ 1.1034 +void 1.1035 +MergeCompartments(JSCompartment *source, JSCompartment *target); 1.1036 + 1.1037 +const int ZealPokeValue = 1; 1.1038 +const int ZealAllocValue = 2; 1.1039 +const int ZealFrameGCValue = 3; 1.1040 +const int ZealVerifierPreValue = 4; 1.1041 +const int ZealFrameVerifierPreValue = 5; 1.1042 +const int ZealStackRootingValue = 6; 1.1043 +const int ZealGenerationalGCValue = 7; 1.1044 +const int ZealIncrementalRootsThenFinish = 8; 1.1045 +const int ZealIncrementalMarkAllThenFinish = 9; 1.1046 +const int ZealIncrementalMultipleSlices = 10; 1.1047 +const int ZealVerifierPostValue = 11; 1.1048 +const int ZealFrameVerifierPostValue = 12; 1.1049 +const int ZealCheckHashTablesOnMinorGC = 13; 1.1050 +const int ZealLimit = 13; 1.1051 + 1.1052 +enum VerifierType { 1.1053 + PreBarrierVerifier, 1.1054 + PostBarrierVerifier 1.1055 +}; 1.1056 + 1.1057 +#ifdef JS_GC_ZEAL 1.1058 + 1.1059 +/* Check that write barriers have been used correctly. See jsgc.cpp. */ 1.1060 +void 1.1061 +VerifyBarriers(JSRuntime *rt, VerifierType type); 1.1062 + 1.1063 +void 1.1064 +MaybeVerifyBarriers(JSContext *cx, bool always = false); 1.1065 + 1.1066 +#else 1.1067 + 1.1068 +static inline void 1.1069 +VerifyBarriers(JSRuntime *rt, VerifierType type) 1.1070 +{ 1.1071 +} 1.1072 + 1.1073 +static inline void 1.1074 +MaybeVerifyBarriers(JSContext *cx, bool always = false) 1.1075 +{ 1.1076 +} 1.1077 + 1.1078 +#endif 1.1079 + 1.1080 +/* 1.1081 + * Instances of this class set the |JSRuntime::suppressGC| flag for the duration 1.1082 + * that they are live. Use of this class is highly discouraged. Please carefully 1.1083 + * read the comment in jscntxt.h above |suppressGC| and take all appropriate 1.1084 + * precautions before instantiating this class. 1.1085 + */ 1.1086 +class AutoSuppressGC 1.1087 +{ 1.1088 + int32_t &suppressGC_; 1.1089 + 1.1090 + public: 1.1091 + AutoSuppressGC(ExclusiveContext *cx); 1.1092 + AutoSuppressGC(JSCompartment *comp); 1.1093 + AutoSuppressGC(JSRuntime *rt); 1.1094 + 1.1095 + ~AutoSuppressGC() 1.1096 + { 1.1097 + suppressGC_--; 1.1098 + } 1.1099 +}; 1.1100 + 1.1101 +#ifdef DEBUG 1.1102 +/* Disable OOM testing in sections which are not OOM safe. */ 1.1103 +class AutoEnterOOMUnsafeRegion 1.1104 +{ 1.1105 + uint32_t saved_; 1.1106 + 1.1107 + public: 1.1108 + AutoEnterOOMUnsafeRegion() : saved_(OOM_maxAllocations) { 1.1109 + OOM_maxAllocations = UINT32_MAX; 1.1110 + } 1.1111 + ~AutoEnterOOMUnsafeRegion() { 1.1112 + OOM_maxAllocations = saved_; 1.1113 + } 1.1114 +}; 1.1115 +#else 1.1116 +class AutoEnterOOMUnsafeRegion {}; 1.1117 +#endif /* DEBUG */ 1.1118 + 1.1119 +} /* namespace gc */ 1.1120 + 1.1121 +#ifdef DEBUG 1.1122 +/* Use this to avoid assertions when manipulating the wrapper map. */ 1.1123 +class AutoDisableProxyCheck 1.1124 +{ 1.1125 + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER; 1.1126 + uintptr_t &count; 1.1127 + 1.1128 + public: 1.1129 + AutoDisableProxyCheck(JSRuntime *rt 1.1130 + MOZ_GUARD_OBJECT_NOTIFIER_PARAM); 1.1131 + 1.1132 + ~AutoDisableProxyCheck() { 1.1133 + count--; 1.1134 + } 1.1135 +}; 1.1136 +#else 1.1137 +struct AutoDisableProxyCheck 1.1138 +{ 1.1139 + AutoDisableProxyCheck(JSRuntime *rt) {} 1.1140 +}; 1.1141 +#endif 1.1142 + 1.1143 +void 1.1144 +PurgeJITCaches(JS::Zone *zone); 1.1145 + 1.1146 +// This is the same as IsInsideNursery, but not inlined. 1.1147 +bool 1.1148 +UninlinedIsInsideNursery(JSRuntime *rt, const void *thing); 1.1149 + 1.1150 +} /* namespace js */ 1.1151 + 1.1152 +#endif /* jsgc_h */