📄 jsgc.c
字号:
JS_NewDHashTable(JS_DHashGetStubOps(), NULL, sizeof(JSGCLockHashEntry), GC_ROOTS_SIZE); if (!rt->gcLocksHash) { ok = JS_FALSE; goto done; } } else if (lock == 0) {#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) { ok = JS_FALSE; goto done; } if (!lhe->thing) { lhe->thing = thing; lhe->count = deep ? 1 : 2; } else { JS_ASSERT(lhe->count >= 1); lhe->count++; } } *flagp = (uint8)(flags | GCF_LOCK); METER(rt->gcStats.lock++); ok = JS_TRUE;done: JS_UNLOCK_GC(rt); return ok;}JSBooljs_UnlockGCThingRT(JSRuntime *rt, void *thing){ uint8 *flagp, flags; JSGCLockHashEntry *lhe; if (!thing) return JS_TRUE; flagp = js_GetGCThingFlags(thing); JS_LOCK_GC(rt); flags = *flagp; if (flags & GCF_LOCK) { if (!rt->gcLocksHash || (lhe = (JSGCLockHashEntry *) JS_DHashTableOperate(rt->gcLocksHash, thing, JS_DHASH_LOOKUP), JS_DHASH_ENTRY_IS_FREE(&lhe->hdr))) { /* Shallow GC-thing with an implicit lock count of 1. */ JS_ASSERT(!GC_THING_IS_DEEP(flags & GCF_TYPEMASK, thing)); } else { /* Basis or nested unlock of a deep thing, or nested of shallow. */ if (--lhe->count != 0) goto out; JS_DHashTableOperate(rt->gcLocksHash, thing, JS_DHASH_REMOVE); } *flagp = (uint8)(flags & ~GCF_LOCK); } rt->gcPoke = JS_TRUE;out: METER(rt->gcStats.unlock++); JS_UNLOCK_GC(rt); return JS_TRUE;}#ifdef GC_MARK_DEBUG#include <stdio.h>#include "jsprf.h"typedef struct GCMarkNode GCMarkNode;struct GCMarkNode { void *thing; const char *name; GCMarkNode *next; GCMarkNode *prev;};JS_FRIEND_DATA(FILE *) js_DumpGCHeap;JS_EXPORT_DATA(void *) js_LiveThingToFind;#ifdef HAVE_XPCONNECT#include "dump_xpc.h"#endifstatic voidGetObjSlotName(JSScope *scope, JSObject *obj, uint32 slot, char *buf, size_t bufsize){ jsval nval; JSScopeProperty *sprop; JSClass *clasp; uint32 key; const char *slotname; if (!scope) { JS_snprintf(buf, bufsize, "**UNKNOWN OBJECT MAP ENTRY**"); return; } sprop = SCOPE_LAST_PROP(scope); while (sprop && sprop->slot != slot) sprop = sprop->parent; if (!sprop) { switch (slot) { case JSSLOT_PROTO: JS_snprintf(buf, bufsize, "__proto__"); break; case JSSLOT_PARENT: JS_snprintf(buf, bufsize, "__parent__"); break; default: slotname = NULL; clasp = LOCKED_OBJ_GET_CLASS(obj); if (clasp->flags & JSCLASS_IS_GLOBAL) { key = slot - JSSLOT_START(clasp);#define JS_PROTO(name,code,init) \ if ((code) == key) { slotname = js_##name##_str; goto found; }#include "jsproto.tbl"#undef JS_PROTO } found: if (slotname) JS_snprintf(buf, bufsize, "CLASS_OBJECT(%s)", slotname); else JS_snprintf(buf, bufsize, "**UNKNOWN SLOT %ld**", (long)slot); break; } } else { nval = ID_TO_VALUE(sprop->id); if (JSVAL_IS_INT(nval)) { JS_snprintf(buf, bufsize, "%ld", (long)JSVAL_TO_INT(nval)); } else if (JSVAL_IS_STRING(nval)) { JS_snprintf(buf, bufsize, "%s", JS_GetStringBytes(JSVAL_TO_STRING(nval))); } else { JS_snprintf(buf, bufsize, "**FINALIZED ATOM KEY**"); } }}static 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 break; } case GCX_STRING: case GCX_MUTABLE_STRING: { JSString *str = (JSString *)thing; if (JSSTRING_IS_DEPENDENT(str)) { JS_snprintf(depbuf, sizeof depbuf, "start:%u, length:%u", JSSTRDEP_START(str), JSSTRDEP_LENGTH(str)); className = depbuf; } else { className = "string"; } break; } case GCX_DOUBLE: className = "double"; break; } return className;}static voidgc_dump_thing(JSContext *cx, JSGCThing *thing, FILE *fp){ GCMarkNode *prev = (GCMarkNode *)cx->gcCurrentMarkNode; GCMarkNode *next = NULL; char *path = NULL; while (prev) { next = prev; prev = prev->prev; } while (next) { uint8 nextFlags = *js_GetGCThingFlags(next->thing); if ((nextFlags & GCF_TYPEMASK) == GCX_OBJECT) { path = JS_sprintf_append(path, "%s(%s @ 0x%08p).", next->name, gc_object_class_name(next->thing), (JSObject*)next->thing); } else { path = JS_sprintf_append(path, "%s(%s).", next->name, gc_object_class_name(next->thing)); } next = next->next; } if (!path) return; fprintf(fp, "%08lx ", (long)thing); switch (*js_GetGCThingFlags(thing) & GCF_TYPEMASK) { case GCX_OBJECT: { JSObject *obj = (JSObject *)thing; jsval privateValue = obj->slots[JSSLOT_PRIVATE]; void *privateThing = JSVAL_IS_VOID(privateValue) ? NULL : JSVAL_TO_PRIVATE(privateValue); const char *className = gc_object_class_name(thing); fprintf(fp, "object %8p %s", privateThing, className); break; }#if JS_HAS_XML_SUPPORT case GCX_NAMESPACE: { JSXMLNamespace *ns = (JSXMLNamespace *)thing; fprintf(fp, "namespace %s:%s", JS_GetStringBytes(ns->prefix), JS_GetStringBytes(ns->uri)); break; } case GCX_QNAME: { JSXMLQName *qn = (JSXMLQName *)thing; fprintf(fp, "qname %s(%s):%s", JS_GetStringBytes(qn->prefix), JS_GetStringBytes(qn->uri), JS_GetStringBytes(qn->localName)); break; } case GCX_XML: { extern const char *js_xml_class_str[]; JSXML *xml = (JSXML *)thing; fprintf(fp, "xml %8p %s", xml, js_xml_class_str[xml->xml_class]); break; }#endif case GCX_DOUBLE: fprintf(fp, "double %g", *(jsdouble *)thing); break; case GCX_PRIVATE: fprintf(fp, "private %8p", (void *)thing); break; default: fprintf(fp, "string %s", JS_GetStringBytes((JSString *)thing)); break; } fprintf(fp, " via %s\n", path); free(path);}voidjs_MarkNamedGCThing(JSContext *cx, void *thing, const char *name){ GCMarkNode markNode; if (!thing) return; markNode.thing = thing; markNode.name = name; markNode.next = NULL; markNode.prev = (GCMarkNode *)cx->gcCurrentMarkNode; if (markNode.prev) markNode.prev->next = &markNode; cx->gcCurrentMarkNode = &markNode; if (thing == js_LiveThingToFind) { /* * Dump js_LiveThingToFind each time we reach it during the marking * phase of GC to print all live references to the thing. */ gc_dump_thing(cx, thing, stderr); } js_MarkGCThing(cx, thing); if (markNode.prev) markNode.prev->next = NULL; cx->gcCurrentMarkNode = markNode.prev;}#endif /* !GC_MARK_DEBUG */static voidgc_mark_atom_key_thing(void *thing, void *arg){ JSContext *cx = (JSContext *) arg; GC_MARK(cx, thing, "atom");}voidjs_MarkAtom(JSContext *cx, JSAtom *atom){ jsval key; if (atom->flags & ATOM_MARK) return; atom->flags |= ATOM_MARK; key = ATOM_KEY(atom); if (JSVAL_IS_GCTHING(key)) {#ifdef GC_MARK_DEBUG char name[32]; if (JSVAL_IS_STRING(key)) { JS_snprintf(name, sizeof name, "'%s'", JS_GetStringBytes(JSVAL_TO_STRING(key))); } else { JS_snprintf(name, sizeof name, "<%x>", key); }#endif GC_MARK(cx, JSVAL_TO_GCTHING(key), name); } if (atom->flags & ATOM_HIDDEN) js_MarkAtom(cx, atom->entry.value);}static voidAddThingToUnscannedBag(JSRuntime *rt, void *thing, uint8 *flagp);static voidMarkGCThingChildren(JSContext *cx, void *thing, uint8 *flagp, JSBool shouldCheckRecursion){ JSRuntime *rt; JSObject *obj; jsval v, *vp, *end; void *next_thing; uint8 *next_flagp; JSString *str;#ifdef JS_GCMETER uint32 tailCallNesting;#endif#ifdef GC_MARK_DEBUG JSScope *scope; char name[32];#endif /* * With JS_GC_ASSUME_LOW_C_STACK defined the mark phase of GC always * uses the non-recursive code that otherwise would be called only on * a low C stack condition. */#ifdef JS_GC_ASSUME_LOW_C_STACK# define RECURSION_TOO_DEEP() shouldCheckRecursion#else int stackDummy;# define RECURSION_TOO_DEEP() (shouldCheckRecursion && \ !JS_CHECK_STACK_SIZE(cx, stackDummy))#endif rt = cx->runtime; METER(tailCallNesting = 0); METER(if (++rt->gcStats.cdepth > rt->gcStats.maxcdepth) rt->gcStats.maxcdepth = rt->gcStats.cdepth);#ifndef GC_MARK_DEBUG start:#endif JS_ASSERT(flagp); JS_ASSERT(*flagp & GCF_MARK); /* the caller must already mark the thing */ METER(if (++rt->gcStats.depth > rt->gcStats.maxdepth) rt->gcStats.maxdepth = rt->gcStats.depth);#ifdef GC_MARK_DEBUG if (js_DumpGCHeap) gc_dump_thing(cx, thing, js_DumpGCHeap);#endif switch (*flagp & GCF_TYPEMASK) { case GCX_OBJECT: if (RECURSION_TOO_DEEP()) goto add_to_unscanned_bag; /* If obj->slots is null, obj must be a newborn. */ obj = (JSObject *) thing; vp = obj->slots; if (!vp) break; /* Mark slots if they are smal
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -