shithub: libmujs

Download patch

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];
 };