Mercurial > hgrepos > Python2 > PyMuPDF
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 } |
