JSRuntime *rt; uint8 *flagp, flags, lockbits; JSBool ok; JSGCLockHashEntry *lhe;  if (!thing) return JS_TRUE; flagp = js_GetGCThingFlags(thing); flags = *flagp;  ok = JS_TRUE; rt = cx->runtime; JS_LOCK_GC(rt); lockbits = (flags & GCF_LOCKMASK);  if (lockbits != GCF_LOCKMASK) { if ((flags & GCF_TYPEMASK) == GCX_OBJECT) {  if (lockbits == 0) { if (!rt->gcLocksHash) { rt->gcLocksHash = JS_NewDHashTable(JS_DHashGetStubOps(), NULL, sizeof(JSGCLockHashEntry), GC_ROOTS_SIZE); if (!rt->gcLocksHash) goto outofmem; } 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 outofmem; 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++); out: JS_UNLOCK_GC(rt);
JSBool ok = js_LockGCThingRT(cx->runtime, thing); if (!ok) JS_ReportOutOfMemory(cx);
js_LockGCThing(JSContext *cx, void *thing){    JSRuntime *rt;    uint8 *flagp, flags, lockbits;    JSBool ok;    JSGCLockHashEntry *lhe;    if (!thing)        return JS_TRUE;    flagp = js_GetGCThingFlags(thing);    flags = *flagp;    ok = JS_TRUE;    rt = cx->runtime;    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 outofmem;                } 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 outofmem;                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++);out:    JS_UNLOCK_GC(rt);    return ok;outofmem:    JS_ReportOutOfMemory(cx);    ok = JS_FALSE;    goto out;}