1 #include "jsi.h"
2 #include "jscompile.h"
3 #include "jsvalue.h"
4 #include "jsrun.h"
5 
6 #include "regexp.h"
7 
8 static void jsG_markobject(js_State *J, int mark, js_Object *obj);
9 
jsG_freeenvironment(js_State * J,js_Environment * env)10 static void jsG_freeenvironment(js_State *J, js_Environment *env)
11 {
12 	js_free(J, env);
13 }
14 
jsG_freefunction(js_State * J,js_Function * fun)15 static void jsG_freefunction(js_State *J, js_Function *fun)
16 {
17 	js_free(J, fun->funtab);
18 	js_free(J, fun->numtab);
19 	js_free(J, fun->strtab);
20 	js_free(J, fun->vartab);
21 	js_free(J, fun->code);
22 	js_free(J, fun);
23 }
24 
jsG_freeproperty(js_State * J,js_Property * node)25 static void jsG_freeproperty(js_State *J, js_Property *node)
26 {
27 	if (node->left->level) jsG_freeproperty(J, node->left);
28 	if (node->right->level) jsG_freeproperty(J, node->right);
29 	js_free(J, node);
30 }
31 
jsG_freeiterator(js_State * J,js_Iterator * node)32 static void jsG_freeiterator(js_State *J, js_Iterator *node)
33 {
34 	while (node) {
35 		js_Iterator *next = node->next;
36 		js_free(J, node);
37 		node = next;
38 	}
39 }
40 
jsG_freeobject(js_State * J,js_Object * obj)41 static void jsG_freeobject(js_State *J, js_Object *obj)
42 {
43 	if (obj->properties->level)
44 		jsG_freeproperty(J, obj->properties);
45 	if (obj->type == JS_CREGEXP) {
46 		js_free(J, obj->u.r.source);
47 		js_regfreex(J->alloc, J->actx, obj->u.r.prog);
48 	}
49 	if (obj->type == JS_CITERATOR)
50 		jsG_freeiterator(J, obj->u.iter.head);
51 	if (obj->type == JS_CUSERDATA && obj->u.user.finalize)
52 		obj->u.user.finalize(J, obj->u.user.data);
53 	js_free(J, obj);
54 }
55 
jsG_markfunction(js_State * J,int mark,js_Function * fun)56 static void jsG_markfunction(js_State *J, int mark, js_Function *fun)
57 {
58 	int i;
59 	fun->gcmark = mark;
60 	for (i = 0; i < fun->funlen; ++i)
61 		if (fun->funtab[i]->gcmark != mark)
62 			jsG_markfunction(J, mark, fun->funtab[i]);
63 }
64 
jsG_markenvironment(js_State * J,int mark,js_Environment * env)65 static void jsG_markenvironment(js_State *J, int mark, js_Environment *env)
66 {
67 	do {
68 		env->gcmark = mark;
69 		if (env->variables->gcmark != mark)
70 			jsG_markobject(J, mark, env->variables);
71 		env = env->outer;
72 	} while (env && env->gcmark != mark);
73 }
74 
jsG_markproperty(js_State * J,int mark,js_Property * node)75 static void jsG_markproperty(js_State *J, int mark, js_Property *node)
76 {
77 	if (node->left->level) jsG_markproperty(J, mark, node->left);
78 	if (node->right->level) jsG_markproperty(J, mark, node->right);
79 
80 	if (node->value.type == JS_TMEMSTR && node->value.u.memstr->gcmark != mark)
81 		node->value.u.memstr->gcmark = mark;
82 	if (node->value.type == JS_TOBJECT && node->value.u.object->gcmark != mark)
83 		jsG_markobject(J, mark, node->value.u.object);
84 	if (node->getter && node->getter->gcmark != mark)
85 		jsG_markobject(J, mark, node->getter);
86 	if (node->setter && node->setter->gcmark != mark)
87 		jsG_markobject(J, mark, node->setter);
88 }
89 
jsG_markobject(js_State * J,int mark,js_Object * obj)90 static void jsG_markobject(js_State *J, int mark, js_Object *obj)
91 {
92 	obj->gcmark = mark;
93 	if (obj->properties->level)
94 		jsG_markproperty(J, mark, obj->properties);
95 	if (obj->prototype && obj->prototype->gcmark != mark)
96 		jsG_markobject(J, mark, obj->prototype);
97 	if (obj->type == JS_CITERATOR) {
98 		jsG_markobject(J, mark, obj->u.iter.target);
99 	}
100 	if (obj->type == JS_CFUNCTION || obj->type == JS_CSCRIPT) {
101 		if (obj->u.f.scope && obj->u.f.scope->gcmark != mark)
102 			jsG_markenvironment(J, mark, obj->u.f.scope);
103 		if (obj->u.f.function && obj->u.f.function->gcmark != mark)
104 			jsG_markfunction(J, mark, obj->u.f.function);
105 	}
106 }
107 
jsG_markstack(js_State * J,int mark)108 static void jsG_markstack(js_State *J, int mark)
109 {
110 	js_Value *v = J->stack;
111 	int n = J->top;
112 	while (n--) {
113 		if (v->type == JS_TMEMSTR && v->u.memstr->gcmark != mark)
114 			v->u.memstr->gcmark = mark;
115 		if (v->type == JS_TOBJECT && v->u.object->gcmark != mark)
116 			jsG_markobject(J, mark, v->u.object);
117 		++v;
118 	}
119 }
120 
js_gc(js_State * J,int report)121 void js_gc(js_State *J, int report)
122 {
123 	js_Function *fun, *nextfun, **prevnextfun;
124 	js_Object *obj, *nextobj, **prevnextobj;
125 	js_String *str, *nextstr, **prevnextstr;
126 	js_Environment *env, *nextenv, **prevnextenv;
127 	int nenv = 0, nfun = 0, nobj = 0, nstr = 0;
128 	int genv = 0, gfun = 0, gobj = 0, gstr = 0;
129 	int mark;
130 	int i;
131 
132 	mark = J->gcmark = J->gcmark == 1 ? 2 : 1;
133 
134 	jsG_markobject(J, mark, J->Object_prototype);
135 	jsG_markobject(J, mark, J->Array_prototype);
136 	jsG_markobject(J, mark, J->Function_prototype);
137 	jsG_markobject(J, mark, J->Boolean_prototype);
138 	jsG_markobject(J, mark, J->Number_prototype);
139 	jsG_markobject(J, mark, J->String_prototype);
140 	jsG_markobject(J, mark, J->RegExp_prototype);
141 	jsG_markobject(J, mark, J->Date_prototype);
142 
143 	jsG_markobject(J, mark, J->Error_prototype);
144 	jsG_markobject(J, mark, J->EvalError_prototype);
145 	jsG_markobject(J, mark, J->RangeError_prototype);
146 	jsG_markobject(J, mark, J->ReferenceError_prototype);
147 	jsG_markobject(J, mark, J->SyntaxError_prototype);
148 	jsG_markobject(J, mark, J->TypeError_prototype);
149 	jsG_markobject(J, mark, J->URIError_prototype);
150 
151 	jsG_markobject(J, mark, J->R);
152 	jsG_markobject(J, mark, J->G);
153 
154 	jsG_markstack(J, mark);
155 
156 	jsG_markenvironment(J, mark, J->E);
157 	jsG_markenvironment(J, mark, J->GE);
158 	for (i = 0; i < J->envtop; ++i)
159 		jsG_markenvironment(J, mark, J->envstack[i]);
160 
161 	prevnextenv = &J->gcenv;
162 	for (env = J->gcenv; env; env = nextenv) {
163 		nextenv = env->gcnext;
164 		if (env->gcmark != mark) {
165 			*prevnextenv = nextenv;
166 			jsG_freeenvironment(J, env);
167 			++genv;
168 		} else {
169 			prevnextenv = &env->gcnext;
170 		}
171 		++nenv;
172 	}
173 
174 	prevnextfun = &J->gcfun;
175 	for (fun = J->gcfun; fun; fun = nextfun) {
176 		nextfun = fun->gcnext;
177 		if (fun->gcmark != mark) {
178 			*prevnextfun = nextfun;
179 			jsG_freefunction(J, fun);
180 			++gfun;
181 		} else {
182 			prevnextfun = &fun->gcnext;
183 		}
184 		++nfun;
185 	}
186 
187 	prevnextobj = &J->gcobj;
188 	for (obj = J->gcobj; obj; obj = nextobj) {
189 		nextobj = obj->gcnext;
190 		if (obj->gcmark != mark) {
191 			*prevnextobj = nextobj;
192 			jsG_freeobject(J, obj);
193 			++gobj;
194 		} else {
195 			prevnextobj = &obj->gcnext;
196 		}
197 		++nobj;
198 	}
199 
200 	prevnextstr = &J->gcstr;
201 	for (str = J->gcstr; str; str = nextstr) {
202 		nextstr = str->gcnext;
203 		if (str->gcmark != mark) {
204 			*prevnextstr = nextstr;
205 			js_free(J, str);
206 			++gstr;
207 		} else {
208 			prevnextstr = &str->gcnext;
209 		}
210 		++nstr;
211 	}
212 
213 	if (report) {
214 		char buf[256];
215 		snprintf(buf, sizeof buf, "garbage collected: %d/%d envs, %d/%d funs, %d/%d objs, %d/%d strs",
216 			genv, nenv, gfun, nfun, gobj, nobj, gstr, nstr);
217 		js_report(J, buf);
218 	}
219 }
220 
js_freestate(js_State * J)221 void js_freestate(js_State *J)
222 {
223 	js_Function *fun, *nextfun;
224 	js_Object *obj, *nextobj;
225 	js_Environment *env, *nextenv;
226 	js_String *str, *nextstr;
227 
228 	if (!J)
229 		return;
230 
231 	for (env = J->gcenv; env; env = nextenv)
232 		nextenv = env->gcnext, jsG_freeenvironment(J, env);
233 	for (fun = J->gcfun; fun; fun = nextfun)
234 		nextfun = fun->gcnext, jsG_freefunction(J, fun);
235 	for (obj = J->gcobj; obj; obj = nextobj)
236 		nextobj = obj->gcnext, jsG_freeobject(J, obj);
237 	for (str = J->gcstr; str; str = nextstr)
238 		nextstr = str->gcnext, js_free(J, str);
239 
240 	jsS_freestrings(J);
241 
242 	js_free(J, J->lexbuf.text);
243 	J->alloc(J->actx, J->stack, 0);
244 	J->alloc(J->actx, J, 0);
245 }
246