mirror of
https://github.com/ccxvii/mujs.git
synced 2026-09-22 15:13:35 +08:00
Collect garbage.
This commit is contained in:
@@ -46,7 +46,7 @@ int js_loadfile(js_State *J, const char *filename);
|
||||
int js_dostring(js_State *J, const char *source);
|
||||
int js_dofile(js_State *J, const char *filename);
|
||||
|
||||
void js_gc(js_State *J);
|
||||
void js_gc(js_State *J, int report);
|
||||
|
||||
/* binding API: TODO: move from jsrun.h */
|
||||
|
||||
|
||||
@@ -15,6 +15,13 @@ static int jsB_print(js_State *J, int argc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jsB_collectGarbage(js_State *J, int argc)
|
||||
{
|
||||
int report = js_toboolean(J, 1);
|
||||
js_gc(J, report);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jsB_eval(js_State *J, int argc)
|
||||
{
|
||||
const char *s;
|
||||
@@ -167,5 +174,6 @@ void jsB_init(js_State *J)
|
||||
jsB_register(J, "isNaN", jsB_isNaN);
|
||||
jsB_register(J, "isFinite", jsB_isFinite);
|
||||
|
||||
jsB_register(J, "collectGarbage", jsB_collectGarbage);
|
||||
jsB_register(J, "print", jsB_print);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,13 @@
|
||||
#include "jsobject.h"
|
||||
#include "jsstate.h"
|
||||
|
||||
static void jsG_markobject(js_State *J, int mark, js_Object *obj);
|
||||
|
||||
static void jsG_freeenvironment(js_State *J, js_Environment *env)
|
||||
{
|
||||
free(env);
|
||||
}
|
||||
|
||||
static void jsG_freefunction(js_State *J, js_Function *fun)
|
||||
{
|
||||
free(fun->params);
|
||||
@@ -14,11 +21,6 @@ static void jsG_freefunction(js_State *J, js_Function *fun)
|
||||
free(fun);
|
||||
}
|
||||
|
||||
static void jsG_freeenvironment(js_State *J, js_Environment *env)
|
||||
{
|
||||
free(env);
|
||||
}
|
||||
|
||||
static void jsG_freeproperty(js_State *J, js_Property *node)
|
||||
{
|
||||
if (node->left->level) jsG_freeproperty(J, node->left);
|
||||
@@ -33,8 +35,114 @@ static void jsG_freeobject(js_State *J, js_Object *obj)
|
||||
free(obj);
|
||||
}
|
||||
|
||||
void js_gc(js_State *J)
|
||||
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.type == JS_TOBJECT && node->value.u.object->gcmark != mark)
|
||||
jsG_markobject(J, mark, node->value.u.object);
|
||||
}
|
||||
|
||||
static void jsG_markobject(js_State *J, int mark, js_Object *obj)
|
||||
{
|
||||
obj->gcmark = mark;
|
||||
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->scope && obj->scope->gcmark != mark)
|
||||
jsG_markenvironment(J, mark, obj->scope);
|
||||
if (obj->function && obj->function->gcmark != mark)
|
||||
jsG_markfunction(J, mark, obj->function);
|
||||
}
|
||||
|
||||
static void jsG_markstack(js_State *J, int mark)
|
||||
{
|
||||
js_Value *v = J->stack;
|
||||
int n = J->top;
|
||||
while (n--) {
|
||||
if (v->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_Environment *env, *nextenv, **prevnextenv;
|
||||
int nenv = 0, nfun = 0, nobj = 0;
|
||||
int genv = 0, gfun = 0, gobj = 0;
|
||||
int mark;
|
||||
|
||||
mark = J->gcmark = J->gcmark == 1 ? 2 : 1;
|
||||
|
||||
jsG_markstack(J, mark);
|
||||
if (J->E)
|
||||
jsG_markenvironment(J, mark, J->E);
|
||||
|
||||
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) {
|
||||
nextobj = obj->gcnext;
|
||||
if (obj->gcmark != mark) {
|
||||
*prevnextobj = nextobj;
|
||||
jsG_freeobject(J, obj);
|
||||
++gobj;
|
||||
} else {
|
||||
prevnextobj = &obj->gcnext;
|
||||
}
|
||||
++nobj;
|
||||
}
|
||||
|
||||
if (report)
|
||||
printf("garbage collected: %d/%d envs, %d/%d funs, %d/%d objs\n",
|
||||
genv, nenv, gfun, nfun, gobj, nobj);
|
||||
}
|
||||
|
||||
void js_close(js_State *J)
|
||||
|
||||
@@ -79,6 +79,8 @@ js_State *js_newstate(void)
|
||||
js_State *J = malloc(sizeof *J);
|
||||
memset(J, 0, sizeof(*J));
|
||||
|
||||
J->gcmark = 1;
|
||||
|
||||
J->G = jsR_newobject(J, JS_COBJECT, NULL);
|
||||
J->E = jsR_newenvironment(J, J->G, NULL);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user