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 | |
10 | static void jsG_freeenvironment(js_State *J, js_Environment *env) |
11 | { |
12 | js_free(J, env); |
13 | } |
14 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | 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 | |
229 | void 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 | |