1#include "jsi.h"
2#include "jscompile.h"
3#include "jsvalue.h"
4#include "jsrun.h"
5
6#include "regexp.h"
7
8static void jsG_markobject(js_State *J, int mark, js_Object *obj);
9
10static void jsG_freeenvironment(js_State *J, js_Environment *env)
11{
12 js_free(J, env);
13}
14
15static 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
25static 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
32static 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
41static 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
56static 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
65static 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
75static 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
90static 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
108static 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
121void 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 if (J->gcpause) {
133 if (report)
134 js_report(J, "garbage collector is paused");
135 return;
136 }
137
138 J->gccounter = 0;
139
140 mark = J->gcmark = J->gcmark == 1 ? 2 : 1;
141
142 jsG_markobject(J, mark, J->Object_prototype);
143 jsG_markobject(J, mark, J->Array_prototype);
144 jsG_markobject(J, mark, J->Function_prototype);
145 jsG_markobject(J, mark, J->Boolean_prototype);
146 jsG_markobject(J, mark, J->Number_prototype);
147 jsG_markobject(J, mark, J->String_prototype);
148 jsG_markobject(J, mark, J->RegExp_prototype);
149 jsG_markobject(J, mark, J->Date_prototype);
150
151 jsG_markobject(J, mark, J->Error_prototype);
152 jsG_markobject(J, mark, J->EvalError_prototype);
153 jsG_markobject(J, mark, J->RangeError_prototype);
154 jsG_markobject(J, mark, J->ReferenceError_prototype);
155 jsG_markobject(J, mark, J->SyntaxError_prototype);
156 jsG_markobject(J, mark, J->TypeError_prototype);
157 jsG_markobject(J, mark, J->URIError_prototype);
158
159 jsG_markobject(J, mark, J->R);
160 jsG_markobject(J, mark, J->G);
161
162 jsG_markstack(J, mark);
163
164 jsG_markenvironment(J, mark, J->E);
165 jsG_markenvironment(J, mark, J->GE);
166 for (i = 0; i < J->envtop; ++i)
167 jsG_markenvironment(J, mark, J->envstack[i]);
168
169 prevnextenv = &J->gcenv;
170 for (env = J->gcenv; env; env = nextenv) {
171 nextenv = env->gcnext;
172 if (env->gcmark != mark) {
173 *prevnextenv = nextenv;
174 jsG_freeenvironment(J, env);
175 ++genv;
176 } else {
177 prevnextenv = &env->gcnext;
178 }
179 ++nenv;
180 }
181
182 prevnextfun = &J->gcfun;
183 for (fun = J->gcfun; fun; fun = nextfun) {
184 nextfun = fun->gcnext;
185 if (fun->gcmark != mark) {
186 *prevnextfun = nextfun;
187 jsG_freefunction(J, fun);
188 ++gfun;
189 } else {
190 prevnextfun = &fun->gcnext;
191 }
192 ++nfun;
193 }
194
195 prevnextobj = &J->gcobj;
196 for (obj = J->gcobj; obj; obj = nextobj) {
197 nextobj = obj->gcnext;
198 if (obj->gcmark != mark) {
199 *prevnextobj = nextobj;
200 jsG_freeobject(J, obj);
201 ++gobj;
202 } else {
203 prevnextobj = &obj->gcnext;
204 }
205 ++nobj;
206 }
207
208 prevnextstr = &J->gcstr;
209 for (str = J->gcstr; str; str = nextstr) {
210 nextstr = str->gcnext;
211 if (str->gcmark != mark) {
212 *prevnextstr = nextstr;
213 js_free(J, str);
214 ++gstr;
215 } else {
216 prevnextstr = &str->gcnext;
217 }
218 ++nstr;
219 }
220
221 if (report) {
222 char buf[256];
223 snprintf(buf, sizeof buf, "garbage collected: %d/%d envs, %d/%d funs, %d/%d objs, %d/%d strs",
224 genv, nenv, gfun, nfun, gobj, nobj, gstr, nstr);
225 js_report(J, buf);
226 }
227}
228
229void js_freestate(js_State *J)
230{
231 js_Function *fun, *nextfun;
232 js_Object *obj, *nextobj;
233 js_Environment *env, *nextenv;
234 js_String *str, *nextstr;
235
236 if (!J)
237 return;
238
239 for (env = J->gcenv; env; env = nextenv)
240 nextenv = env->gcnext, jsG_freeenvironment(J, env);
241 for (fun = J->gcfun; fun; fun = nextfun)
242 nextfun = fun->gcnext, jsG_freefunction(J, fun);
243 for (obj = J->gcobj; obj; obj = nextobj)
244 nextobj = obj->gcnext, jsG_freeobject(J, obj);
245 for (str = J->gcstr; str; str = nextstr)
246 nextstr = str->gcnext, js_free(J, str);
247
248 jsS_freestrings(J);
249
250 js_free(J, J->lexbuf.text);
251 J->alloc(J->actx, J->stack, 0);
252 J->alloc(J->actx, J, 0);
253}
254