comparison mupdf-source/thirdparty/mujs/jsgc.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 #include "jsi.h"
2 #include "regexp.h"
3
4 static void jsG_freeenvironment(js_State *J, js_Environment *env)
5 {
6 js_free(J, env);
7 }
8
9 static void jsG_freefunction(js_State *J, js_Function *fun)
10 {
11 js_free(J, fun->funtab);
12 js_free(J, fun->vartab);
13 js_free(J, fun->code);
14 js_free(J, fun);
15 }
16
17 static void jsG_freeproperty(js_State *J, js_Property *node)
18 {
19 if (node->left->level) jsG_freeproperty(J, node->left);
20 if (node->right->level) jsG_freeproperty(J, node->right);
21 js_free(J, node);
22 }
23
24 static void jsG_freeiterator(js_State *J, js_Iterator *node)
25 {
26 while (node) {
27 js_Iterator *next = node->next;
28 js_free(J, node);
29 node = next;
30 }
31 }
32
33 static void jsG_freeobject(js_State *J, js_Object *obj)
34 {
35 if (obj->properties->level)
36 jsG_freeproperty(J, obj->properties);
37 if (obj->type == JS_CREGEXP) {
38 js_free(J, obj->u.r.source);
39 js_regfreex(J->alloc, J->actx, obj->u.r.prog);
40 }
41 if (obj->type == JS_CSTRING) {
42 if (obj->u.s.string != obj->u.s.shrstr)
43 js_free(J, obj->u.s.string);
44 }
45 if (obj->type == JS_CARRAY && obj->u.a.simple)
46 js_free(J, obj->u.a.array);
47 if (obj->type == JS_CITERATOR)
48 jsG_freeiterator(J, obj->u.iter.head);
49 if (obj->type == JS_CUSERDATA && obj->u.user.finalize)
50 obj->u.user.finalize(J, obj->u.user.data);
51 if (obj->type == JS_CCFUNCTION && obj->u.c.finalize)
52 obj->u.c.finalize(J, obj->u.c.data);
53 js_free(J, obj);
54 }
55
56 /* Mark and add object to scan queue */
57 static void jsG_markobject(js_State *J, int mark, js_Object *obj)
58 {
59 obj->gcmark = mark;
60 obj->gcroot = J->gcroot;
61 J->gcroot = obj;
62 }
63
64 static void jsG_markfunction(js_State *J, int mark, js_Function *fun)
65 {
66 int i;
67 fun->gcmark = mark;
68 for (i = 0; i < fun->funlen; ++i)
69 if (fun->funtab[i]->gcmark != mark)
70 jsG_markfunction(J, mark, fun->funtab[i]);
71 }
72
73 static void jsG_markenvironment(js_State *J, int mark, js_Environment *env)
74 {
75 do {
76 env->gcmark = mark;
77 if (env->variables->gcmark != mark)
78 jsG_markobject(J, mark, env->variables);
79 env = env->outer;
80 } while (env && env->gcmark != mark);
81 }
82
83 static void jsG_markproperty(js_State *J, int mark, js_Property *node)
84 {
85 if (node->left->level) jsG_markproperty(J, mark, node->left);
86 if (node->right->level) jsG_markproperty(J, mark, node->right);
87
88 if (node->value.t.type == JS_TMEMSTR && node->value.u.memstr->gcmark != mark)
89 node->value.u.memstr->gcmark = mark;
90 if (node->value.t.type == JS_TOBJECT && node->value.u.object->gcmark != mark)
91 jsG_markobject(J, mark, node->value.u.object);
92 if (node->getter && node->getter->gcmark != mark)
93 jsG_markobject(J, mark, node->getter);
94 if (node->setter && node->setter->gcmark != mark)
95 jsG_markobject(J, mark, node->setter);
96 }
97
98 /* Mark everything the object can reach. */
99 static void jsG_scanobject(js_State *J, int mark, js_Object *obj)
100 {
101 if (obj->properties->level)
102 jsG_markproperty(J, mark, obj->properties);
103 if (obj->prototype && obj->prototype->gcmark != mark)
104 jsG_markobject(J, mark, obj->prototype);
105 if (obj->type == JS_CARRAY && obj->u.a.simple) {
106 int i;
107 for (i = 0; i < obj->u.a.flat_length; ++i) {
108 js_Value *v = &obj->u.a.array[i];
109 if (v->t.type == JS_TMEMSTR && v->u.memstr->gcmark != mark)
110 v->u.memstr->gcmark = mark;
111 if (v->t.type == JS_TOBJECT && v->u.object->gcmark != mark)
112 jsG_markobject(J, mark, v->u.object);
113 }
114 }
115 if (obj->type == JS_CITERATOR && obj->u.iter.target->gcmark != mark) {
116 jsG_markobject(J, mark, obj->u.iter.target);
117 }
118 if (obj->type == JS_CFUNCTION || obj->type == JS_CSCRIPT) {
119 if (obj->u.f.scope && obj->u.f.scope->gcmark != mark)
120 jsG_markenvironment(J, mark, obj->u.f.scope);
121 if (obj->u.f.function && obj->u.f.function->gcmark != mark)
122 jsG_markfunction(J, mark, obj->u.f.function);
123 }
124 }
125
126 static void jsG_markstack(js_State *J, int mark)
127 {
128 js_Value *v = J->stack;
129 int n = J->top;
130 while (n--) {
131 if (v->t.type == JS_TMEMSTR && v->u.memstr->gcmark != mark)
132 v->u.memstr->gcmark = mark;
133 if (v->t.type == JS_TOBJECT && v->u.object->gcmark != mark)
134 jsG_markobject(J, mark, v->u.object);
135 ++v;
136 }
137 }
138
139 void js_gc(js_State *J, int report)
140 {
141 js_Function *fun, *nextfun, **prevnextfun;
142 js_Object *obj, *nextobj, **prevnextobj;
143 js_String *str, *nextstr, **prevnextstr;
144 js_Environment *env, *nextenv, **prevnextenv;
145 unsigned int nenv = 0, nfun = 0, nobj = 0, nstr = 0, nprop = 0;
146 unsigned int genv = 0, gfun = 0, gobj = 0, gstr = 0, gprop = 0;
147 int mark;
148 int i;
149
150 if (J->gcpause) {
151 if (report)
152 js_report(J, "garbage collector is paused");
153 return;
154 }
155
156 mark = J->gcmark = J->gcmark == 1 ? 2 : 1;
157
158 /* Add initial roots. */
159
160 jsG_markobject(J, mark, J->Object_prototype);
161 jsG_markobject(J, mark, J->Array_prototype);
162 jsG_markobject(J, mark, J->Function_prototype);
163 jsG_markobject(J, mark, J->Boolean_prototype);
164 jsG_markobject(J, mark, J->Number_prototype);
165 jsG_markobject(J, mark, J->String_prototype);
166 jsG_markobject(J, mark, J->RegExp_prototype);
167 jsG_markobject(J, mark, J->Date_prototype);
168
169 jsG_markobject(J, mark, J->Error_prototype);
170 jsG_markobject(J, mark, J->EvalError_prototype);
171 jsG_markobject(J, mark, J->RangeError_prototype);
172 jsG_markobject(J, mark, J->ReferenceError_prototype);
173 jsG_markobject(J, mark, J->SyntaxError_prototype);
174 jsG_markobject(J, mark, J->TypeError_prototype);
175 jsG_markobject(J, mark, J->URIError_prototype);
176
177 jsG_markobject(J, mark, J->R);
178 jsG_markobject(J, mark, J->G);
179
180 jsG_markstack(J, mark);
181
182 jsG_markenvironment(J, mark, J->E);
183 jsG_markenvironment(J, mark, J->GE);
184 for (i = 0; i < J->envtop; ++i)
185 jsG_markenvironment(J, mark, J->envstack[i]);
186
187 /* Scan objects until none remain. */
188
189 while ((obj = J->gcroot) != NULL) {
190 J->gcroot = obj->gcroot;
191 obj->gcroot = NULL;
192 jsG_scanobject(J, mark, obj);
193 }
194
195 /* Free everything not marked. */
196
197 prevnextenv = &J->gcenv;
198 for (env = J->gcenv; env; env = nextenv) {
199 nextenv = env->gcnext;
200 if (env->gcmark != mark) {
201 *prevnextenv = nextenv;
202 jsG_freeenvironment(J, env);
203 ++genv;
204 } else {
205 prevnextenv = &env->gcnext;
206 }
207 ++nenv;
208 }
209
210 prevnextfun = &J->gcfun;
211 for (fun = J->gcfun; fun; fun = nextfun) {
212 nextfun = fun->gcnext;
213 if (fun->gcmark != mark) {
214 *prevnextfun = nextfun;
215 jsG_freefunction(J, fun);
216 ++gfun;
217 } else {
218 prevnextfun = &fun->gcnext;
219 }
220 ++nfun;
221 }
222
223 prevnextobj = &J->gcobj;
224 for (obj = J->gcobj; obj; obj = nextobj) {
225 nprop += obj->count;
226 nextobj = obj->gcnext;
227 if (obj->gcmark != mark) {
228 gprop += obj->count;
229 *prevnextobj = nextobj;
230 jsG_freeobject(J, obj);
231 ++gobj;
232 } else {
233 prevnextobj = &obj->gcnext;
234 }
235 ++nobj;
236 }
237
238 prevnextstr = &J->gcstr;
239 for (str = J->gcstr; str; str = nextstr) {
240 nextstr = str->gcnext;
241 if (str->gcmark != mark) {
242 *prevnextstr = nextstr;
243 js_free(J, str);
244 ++gstr;
245 } else {
246 prevnextstr = &str->gcnext;
247 }
248 ++nstr;
249 }
250
251 unsigned int ntot = nenv + nfun + nobj + nstr + nprop;
252 unsigned int gtot = genv + gfun + gobj + gstr + gprop;
253 unsigned int remaining = ntot - gtot;
254
255 J->gccounter = remaining;
256 J->gcthresh = remaining * JS_GCFACTOR;
257
258 if (report) {
259 char buf[256];
260 snprintf(buf, sizeof buf, "garbage collected (%d%%): %d/%d envs, %d/%d funs, %d/%d objs, %d/%d props, %d/%d strs",
261 100*gtot/ntot, genv, nenv, gfun, nfun, gobj, nobj, gprop, nprop, gstr, nstr);
262 js_report(J, buf);
263 }
264 }
265
266 void js_freestate(js_State *J)
267 {
268 js_Function *fun, *nextfun;
269 js_Object *obj, *nextobj;
270 js_Environment *env, *nextenv;
271 js_String *str, *nextstr;
272
273 if (!J)
274 return;
275
276 for (env = J->gcenv; env; env = nextenv)
277 nextenv = env->gcnext, jsG_freeenvironment(J, env);
278 for (fun = J->gcfun; fun; fun = nextfun)
279 nextfun = fun->gcnext, jsG_freefunction(J, fun);
280 for (obj = J->gcobj; obj; obj = nextobj)
281 nextobj = obj->gcnext, jsG_freeobject(J, obj);
282 for (str = J->gcstr; str; str = nextstr)
283 nextstr = str->gcnext, js_free(J, str);
284
285 jsS_freestrings(J);
286
287 js_free(J, J->lexbuf.text);
288 J->alloc(J->actx, J->stack, 0);
289 J->alloc(J->actx, J, 0);
290 }