js/src/jsgc.h

changeset 0
6474c204b198
     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 */

mercurial