shithub: libmujs

Download patch

ref: 331c5ecbaca705eb8c899e814afe94971b14207b
parent: 8c5f2f24c7d7da0a2fceaf32aaa9e80d0b3b7c86
author: Tor Andersson <tor.andersson@artifex.com>
date: Thu May 14 09:42:00 EDT 2020

Issue 133: Eliminate recursion in GC scanning phase.

Use a queue instead of recursion to scan reachable objects.

--- a/jsgc.c
+++ b/jsgc.c
@@ -5,8 +5,6 @@
 
 #include "regexp.h"
 
-static void jsG_markobject(js_State *J, int mark, js_Object *obj);
-
 static void jsG_freeenvironment(js_State *J, js_Environment *env)
 {
 	js_free(J, env);
@@ -53,6 +51,14 @@
 	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;
@@ -87,9 +93,9 @@
 		jsG_markobject(J, mark, node->setter);
 }
 
-static void jsG_markobject(js_State *J, int mark, js_Object *obj)
+/* Mark everything the object can reach. */
+static void jsG_scanobject(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)
@@ -139,6 +145,8 @@
 
 	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);
@@ -165,6 +173,16 @@
 	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) {
--- a/jsi.h
+++ b/jsi.h
@@ -239,6 +239,8 @@
 	js_Object *gcobj;
 	js_String *gcstr;
 
+	js_Object *gcroot; /* gc scan list */
+
 	/* environments on the call stack but currently not in scope */
 	int envtop;
 	js_Environment *envstack[JS_ENVLIMIT];
--- a/jsvalue.h
+++ b/jsvalue.h
@@ -119,7 +119,8 @@
 			js_Finalize finalize;
 		} user;
 	} u;
-	js_Object *gcnext;
+	js_Object *gcnext; /* allocation list */
+	js_Object *gcroot; /* scan list */
 	int gcmark;
 };