| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 |
- #include "jsi.h"
- #include "regexp.h"
- static void jsG_freeenvironment(js_State *J, js_Environment *env)
- {
- js_free(J, env);
- }
- static void jsG_freefunction(js_State *J, js_Function *fun)
- {
- js_free(J, fun->funtab);
- js_free(J, fun->vartab);
- js_free(J, fun->code);
- js_free(J, fun);
- }
- static void jsG_freeproperty(js_State *J, js_Property *node)
- {
- if (node->left->level) jsG_freeproperty(J, node->left);
- if (node->right->level) jsG_freeproperty(J, node->right);
- js_free(J, node);
- }
- static void jsG_freeiterator(js_State *J, js_Iterator *node)
- {
- while (node) {
- js_Iterator *next = node->next;
- js_free(J, node);
- node = next;
- }
- }
- static void jsG_freeobject(js_State *J, js_Object *obj)
- {
- if (obj->properties->level)
- jsG_freeproperty(J, obj->properties);
- if (obj->type == JS_CREGEXP) {
- js_free(J, obj->u.r.source);
- js_regfreex(J->alloc, J->actx, obj->u.r.prog);
- }
- if (obj->type == JS_CSTRING) {
- if (obj->u.s.string != obj->u.s.shrstr)
- js_free(J, obj->u.s.string);
- }
- if (obj->type == JS_CARRAY && obj->u.a.simple)
- js_free(J, obj->u.a.array);
- if (obj->type == JS_CITERATOR)
- jsG_freeiterator(J, obj->u.iter.head);
- if (obj->type == JS_CUSERDATA && obj->u.user.finalize)
- obj->u.user.finalize(J, obj->u.user.data);
- if (obj->type == JS_CCFUNCTION && obj->u.c.finalize)
- obj->u.c.finalize(J, obj->u.c.data);
- js_free(J, obj);
- }
- /* Mark and add object to scan queue */
- static void jsG_markobject(js_State *J, int mark, js_Object *obj)
- {
- obj->gcmark = mark;
- obj->gcroot = J->gcroot;
- J->gcroot = obj;
- }
- static void jsG_markfunction(js_State *J, int mark, js_Function *fun)
- {
- int i;
- fun->gcmark = mark;
- for (i = 0; i < fun->funlen; ++i)
- if (fun->funtab[i]->gcmark != mark)
- jsG_markfunction(J, mark, fun->funtab[i]);
- }
- static void jsG_markenvironment(js_State *J, int mark, js_Environment *env)
- {
- do {
- env->gcmark = mark;
- if (env->variables->gcmark != mark)
- jsG_markobject(J, mark, env->variables);
- env = env->outer;
- } while (env && env->gcmark != mark);
- }
- static void jsG_markproperty(js_State *J, int mark, js_Property *node)
- {
- if (node->left->level) jsG_markproperty(J, mark, node->left);
- if (node->right->level) jsG_markproperty(J, mark, node->right);
- if (node->value.t.type == JS_TMEMSTR && node->value.u.memstr->gcmark != mark)
- node->value.u.memstr->gcmark = mark;
- if (node->value.t.type == JS_TOBJECT && node->value.u.object->gcmark != mark)
- jsG_markobject(J, mark, node->value.u.object);
- if (node->getter && node->getter->gcmark != mark)
- jsG_markobject(J, mark, node->getter);
- if (node->setter && node->setter->gcmark != mark)
- jsG_markobject(J, mark, node->setter);
- }
- /* Mark everything the object can reach. */
- static void jsG_scanobject(js_State *J, int mark, js_Object *obj)
- {
- if (obj->properties->level)
- jsG_markproperty(J, mark, obj->properties);
- if (obj->prototype && obj->prototype->gcmark != mark)
- jsG_markobject(J, mark, obj->prototype);
- if (obj->type == JS_CARRAY && obj->u.a.simple) {
- int i;
- for (i = 0; i < obj->u.a.flat_length; ++i) {
- js_Value *v = &obj->u.a.array[i];
- if (v->t.type == JS_TMEMSTR && v->u.memstr->gcmark != mark)
- v->u.memstr->gcmark = mark;
- if (v->t.type == JS_TOBJECT && v->u.object->gcmark != mark)
- jsG_markobject(J, mark, v->u.object);
- }
- }
- if (obj->type == JS_CITERATOR && obj->u.iter.target->gcmark != mark) {
- jsG_markobject(J, mark, obj->u.iter.target);
- }
- if (obj->type == JS_CFUNCTION || obj->type == JS_CSCRIPT) {
- if (obj->u.f.scope && obj->u.f.scope->gcmark != mark)
- jsG_markenvironment(J, mark, obj->u.f.scope);
- if (obj->u.f.function && obj->u.f.function->gcmark != mark)
- jsG_markfunction(J, mark, obj->u.f.function);
- }
- }
- static void jsG_markstack(js_State *J, int mark)
- {
- js_Value *v = J->stack;
- int n = J->top;
- while (n--) {
- if (v->t.type == JS_TMEMSTR && v->u.memstr->gcmark != mark)
- v->u.memstr->gcmark = mark;
- if (v->t.type == JS_TOBJECT && v->u.object->gcmark != mark)
- jsG_markobject(J, mark, v->u.object);
- ++v;
- }
- }
- void js_gc(js_State *J, int report)
- {
- js_Function *fun, *nextfun, **prevnextfun;
- js_Object *obj, *nextobj, **prevnextobj;
- js_String *str, *nextstr, **prevnextstr;
- js_Environment *env, *nextenv, **prevnextenv;
- unsigned int nenv = 0, nfun = 0, nobj = 0, nstr = 0, nprop = 0;
- unsigned int genv = 0, gfun = 0, gobj = 0, gstr = 0, gprop = 0;
- int mark;
- int i;
- if (J->gcpause) {
- if (report)
- js_report(J, "garbage collector is paused");
- return;
- }
- mark = J->gcmark = J->gcmark == 1 ? 2 : 1;
- /* Add initial roots. */
- jsG_markobject(J, mark, J->Object_prototype);
- jsG_markobject(J, mark, J->Array_prototype);
- jsG_markobject(J, mark, J->Function_prototype);
- jsG_markobject(J, mark, J->Boolean_prototype);
- jsG_markobject(J, mark, J->Number_prototype);
- jsG_markobject(J, mark, J->String_prototype);
- jsG_markobject(J, mark, J->RegExp_prototype);
- jsG_markobject(J, mark, J->Date_prototype);
- jsG_markobject(J, mark, J->Error_prototype);
- jsG_markobject(J, mark, J->EvalError_prototype);
- jsG_markobject(J, mark, J->RangeError_prototype);
- jsG_markobject(J, mark, J->ReferenceError_prototype);
- jsG_markobject(J, mark, J->SyntaxError_prototype);
- jsG_markobject(J, mark, J->TypeError_prototype);
- jsG_markobject(J, mark, J->URIError_prototype);
- jsG_markobject(J, mark, J->R);
- jsG_markobject(J, mark, J->G);
- jsG_markstack(J, mark);
- jsG_markenvironment(J, mark, J->E);
- jsG_markenvironment(J, mark, J->GE);
- for (i = 0; i < J->envtop; ++i)
- jsG_markenvironment(J, mark, J->envstack[i]);
- /* Scan objects until none remain. */
- while ((obj = J->gcroot) != NULL) {
- J->gcroot = obj->gcroot;
- obj->gcroot = NULL;
- jsG_scanobject(J, mark, obj);
- }
- /* Free everything not marked. */
- prevnextenv = &J->gcenv;
- for (env = J->gcenv; env; env = nextenv) {
- nextenv = env->gcnext;
- if (env->gcmark != mark) {
- *prevnextenv = nextenv;
- jsG_freeenvironment(J, env);
- ++genv;
- } else {
- prevnextenv = &env->gcnext;
- }
- ++nenv;
- }
- prevnextfun = &J->gcfun;
- for (fun = J->gcfun; fun; fun = nextfun) {
- nextfun = fun->gcnext;
- if (fun->gcmark != mark) {
- *prevnextfun = nextfun;
- jsG_freefunction(J, fun);
- ++gfun;
- } else {
- prevnextfun = &fun->gcnext;
- }
- ++nfun;
- }
- prevnextobj = &J->gcobj;
- for (obj = J->gcobj; obj; obj = nextobj) {
- nprop += obj->count;
- nextobj = obj->gcnext;
- if (obj->gcmark != mark) {
- gprop += obj->count;
- *prevnextobj = nextobj;
- jsG_freeobject(J, obj);
- ++gobj;
- } else {
- prevnextobj = &obj->gcnext;
- }
- ++nobj;
- }
- prevnextstr = &J->gcstr;
- for (str = J->gcstr; str; str = nextstr) {
- nextstr = str->gcnext;
- if (str->gcmark != mark) {
- *prevnextstr = nextstr;
- js_free(J, str);
- ++gstr;
- } else {
- prevnextstr = &str->gcnext;
- }
- ++nstr;
- }
- unsigned int ntot = nenv + nfun + nobj + nstr + nprop;
- unsigned int gtot = genv + gfun + gobj + gstr + gprop;
- unsigned int remaining = ntot - gtot;
- J->gccounter = remaining;
- J->gcthresh = remaining * JS_GCFACTOR;
- if (report) {
- char buf[256];
- snprintf(buf, sizeof buf, "garbage collected (%d%%): %d/%d envs, %d/%d funs, %d/%d objs, %d/%d props, %d/%d strs",
- 100*gtot/ntot, genv, nenv, gfun, nfun, gobj, nobj, gprop, nprop, gstr, nstr);
- js_report(J, buf);
- }
- }
- void js_freestate(js_State *J)
- {
- js_Function *fun, *nextfun;
- js_Object *obj, *nextobj;
- js_Environment *env, *nextenv;
- js_String *str, *nextstr;
- if (!J)
- return;
- for (env = J->gcenv; env; env = nextenv)
- nextenv = env->gcnext, jsG_freeenvironment(J, env);
- for (fun = J->gcfun; fun; fun = nextfun)
- nextfun = fun->gcnext, jsG_freefunction(J, fun);
- for (obj = J->gcobj; obj; obj = nextobj)
- nextobj = obj->gcnext, jsG_freeobject(J, obj);
- for (str = J->gcstr; str; str = nextstr)
- nextstr = str->gcnext, js_free(J, str);
- jsS_freestrings(J);
- js_free(J, J->lexbuf.text);
- J->alloc(J->actx, J->stack, 0);
- J->alloc(J->actx, J, 0);
- }
|