⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jsgc.c

📁 Swfdec still is development software, but has also followed a rigid no-crashes-allowed policy. I b
💻 C
📖 第 1 页 / 共 4 页
字号:
    /* Bump gcLevel and return rather than nest on this thread. */    currentThread = js_CurrentThreadId();    if (rt->gcThread == currentThread) {        JS_ASSERT(rt->gcLevel > 0);        rt->gcLevel++;        METER(if (rt->gcLevel > rt->gcStats.maxlevel)                  rt->gcStats.maxlevel = rt->gcLevel);        if (!(gcflags & GC_ALREADY_LOCKED))            JS_UNLOCK_GC(rt);        return;    }    /*     * If we're in one or more requests (possibly on more than one context)     * running on the current thread, indicate, temporarily, that all these     * requests are inactive.  NB: if cx->thread is 0, then cx is not using     * the request model, and does not contribute to rt->requestCount.     */    requestDebit = 0;    if (cx->thread) {        /*         * Check all contexts for any with the same thread-id.  XXX should we         * keep a sub-list of contexts having the same id?         */        iter = NULL;        while ((acx = js_ContextIterator(rt, JS_FALSE, &iter)) != NULL) {            if (acx->thread == cx->thread && acx->requestDepth)                requestDebit++;        }    } else {        /*         * We assert, but check anyway, in case someone is misusing the API.         * Avoiding the loop over all of rt's contexts is a win in the event         * that the GC runs only on request-less contexts with 0 thread-ids,         * in a special thread such as might be used by the UI/DOM/Layout         * "mozilla" or "main" thread in Mozilla-the-browser.         */        JS_ASSERT(cx->requestDepth == 0);        if (cx->requestDepth)            requestDebit = 1;    }    if (requestDebit) {        JS_ASSERT(requestDebit <= rt->requestCount);        rt->requestCount -= requestDebit;        if (rt->requestCount == 0)            JS_NOTIFY_REQUEST_DONE(rt);    }    /* If another thread is already in GC, don't attempt GC; wait instead. */    if (rt->gcLevel > 0) {        /* Bump gcLevel to restart the current GC, so it finds new garbage. */        rt->gcLevel++;        METER(if (rt->gcLevel > rt->gcStats.maxlevel)                  rt->gcStats.maxlevel = rt->gcLevel);        /* Wait for the other thread to finish, then resume our request. */        while (rt->gcLevel > 0)            JS_AWAIT_GC_DONE(rt);        if (requestDebit)            rt->requestCount += requestDebit;        if (!(gcflags & GC_ALREADY_LOCKED))            JS_UNLOCK_GC(rt);        return;    }    /* No other thread is in GC, so indicate that we're now in GC. */    rt->gcLevel = 1;    rt->gcThread = currentThread;    /* Wait for all other requests to finish. */    while (rt->requestCount > 0)        JS_AWAIT_REQUEST_DONE(rt);#else  /* !JS_THREADSAFE */    /* Bump gcLevel and return rather than nest; the outer gc will restart. */    rt->gcLevel++;    METER(if (rt->gcLevel > rt->gcStats.maxlevel)              rt->gcStats.maxlevel = rt->gcLevel);    if (rt->gcLevel > 1)        return;#endif /* !JS_THREADSAFE *///fprintf(stderr, "Doing the GC thing!\n"); /* FIXME */    /*     * Set rt->gcRunning here within the GC lock, and after waiting for any     * active requests to end, so that new requests that try to JS_AddRoot,     * JS_RemoveRoot, or JS_RemoveRootRT block in JS_BeginRequest waiting for     * rt->gcLevel to drop to zero, while request-less calls to the *Root*     * APIs block in js_AddRoot or js_RemoveRoot (see above in this file),     * waiting for GC to finish.     */    rt->gcRunning = JS_TRUE;    JS_UNLOCK_GC(rt);    /* If a suspended compile is running on another context, keep atoms. */    if (rt->gcKeepAtoms)        gcflags |= GC_KEEP_ATOMS;    /* Reset malloc counter. */    rt->gcMallocBytes = 0;    /* Drop atoms held by the property cache, and clear property weak links. */    js_DisablePropertyCache(cx);    js_FlushPropertyCache(cx);#ifdef DEBUG_brendan  { extern void js_DumpScopeMeters(JSRuntime *rt);    js_DumpScopeMeters(rt);  }#endifrestart:    rt->gcNumber++;    /*     * Mark phase.     */    JS_DHashTableEnumerate(&rt->gcRootsHash, gc_root_marker, cx);    if (rt->gcLocksHash)        JS_DHashTableEnumerate(rt->gcLocksHash, gc_lock_marker, cx);    js_MarkAtomState(&rt->atomState, gcflags, gc_mark_atom_key_thing, cx);    js_MarkWatchPoints(rt);    iter = NULL;    while ((acx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL) {        /*         * Iterate frame chain and dormant chains. Temporarily tack current         * frame onto the head of the dormant list to ease iteration.         *         * (NB: see comment on this whole "dormant" thing in js_Execute.)         */        chain = acx->fp;        if (chain) {            JS_ASSERT(!chain->dormantNext);            chain->dormantNext = acx->dormantFrameChain;        } else {            chain = acx->dormantFrameChain;        }        for (fp = chain; fp; fp = chain = chain->dormantNext) {            do {                if (fp->callobj)                    GC_MARK(cx, fp->callobj, "call object", NULL);                if (fp->argsobj)                    GC_MARK(cx, fp->argsobj, "arguments object", NULL);                if (fp->varobj)                    GC_MARK(cx, fp->varobj, "variables object", NULL);                if (fp->script)                    js_MarkScript(cx, fp->script, NULL);		if (fp->spbase) {		    /*		     * Don't mark what has not been pushed yet, or what		     * has been popped already.		     */		    if (fp->script) {		      depth = fp->script->depth;		      nslots = (JS_UPTRDIFF(fp->sp, fp->spbase)				< depth * sizeof(jsval))			       ? (uintN)(fp->sp - fp->spbase)			       : depth;		    } else {		      nslots = (uintN) (fp->sp - fp->spbase);		    }                    GC_MARK_JSVALS(cx, nslots, fp->spbase, "operand");                }                GC_MARK(cx, fp->thisp, "this", NULL);                if (fp->argv) {                    nslots = fp->argc;                    if (fp->fun && fp->fun->nargs > nslots)                        nslots = fp->fun->nargs;                    GC_MARK_JSVALS(cx, nslots, fp->argv, "arg");                }                if (JSVAL_IS_GCTHING(fp->rval))                    GC_MARK(cx, JSVAL_TO_GCTHING(fp->rval), "rval", NULL);                if (fp->vars)                    GC_MARK_JSVALS(cx, fp->nvars, fp->vars, "var");                GC_MARK(cx, fp->scopeChain, "scope chain", NULL);                if (fp->sharpArray)                    GC_MARK(cx, fp->sharpArray, "sharp array", NULL);                if (fp->objAtomMap) {                    JSAtom **vector, *atom;                    nslots = fp->objAtomMap->length;                    vector = fp->objAtomMap->vector;                    for (i = 0; i < nslots; i++) {                        atom = vector[i];                        if (atom)                            GC_MARK_ATOM(cx, atom, NULL);                    }                }            } while ((fp = fp->down) != NULL);        }        /* Cleanup temporary "dormant" linkage. */        if (acx->fp)            acx->fp->dormantNext = NULL;        /* Mark other roots-by-definition in acx. */        GC_MARK(cx, acx->globalObject, "global object", NULL);        GC_MARK(cx, acx->newborn[GCX_OBJECT], "newborn object", NULL);        GC_MARK(cx, acx->newborn[GCX_STRING], "newborn string", NULL);        GC_MARK(cx, acx->newborn[GCX_DOUBLE], "newborn double", NULL);        GC_MARK(cx, acx->newborn[GCX_MUTABLE_STRING], "newborn mutable string",                NULL);        for (i = GCX_EXTERNAL_STRING; i < GCX_NTYPES; i++)            GC_MARK(cx, acx->newborn[i], "newborn external string", NULL);        if (acx->lastAtom)            GC_MARK_ATOM(cx, acx->lastAtom, NULL);#if JS_HAS_EXCEPTIONS        if (acx->throwing && JSVAL_IS_GCTHING(acx->exception))            GC_MARK(cx, JSVAL_TO_GCTHING(acx->exception), "exception", NULL);#endif#if JS_HAS_LVALUE_RETURN        if (acx->rval2set && JSVAL_IS_GCTHING(acx->rval2))            GC_MARK(cx, JSVAL_TO_GCTHING(acx->rval2), "rval2", NULL);#endif        for (sh = acx->stackHeaders; sh; sh = sh->down) {            METER(rt->gcStats.stackseg++);            METER(rt->gcStats.segslots += sh->nslots);            GC_MARK_JSVALS(cx, sh->nslots, JS_STACK_SEGMENT(sh), "stack");        }    }    if (rt->gcCallback)        (void) rt->gcCallback(cx, JSGC_MARK_END);    /*     * Sweep phase.     * Finalize as we sweep, outside of rt->gcLock, but with rt->gcRunning set     * so that any attempt to allocate a GC-thing from a finalizer will fail,     * rather than nest badly and leave the unmarked newborn to be swept.     */    js_SweepAtomState(&rt->atomState);    js_SweepScopeProperties(rt);    js_SweepScriptFilenames(rt);    for (a = rt->gcArenaPool.first.next; a; a = a->next) {        flagp = (uint8 *) a->base;        split = (uint8 *) FIRST_THING_PAGE(a);        limit = (JSGCThing *) a->avail;        for (thing = (JSGCThing *) split; thing < limit; thing++) {            if (((jsuword)thing & GC_PAGE_MASK) == 0) {                flagp++;                thing++;            }            flags = *flagp;            if (flags & GCF_MARK) {                *flagp &= ~GCF_MARK;            } else if (!(flags & (GCF_LOCKMASK | GCF_FINAL))) {                /* Call the finalizer with GCF_FINAL ORed into flags. */                type = flags & GCF_TYPEMASK;                finalizer = gc_finalizers[type];                if (finalizer) {                    *flagp = (uint8)(flags | GCF_FINAL);                    if (type >= GCX_EXTERNAL_STRING)                        js_PurgeDeflatedStringCache((JSString *)thing);                    finalizer(cx, thing);                }                /* Set flags to GCF_FINAL, signifying that thing is free. */                *flagp = GCF_FINAL;                JS_ASSERT(rt->gcBytes >= sizeof(JSGCThing) + sizeof(uint8));                rt->gcBytes -= sizeof(JSGCThing) + sizeof(uint8);            }            if (++flagp == split)                flagp += GC_THINGS_SIZE;        }    }    /*     * Free phase.     * Free any unused arenas and rebuild the JSGCThing freelist.     */    ap = &rt->gcArenaPool.first.next;    a = *ap;    if (!a)        goto out;    all_clear = JS_TRUE;    flp = oflp = &rt->gcFreeList;    *flp = NULL;    METER(rt->gcStats.freelen = 0);    do {        flagp = (uint8 *) a->base;        split = (uint8 *) FIRST_THING_PAGE(a);        limit = (JSGCThing *) a->avail;        for (thing = (JSGCThing *) split; thing < limit; thing++) {            if (((jsuword)thing & GC_PAGE_MASK) == 0) {                flagp++;                thing++;            }            if (*flagp != GCF_FINAL) {                all_clear = JS_FALSE;            } else {                thing->flagp = flagp;                *flp = thing;                flp = &thing->next;                METER(rt->gcStats.freelen++);            }            if (++flagp == split)                flagp += GC_THINGS_SIZE;        }        if (all_clear) {            JS_ARENA_DESTROY(&rt->gcArenaPool, a, ap);            flp = oflp;            METER(rt->gcStats.afree++);        } else {            ap = &a->next;            all_clear = JS_TRUE;            oflp = flp;        }    } while ((a = *ap) != NULL);    /* Terminate the new freelist. */    *flp = NULL;    if (rt->gcCallback)        (void) rt->gcCallback(cx, JSGC_FINALIZE_END);#ifdef DEBUG_brendan  { extern void DumpSrcNoteSizeHist();    DumpSrcNoteSizeHist();  }#endifout:    JS_LOCK_GC(rt);    if (rt->gcLevel > 1) {        rt->gcLevel = 1;        JS_UNLOCK_GC(rt);        goto restart;    }    js_EnablePropertyCache(cx);    rt->gcLevel = 0;    rt->gcLastBytes = rt->gcBytes;    rt->gcPoke = rt->gcRunning = JS_FALSE;#ifdef JS_THREADSAFE    /* If we were invoked during a request, pay back the temporary debit. */    if (requestDebit)        rt->requestCount += requestDebit;    rt->gcThread = 0;    JS_NOTIFY_GC_DONE(rt);    if (!(gcflags & GC_ALREADY_LOCKED))        JS_UNLOCK_GC(rt);#endif    if (rt->gcCallback) {        if (gcflags & GC_ALREADY_LOCKED)            JS_UNLOCK_GC(rt);        (void) rt->gcCallback(cx, JSGC_END);        if (gcflags & GC_ALREADY_LOCKED)            JS_LOCK_GC(rt);    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -