ref: 96ca91ec7c4ff8fc1705e48d5b67e9e0570f5fde
parent: 299dbda156c8a8cb05775d9260e78c056a507ccf
author: Tor Andersson <[email protected]>
date: Fri Jan 17 17:57:12 EST 2014
Garbage collector lists.
--- a/js.h
+++ b/js.h
@@ -46,6 +46,8 @@
int js_dostring(js_State *J, const char *source);
int js_dofile(js_State *J, const char *filename);
+void js_gc(js_State *J);
+
/* binding API: TODO: move from jsrun.h */
typedef int (*js_CFunction)(js_State *J, int argc);
@@ -59,6 +61,7 @@
typedef struct js_StringNode js_StringNode;
const char *js_intern(js_State *J, const char *s);
-void js_printstringtree(js_State *J);
+void js_printstrings(js_State *J);
+void js_freestrings(js_State *J);
#endif
--- a/jscompile.c
+++ b/jscompile.c
@@ -17,27 +17,18 @@
{
js_Function *F = malloc(sizeof *F);
memset(F, 0, sizeof *F);
+ F->gcmark = 0;
+ F->gcnext = J->gcfun;
+ J->gcfun = F;
F->filename = js_intern(J, J->filename);
F->line = name ? name->line : params ? params->line : body->line;
- F->next = J->fun;
- J->fun = F;
-
cfunbody(J, F, name, params, body);
return F;
}
-static void freefun(js_State *J, js_Function *F)
-{
- free(F->funtab);
- free(F->numtab);
- free(F->strtab);
- free(F->code);
- free(F);
-}
-
/* Emit opcodes, constants and jumps */
static void emit(JF, int value)
@@ -760,25 +751,12 @@
longjmp(J->jb, 1);
}
-static void jsC_freecompile(js_State *J)
-{
- js_Function *F = J->fun;
- while (F) {
- js_Function *next = F->next;
- freefun(J, F);
- F = next;
- }
- J->fun = NULL;
-}
-
js_Function *jsC_compile(js_State *J, js_Ast *prog)
{
js_Function *F;
- if (setjmp(J->jb)) {
- jsC_freecompile(J);
+ if (setjmp(J->jb))
return NULL;
- }
F = newfun(J, NULL, NULL, prog);
--- a/jscompile.h
+++ b/jscompile.h
@@ -109,7 +109,8 @@
const char *filename;
int line;
- js_Function *next; /* alloc list */
+ js_Function *gcnext;
+ int gcmark;
};
js_Function *jsC_compile(js_State *J, js_Ast *prog);
--- /dev/null
+++ b/jsgc.c
@@ -1,0 +1,57 @@
+#include "js.h"
+#include "jscompile.h"
+#include "jsrun.h"
+#include "jsobject.h"
+#include "jsstate.h"
+
+static void jsG_freefunction(js_State *J, js_Function *fun)
+{
+ free(fun->params);
+ free(fun->funtab);
+ free(fun->numtab);
+ free(fun->strtab);
+ free(fun->code);
+ 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);
+ if (node->right->level) jsG_freeproperty(J, node->right);
+ free(node);
+}
+
+static void jsG_freeobject(js_State *J, js_Object *obj)
+{
+ if (obj->properties->level)
+ jsG_freeproperty(J, obj->properties);
+ free(obj);
+}
+
+void js_gc(js_State *J)
+{
+}
+
+void js_close(js_State *J)
+{
+ js_Function *fun, *nextfun;
+ js_Object *obj, *nextobj;
+ js_Environment *env, *nextenv;
+
+ 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);
+
+ js_freestrings(J);
+
+ free(J->buf.text);
+ free(J);
+}
--- a/jsintern.c
+++ b/jsintern.c
@@ -5,7 +5,7 @@
struct js_StringNode
{
- const char *string;
+ char *string;
js_StringNode *left, *right;
int level;
};
@@ -15,10 +15,10 @@
static js_StringNode *newstringnode(const char *string, const char **result)
{
js_StringNode *node = malloc(sizeof(js_StringNode));
- node->string = *result = strdup(string);
+ node->string = strdup(string);
node->left = node->right = &sentinel;
node->level = 1;
- return node;
+ return *result = node->string, node;
}
static js_StringNode *skew(js_StringNode *node)
@@ -78,7 +78,7 @@
printstringnode(node->right, level + 1);
}
-void js_printstringtree(js_State *J)
+void js_printstrings(js_State *J)
{
js_StringNode *root = J->strings;
printf("--- string dump ---\n");
@@ -85,6 +85,20 @@
if (root && root != &sentinel)
printstringnode(root, 0);
printf("---\n");
+}
+
+static void js_freestringnode(js_State *J, js_StringNode *node)
+{
+ if (node->left != &sentinel) js_freestringnode(J, node->left);
+ if (node->right != &sentinel) js_freestringnode(J, node->right);
+ free(node->string);
+ free(node);
+}
+
+void js_freestrings(js_State *J)
+{
+ if (J->strings && J->strings != &sentinel)
+ js_freestringnode(J, J->strings);
}
const char *js_intern(js_State *J, const char *s)
--- a/jsobject.h
+++ b/jsobject.h
@@ -68,11 +68,14 @@
js_Function *function;
js_CFunction cfunction;
js_CFunction cconstructor;
+
+ js_Object *gcnext;
+ int gcmark;
};
struct js_Property
{
- char *name;
+ const char *name;
js_Property *left, *right;
int level;
js_Value value;
--- a/jsproperty.c
+++ b/jsproperty.c
@@ -21,10 +21,10 @@
static js_Property sentinel = { "", &sentinel, &sentinel, 0 };
-static js_Property *newproperty(const char *name)
+static js_Property *newproperty(js_State *J, const char *name)
{
js_Property *node = malloc(sizeof(js_Property));
- node->name = strdup(name);
+ node->name = js_intern(J, name);
node->left = node->right = &sentinel;
node->level = 1;
node->value.type = JS_TUNDEFINED;
@@ -74,14 +74,14 @@
return node;
}
-static js_Property *insert(js_Property *node, const char *name, js_Property **result)
+static js_Property *insert(js_State *J, js_Property *node, const char *name, js_Property **result)
{
if (node != &sentinel) {
int c = strcmp(name, node->name);
if (c < 0)
- node->left = insert(node->left, name, result);
+ node->left = insert(J, node->left, name, result);
else if (c > 0)
- node->right = insert(node->right, name, result);
+ node->right = insert(J, node->right, name, result);
else
return *result = node;
node = skew(node);
@@ -88,7 +88,7 @@
node = split(node);
return node;
}
- return *result = newproperty(name);
+ return *result = newproperty(J, name);
}
static js_Property *lookupfirst(js_Property *node)
@@ -133,6 +133,10 @@
js_Object *jsR_newobject(js_State *J, js_Class type, js_Object *prototype)
{
js_Object *obj = malloc(sizeof(js_Object));
+ obj->gcmark = 0;
+ obj->gcnext = J->gcobj;
+ J->gcobj = obj;
+
obj->type = type;
obj->properties = &sentinel;
obj->prototype = prototype;
@@ -162,7 +166,7 @@
js_Property *jsR_setproperty(js_State *J, js_Object *obj, const char *name)
{
js_Property *result;
- obj->properties = insert(obj->properties, name, &result);
+ obj->properties = insert(J, obj->properties, name, &result);
return result;
}
--- a/jsrun.c
+++ b/jsrun.c
@@ -324,6 +324,10 @@
js_Environment *jsR_newenvironment(js_State *J, js_Object *vars, js_Environment *outer)
{
js_Environment *E = malloc(sizeof *E);
+ E->gcmark = 0;
+ E->gcnext = J->gcenv;
+ J->gcenv = E;
+
E->outer = outer;
E->variables = vars;
return E;
--- a/jsrun.h
+++ b/jsrun.h
@@ -5,6 +5,9 @@
{
js_Environment *outer;
js_Object *variables;
+
+ js_Environment *gcnext;
+ int gcmark;
};
/* private */
--- a/jsstate.c
+++ b/jsstate.c
@@ -87,12 +87,6 @@
return J;
}
-void js_close(js_State *J)
-{
- free(J->buf.text);
- free(J);
-}
-
int js_error(js_State *J, const char *fmt, ...)
{
va_list ap;
--- a/jsstate.h
+++ b/jsstate.h
@@ -43,6 +43,12 @@
js_Object *G;
js_Environment *E;
+ /* garbage collector list */
+ int gcmark;
+ js_Environment *gcenv;
+ js_Function *gcfun;
+ js_Object *gcobj;
+
int top, bot;
js_Value stack[JS_STACKSIZE];
};