jsgc.c 7.7 KB

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