📄 jsgc.c
字号:
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(JSGCThing *thing, uint8 flags, GCMarkNode *prev, FILE *fp){ GCMarkNode *next = NULL; char *path = NULL; while (prev) { next = prev; prev = prev->prev; } while (next) { 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 (flags & 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; } case GCX_DOUBLE: fprintf(fp, "double %g", *(jsdouble *)thing); break; default: fprintf(fp, "string %s", JS_GetStringBytes((JSString *)thing)); break; } fprintf(fp, " via %s\n", path); free(path);}#endif /* !GC_MARK_DEBUG */static voidgc_mark_atom_key_thing(void *thing, void *arg){ JSContext *cx = (JSContext *) arg; GC_MARK(cx, thing, "atom", NULL);}voidjs_MarkAtom(JSContext *cx, JSAtom *atom, void *arg){ 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, arg); }}voidjs_MarkGCThing(JSContext *cx, void *thing, void *arg){ uint8 flags, *flagp; JSRuntime *rt; JSObject *obj; uint32 nslots; jsval v, *vp, *end; JSString *str;#ifdef GC_MARK_DEBUG JSScope *scope; JSScopeProperty *sprop;#endif if (!thing) return; flagp = js_GetGCThingFlags(thing); flags = *flagp; JS_ASSERT(flags != GCF_FINAL);#ifdef GC_MARK_DEBUG if (js_LiveThingToFind == thing) gc_dump_thing(thing, flags, arg, stderr);#endif if (flags & GCF_MARK) return; *flagp |= GCF_MARK; rt = cx->runtime; METER(if (++rt->gcStats.depth > rt->gcStats.maxdepth) rt->gcStats.maxdepth = rt->gcStats.depth);#ifdef GC_MARK_DEBUG if (!js_DumpGCHeap) js_DumpGCHeap = stderr; gc_dump_thing(thing, flags, arg, js_DumpGCHeap);#endif switch (flags & GCF_TYPEMASK) { case GCX_OBJECT: obj = (JSObject *) thing; vp = obj->slots; if (!vp) { /* If obj->slots is null, obj must be a newborn. */ JS_ASSERT(!obj->map); goto out; } nslots = (obj->map->ops->mark) ? obj->map->ops->mark(cx, obj, arg) : JS_MIN(obj->map->freeslot, obj->map->nslots);#ifdef GC_MARK_DEBUG scope = OBJ_IS_NATIVE(obj) ? OBJ_SCOPE(obj) : NULL;#endif for (end = vp + nslots; vp < end; vp++) { v = *vp; if (JSVAL_IS_GCTHING(v)) {#ifdef GC_MARK_DEBUG char name[32]; if (scope) { uint32 slot; jsval nval; slot = vp - obj->slots; for (sprop = SCOPE_LAST_PROP(scope); ; sprop = sprop->parent) { if (!sprop) { switch (slot) { case JSSLOT_PROTO: strcpy(name, "__proto__"); break; case JSSLOT_PARENT: strcpy(name, "__parent__"); break; case JSSLOT_PRIVATE: strcpy(name, "__private__"); break; default: JS_snprintf(name, sizeof name, "**UNKNOWN SLOT %ld**", (long)slot); break; } break; } if (sprop->slot == slot) { nval = ID_TO_VALUE(sprop->id); if (JSVAL_IS_INT(nval)) { JS_snprintf(name, sizeof name, "%ld", (long)JSVAL_TO_INT(nval)); } else if (JSVAL_IS_STRING(nval)) { JS_snprintf(name, sizeof name, "%s", JS_GetStringBytes(JSVAL_TO_STRING(nval))); } else { strcpy(name, "**FINALIZED ATOM KEY**"); } break; } } } else { strcpy(name, "**UNKNOWN OBJECT MAP ENTRY**"); }#endif GC_MARK(cx, JSVAL_TO_GCTHING(v), name, arg); } } break;#ifdef DEBUG case GCX_STRING: str = (JSString *)thing; JS_ASSERT(!JSSTRING_IS_DEPENDENT(str)); break;#endif case GCX_MUTABLE_STRING: str = (JSString *)thing; if (JSSTRING_IS_DEPENDENT(str)) GC_MARK(cx, JSSTRDEP_BASE(str), "base", arg); break; }out: METER(rt->gcStats.depth--);}JS_STATIC_DLL_CALLBACK(JSDHashOperator)gc_root_marker(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 num, void *arg){ JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr; jsval *rp = (jsval *)rhe->root; jsval v = *rp; /* Ignore null object and scalar values. */ if (!JSVAL_IS_NULL(v) && JSVAL_IS_GCTHING(v)) { JSContext *cx = (JSContext *)arg;#ifdef DEBUG JSArena *a; jsuword firstpage; JSBool root_points_to_gcArenaPool = JS_FALSE; void *thing = JSVAL_TO_GCTHING(v); for (a = cx->runtime->gcArenaPool.first.next; a; a = a->next) { firstpage = FIRST_THING_PAGE(a); if (JS_UPTRDIFF(thing, firstpage) < a->avail - firstpage) { root_points_to_gcArenaPool = JS_TRUE; break; } } if (!root_points_to_gcArenaPool && rhe->name) { fprintf(stderr,"JS API usage error: the address passed to JS_AddNamedRoot currently holds an\n""invalid jsval. This is usually caused by a missing call to JS_RemoveRoot.\n""The root's name is \"%s\".\n", rhe->name); } JS_ASSERT(root_points_to_gcArenaPool);#endif GC_MARK(cx, JSVAL_TO_GCTHING(v), rhe->name ? rhe->name : "root", NULL); } return JS_DHASH_NEXT;}JS_STATIC_DLL_CALLBACK(JSDHashOperator)gc_lock_marker(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 num, void *arg){ JSGCLockHashEntry *lhe = (JSGCLockHashEntry *)hdr; void *thing = (void *)lhe->thing; JSContext *cx = (JSContext *)arg; GC_MARK(cx, thing, "locked object", NULL); return JS_DHASH_NEXT;}voidjs_ForceGC(JSContext *cx, uintN gcflags){ uintN i; for (i = 0; i < GCX_NTYPES; i++) cx->newborn[i] = NULL; cx->lastAtom = NULL; cx->runtime->gcPoke = JS_TRUE; js_GC(cx, gcflags); JS_ArenaFinish();}#define GC_MARK_JSVALS(cx, len, vec, name) \ JS_BEGIN_MACRO \ jsval _v, *_vp, *_end; \ \ for (_vp = vec, _end = _vp + len; _vp < _end; _vp++) { \ _v = *_vp; \ if (JSVAL_IS_GCTHING(_v)) \ GC_MARK(cx, JSVAL_TO_GCTHING(_v), name, NULL); \ } \ JS_END_MACROvoidjs_GC(JSContext *cx, uintN gcflags){ JSRuntime *rt; JSContext *iter, *acx; JSStackFrame *fp, *chain; uintN i, depth, nslots, type; JSStackHeader *sh; JSArena *a, **ap; uint8 flags, *flagp, *split; JSGCThing *thing, *limit, **flp, **oflp; GCFinalizeOp finalizer; JSBool all_clear;#ifdef JS_THREADSAFE jsword currentThread; uint32 requestDebit;#endif rt = cx->runtime;#ifdef JS_THREADSAFE /* Avoid deadlock. */ JS_ASSERT(!JS_IS_RUNTIME_LOCKED(rt));#endif /* * Don't collect garbage if the runtime isn't up, and cx is not the last * context in the runtime. The last context must force a GC, and nothing * should suppress that final collection or there may be shutdown leaks, * or runtime bloat until the next context is created. */ if (rt->state != JSRTS_UP && !(gcflags & GC_LAST_CONTEXT)) return; /* * Let the API user decide to defer a GC if it wants to (unless this * is the last context). Invoke the callback regardless. */ if (rt->gcCallback) { if (!rt->gcCallback(cx, JSGC_BEGIN) && !(gcflags & GC_LAST_CONTEXT)) return; } /* Lock out other GC allocator and collector invocations. */ if (!(gcflags & GC_ALREADY_LOCKED)) JS_LOCK_GC(rt); /* Do nothing if no assignment has executed since the last GC. */ if (!rt->gcPoke) { METER(rt->gcStats.nopoke++); if (!(gcflags & GC_ALREADY_LOCKED)) JS_UNLOCK_GC(rt); return; } METER(rt->gcStats.poke++);#ifdef JS_THREADSAFE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -