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

📄 jsgc.c

📁 Swfdec still is development software, but has also followed a rigid no-crashes-allowed policy. I b
💻 C
📖 第 1 页 / 共 4 页
字号:
                fprintf(stderr,"JS engine warning: 1 GC root remains after destroying the JSRuntime.\n""                   This root may point to freed memory. Objects reachable\n""                   through it have not been finalized.\n");            } else {                fprintf(stderr,"JS engine warning: %lu GC roots remain after destroying the JSRuntime.\n""                   These roots may point to freed memory. Objects reachable\n""                   through them have not been finalized.\n",                        (unsigned long) leakedroots);            }        }#endif        JS_DHashTableFinish(&rt->gcRootsHash);        rt->gcRootsHash.ops = NULL;    }    if (rt->gcLocksHash) {        JS_DHashTableDestroy(rt->gcLocksHash);        rt->gcLocksHash = NULL;    }    rt->gcFreeList = NULL;}JSBooljs_AddRoot(JSContext *cx, void *rp, const char *name){    JSBool ok = js_AddRootRT(cx->runtime, rp, name);    if (!ok)        JS_ReportOutOfMemory(cx);    return ok;}JSBooljs_AddRootRT(JSRuntime *rt, void *rp, const char *name){    JSBool ok;    JSGCRootHashEntry *rhe;    /*     * Due to the long-standing, but now removed, use of rt->gcLock across the     * bulk of js_GC, API users have come to depend on JS_AddRoot etc. locking     * properly with a racing GC, without calling JS_AddRoot from a request.     * We have to preserve API compatibility here, now that we avoid holding     * rt->gcLock across the mark phase (including the root hashtable mark).     *     * If the GC is running and we're called on another thread, wait for this     * GC activation to finish.  We can safely wait here (in the case where we     * are called within a request on another thread's context) without fear     * of deadlock because the GC doesn't set rt->gcRunning until after it has     * waited for all active requests to end.     */    JS_LOCK_GC(rt);#ifdef JS_THREADSAFE    JS_ASSERT(!rt->gcRunning || rt->gcLevel > 0);    if (rt->gcRunning && rt->gcThread != js_CurrentThreadId()) {        do {            JS_AWAIT_GC_DONE(rt);        } while (rt->gcLevel > 0);    }#endif    rhe = (JSGCRootHashEntry *) JS_DHashTableOperate(&rt->gcRootsHash, rp,                                                     JS_DHASH_ADD);    if (rhe) {        rhe->root = rp;        rhe->name = name;        ok = JS_TRUE;    } else {        ok = JS_FALSE;    }    JS_UNLOCK_GC(rt);    return ok;}JSBooljs_RemoveRoot(JSRuntime *rt, void *rp){    /*     * Due to the JS_RemoveRootRT API, we may be called outside of a request.     * Same synchronization drill as above in js_AddRoot.     */    JS_LOCK_GC(rt);#ifdef JS_THREADSAFE    JS_ASSERT(!rt->gcRunning || rt->gcLevel > 0);    if (rt->gcRunning && rt->gcThread != js_CurrentThreadId()) {        do {            JS_AWAIT_GC_DONE(rt);        } while (rt->gcLevel > 0);    }#endif    (void) JS_DHashTableOperate(&rt->gcRootsHash, rp, JS_DHASH_REMOVE);    rt->gcPoke = JS_TRUE;    JS_UNLOCK_GC(rt);    return JS_TRUE;}void *js_AllocGCThing(JSContext *cx, uintN flags){    JSBool tried_gc;    JSRuntime *rt;    JSGCThing *thing;    uint8 *flagp;#ifdef TOO_MUCH_GC    js_GC(cx, GC_KEEP_ATOMS);    tried_gc = JS_TRUE;#else    tried_gc = JS_FALSE;#endif    rt = cx->runtime;    JS_LOCK_GC(rt);    JS_ASSERT(!rt->gcRunning);    if (rt->gcRunning) {        METER(rt->gcStats.finalfail++);        JS_UNLOCK_GC(rt);        return NULL;    }    METER(rt->gcStats.alloc++);retry:    thing = rt->gcFreeList;    if (thing) {        rt->gcFreeList = thing->next;        flagp = thing->flagp;        METER(rt->gcStats.freelen--);        METER(rt->gcStats.recycle++);    } else {        if (rt->gcBytes < rt->gcMaxBytes &&            (tried_gc || rt->gcMallocBytes < rt->gcMaxBytes))        {            /*             * Inline form of JS_ARENA_ALLOCATE adapted to truncate the current             * arena's limit to a GC_PAGE_SIZE boundary, and to skip over every             * GC_PAGE_SIZE-byte-aligned thing (which is actually not a thing,             * it's a JSGCPageInfo record).             */            JSArenaPool *pool = &rt->gcArenaPool;            JSArena *a = pool->current;            size_t nb = sizeof(JSGCThing);            jsuword p = a->avail;            jsuword q = p + nb;            if (q > (a->limit & ~GC_PAGE_MASK)) {                thing = gc_new_arena(pool);            } else {                if ((p & GC_PAGE_MASK) == 0) {                    /* Beware, p points to a JSGCPageInfo record! */                    p = q;                    q += nb;                    JS_ArenaCountAllocation(pool, nb);                }                a->avail = q;                thing = (JSGCThing *)p;            }            JS_ArenaCountAllocation(pool, nb);        }        /*         * Consider doing a "last ditch" GC if thing couldn't be allocated.         *         * Keep rt->gcLock across the call into js_GC so we don't starve and         * lose to racing threads who deplete the heap just after js_GC has         * replenished it (or has synchronized with a racing GC that collected         * a bunch of garbage).  This unfair scheduling can happen on certain         * operating systems.  For the gory details, see Mozilla bug 162779         * (http://bugzilla.mozilla.org/show_bug.cgi?id=162779).         */        if (!thing) {            if (!tried_gc) {                rt->gcPoke = JS_TRUE;                js_GC(cx, GC_KEEP_ATOMS | GC_ALREADY_LOCKED);                tried_gc = JS_TRUE;                METER(rt->gcStats.retry++);                goto retry;            }            METER(rt->gcStats.fail++);            JS_UNLOCK_GC(rt);            JS_ReportOutOfMemory(cx);            return NULL;        }        /* Find the flags pointer given thing's address. */        flagp = js_GetGCThingFlags(thing);    }    *flagp = (uint8)flags;    rt->gcBytes += sizeof(JSGCThing) + sizeof(uint8);    cx->newborn[flags & GCF_TYPEMASK] = thing;    /*     * Clear thing before unlocking in case a GC run is about to scan it,     * finding it via cx->newborn[].     */    thing->next = NULL;    thing->flagp = NULL;    JS_UNLOCK_GC(rt);    return thing;}JSBooljs_LockGCThing(JSContext *cx, void *thing){    JSBool ok = js_LockGCThingRT(cx->runtime, thing);    if (!ok)        JS_ReportOutOfMemory(cx);    return ok;}JSBooljs_LockGCThingRT(JSRuntime *rt, void *thing){    uint8 *flagp, flags, lockbits;    JSBool ok;    JSGCLockHashEntry *lhe;    if (!thing)        return JS_TRUE;    flagp = js_GetGCThingFlags(thing);    flags = *flagp;    ok = JS_FALSE;    JS_LOCK_GC(rt);    lockbits = (flags & GCF_LOCKMASK);    if (lockbits != GCF_LOCKMASK) {        if ((flags & GCF_TYPEMASK) == GCX_OBJECT) {            /* Objects may require "deep locking", i.e., rooting by value. */            if (lockbits == 0) {                if (!rt->gcLocksHash) {                    rt->gcLocksHash =                         JS_NewDHashTable(JS_DHashGetStubOps(), NULL,                                         sizeof(JSGCLockHashEntry),                                         GC_ROOTS_SIZE);                    if (!rt->gcLocksHash)                        goto error;                } else {#ifdef DEBUG                    JSDHashEntryHdr *hdr =                         JS_DHashTableOperate(rt->gcLocksHash, thing,                                             JS_DHASH_LOOKUP);                    JS_ASSERT(JS_DHASH_ENTRY_IS_FREE(hdr));#endif                }                lhe = (JSGCLockHashEntry *)                    JS_DHashTableOperate(rt->gcLocksHash, thing, JS_DHASH_ADD);                if (!lhe)                    goto error;                lhe->thing = thing;                lhe->count = 1;                *flagp = (uint8)(flags + GCF_LOCK);            } else {                JS_ASSERT(lockbits == GCF_LOCK);                lhe = (JSGCLockHashEntry *)                    JS_DHashTableOperate(rt->gcLocksHash, thing,                                         JS_DHASH_LOOKUP);                JS_ASSERT(JS_DHASH_ENTRY_IS_BUSY(&lhe->hdr));                if (JS_DHASH_ENTRY_IS_BUSY(&lhe->hdr)) {                    JS_ASSERT(lhe->count >= 1);                    lhe->count++;                }            }        } else {            *flagp = (uint8)(flags + GCF_LOCK);        }    } else {        METER(rt->gcStats.stuck++);    }    METER(rt->gcStats.lock++);    ok = JS_TRUE;error:    JS_UNLOCK_GC(rt);    return ok;}JSBooljs_UnlockGCThingRT(JSRuntime *rt, void *thing){    uint8 *flagp, flags, lockbits;    JSGCLockHashEntry *lhe;    if (!thing)        return JS_TRUE;    flagp = js_GetGCThingFlags(thing);    flags = *flagp;    JS_LOCK_GC(rt);    lockbits = (flags & GCF_LOCKMASK);    if (lockbits != GCF_LOCKMASK) {        if ((flags & GCF_TYPEMASK) == GCX_OBJECT) {            /* Defend against a call on an unlocked object. */            if (lockbits != 0) {                JS_ASSERT(lockbits == GCF_LOCK);                lhe = (JSGCLockHashEntry *)                    JS_DHashTableOperate(rt->gcLocksHash, thing,                                         JS_DHASH_LOOKUP);                JS_ASSERT(JS_DHASH_ENTRY_IS_BUSY(&lhe->hdr));                if (JS_DHASH_ENTRY_IS_BUSY(&lhe->hdr) &&                    --lhe->count == 0) {                    (void) JS_DHashTableOperate(rt->gcLocksHash, thing,                                                JS_DHASH_REMOVE);                    *flagp = (uint8)(flags & ~GCF_LOCKMASK);                }            }        } else {            *flagp = (uint8)(flags - GCF_LOCK);        }    } else {        METER(rt->gcStats.unstuck++);    }    rt->gcPoke = JS_TRUE;    METER(rt->gcStats.unlock++);    JS_UNLOCK_GC(rt);    return JS_TRUE;}#ifdef GC_MARK_DEBUG#include <stdio.h>#include <stdlib.h>#include "jsprf.h"JS_FRIEND_DATA(FILE *) js_DumpGCHeap;JS_EXPORT_DATA(void *) js_LiveThingToFind;#ifdef HAVE_XPCONNECT#include "dump_xpc.h"#endifstatic const char *gc_object_class_name(void* thing){    uint8 *flagp = js_GetGCThingFlags(thing);    const char *className = "";    static char depbuf[32];    switch (*flagp & GCF_TYPEMASK) {      case GCX_OBJECT: {        JSObject  *obj = (JSObject *)thing;        JSClass   *clasp = JSVAL_TO_PRIVATE(obj->slots[JSSLOT_CLASS]);        className = clasp->name;#ifdef HAVE_XPCONNECT        if (clasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) {            jsval privateValue = obj->slots[JSSLOT_PRIVATE];            JS_ASSERT(clasp->flags & JSCLASS_HAS_PRIVATE);            if (!JSVAL_IS_VOID(privateValue)) {                void  *privateThing = JSVAL_TO_PRIVATE(privateValue);                const char *xpcClassName = GetXPCObjectClassName(privateThing);                if (xpcClassName)                    className = xpcClassName;            }        }#endif

⌨️ 快捷键说明

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