lgc.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /*
  2. ** $Id: lgc.c,v 1.17 1998/03/06 16:54:42 roberto Exp roberto $
  3. ** Garbage Collector
  4. ** See Copyright Notice in lua.h
  5. */
  6. #include "ldo.h"
  7. #include "lfunc.h"
  8. #include "lgc.h"
  9. #include "lmem.h"
  10. #include "lobject.h"
  11. #include "lstate.h"
  12. #include "lstring.h"
  13. #include "ltable.h"
  14. #include "ltm.h"
  15. #include "lua.h"
  16. static int markobject (TObject *o);
  17. /*
  18. ** =======================================================
  19. ** REF mechanism
  20. ** =======================================================
  21. */
  22. int luaC_ref (TObject *o, int lock)
  23. {
  24. int ref;
  25. if (ttype(o) == LUA_T_NIL)
  26. ref = -1; /* special ref for nil */
  27. else {
  28. for (ref=0; ref<L->refSize; ref++)
  29. if (L->refArray[ref].status == FREE)
  30. goto found;
  31. /* no more empty spaces */ {
  32. int oldSize = L->refSize;
  33. L->refSize = luaM_growvector(&L->refArray, L->refSize, struct ref,
  34. refEM, MAX_INT);
  35. for (ref=oldSize; ref<L->refSize; ref++)
  36. L->refArray[ref].status = FREE;
  37. ref = oldSize;
  38. } found:
  39. L->refArray[ref].o = *o;
  40. L->refArray[ref].status = lock ? LOCK : HOLD;
  41. }
  42. return ref;
  43. }
  44. void lua_unref (int ref)
  45. {
  46. if (ref >= 0 && ref < L->refSize)
  47. L->refArray[ref].status = FREE;
  48. }
  49. TObject* luaC_getref (int ref)
  50. {
  51. if (ref == -1)
  52. return &luaO_nilobject;
  53. if (ref >= 0 && ref < L->refSize &&
  54. (L->refArray[ref].status == LOCK || L->refArray[ref].status == HOLD))
  55. return &L->refArray[ref].o;
  56. else
  57. return NULL;
  58. }
  59. static void travlock (void)
  60. {
  61. int i;
  62. for (i=0; i<L->refSize; i++)
  63. if (L->refArray[i].status == LOCK)
  64. markobject(&L->refArray[i].o);
  65. }
  66. static int ismarked (TObject *o)
  67. {
  68. /* valid only for locked objects */
  69. switch (o->ttype) {
  70. case LUA_T_STRING: case LUA_T_USERDATA:
  71. return o->value.ts->head.marked;
  72. case LUA_T_ARRAY:
  73. return o->value.a->head.marked;
  74. case LUA_T_CLOSURE:
  75. return o->value.cl->head.marked;
  76. case LUA_T_PROTO:
  77. return o->value.tf->head.marked;
  78. #ifdef DEBUG
  79. case LUA_T_LINE: case LUA_T_CLMARK:
  80. case LUA_T_CMARK: case LUA_T_PMARK:
  81. LUA_INTERNALERROR("invalid type");
  82. #endif
  83. default: /* nil, number or cproto */
  84. return 1;
  85. }
  86. }
  87. static void invalidaterefs (void)
  88. {
  89. int i;
  90. for (i=0; i<L->refSize; i++)
  91. if (L->refArray[i].status == HOLD && !ismarked(&L->refArray[i].o))
  92. L->refArray[i].status = COLLECTED;
  93. }
  94. void luaC_hashcallIM (Hash *l)
  95. {
  96. TObject t;
  97. ttype(&t) = LUA_T_ARRAY;
  98. for (; l; l=(Hash *)l->head.next) {
  99. avalue(&t) = l;
  100. luaD_gcIM(&t);
  101. }
  102. }
  103. void luaC_strcallIM (TaggedString *l)
  104. {
  105. TObject o;
  106. ttype(&o) = LUA_T_USERDATA;
  107. for (; l; l=(TaggedString *)l->head.next)
  108. if (l->constindex == -1) { /* is userdata? */
  109. tsvalue(&o) = l;
  110. luaD_gcIM(&o);
  111. }
  112. }
  113. static GCnode *listcollect (GCnode *l)
  114. {
  115. GCnode *frees = NULL;
  116. while (l) {
  117. GCnode *next = l->next;
  118. l->marked = 0;
  119. while (next && !next->marked) {
  120. l->next = next->next;
  121. next->next = frees;
  122. frees = next;
  123. next = l->next;
  124. }
  125. l = next;
  126. }
  127. return frees;
  128. }
  129. static void strmark (TaggedString *s)
  130. {
  131. if (!s->head.marked)
  132. s->head.marked = 1;
  133. }
  134. static void protomark (TProtoFunc *f)
  135. {
  136. if (!f->head.marked) {
  137. LocVar *v = f->locvars;
  138. int i;
  139. f->head.marked = 1;
  140. if (f->fileName)
  141. strmark(f->fileName);
  142. for (i=0; i<f->nconsts; i++)
  143. markobject(&f->consts[i]);
  144. if (v) {
  145. for (; v->line != -1; v++)
  146. if (v->varname)
  147. strmark(v->varname);
  148. }
  149. }
  150. }
  151. static void closuremark (Closure *f)
  152. {
  153. if (!f->head.marked) {
  154. int i;
  155. f->head.marked = 1;
  156. for (i=f->nelems; i>=0; i--)
  157. markobject(&f->consts[i]);
  158. }
  159. }
  160. static void hashmark (Hash *h)
  161. {
  162. if (!h->head.marked) {
  163. int i;
  164. h->head.marked = 1;
  165. for (i=0; i<nhash(h); i++) {
  166. Node *n = node(h,i);
  167. if (ttype(ref(n)) != LUA_T_NIL) {
  168. markobject(&n->ref);
  169. markobject(&n->val);
  170. }
  171. }
  172. }
  173. }
  174. static void globalmark (void)
  175. {
  176. TaggedString *g;
  177. for (g=(TaggedString *)L->rootglobal.next; g; g=(TaggedString *)g->head.next){
  178. LUA_ASSERT(g->constindex >= 0, "userdata in global list");
  179. if (g->u.s.globalval.ttype != LUA_T_NIL) {
  180. markobject(&g->u.s.globalval);
  181. strmark(g); /* cannot collect non nil global variables */
  182. }
  183. }
  184. }
  185. static int markobject (TObject *o)
  186. {
  187. switch (ttype(o)) {
  188. case LUA_T_USERDATA: case LUA_T_STRING:
  189. strmark(tsvalue(o));
  190. break;
  191. case LUA_T_ARRAY:
  192. hashmark(avalue(o));
  193. break;
  194. case LUA_T_CLOSURE: case LUA_T_CLMARK:
  195. closuremark(o->value.cl);
  196. break;
  197. case LUA_T_PROTO: case LUA_T_PMARK:
  198. protomark(o->value.tf);
  199. break;
  200. default: break; /* numbers, cprotos, etc */
  201. }
  202. return 0;
  203. }
  204. static void markall (void)
  205. {
  206. luaD_travstack(markobject); /* mark stack objects */
  207. globalmark(); /* mark global variable values and names */
  208. travlock(); /* mark locked objects */
  209. luaT_travtagmethods(markobject); /* mark fallbacks */
  210. }
  211. long lua_collectgarbage (long limit)
  212. {
  213. unsigned long recovered = L->nblocks; /* to subtract nblocks after gc */
  214. Hash *freetable;
  215. TaggedString *freestr;
  216. TProtoFunc *freefunc;
  217. Closure *freeclos;
  218. markall();
  219. invalidaterefs();
  220. freestr = luaS_collector();
  221. freetable = (Hash *)listcollect(&(L->roottable));
  222. freefunc = (TProtoFunc *)listcollect(&(L->rootproto));
  223. freeclos = (Closure *)listcollect(&(L->rootcl));
  224. L->GCthreshold *= 4; /* to avoid GC during GC */
  225. luaC_hashcallIM(freetable); /* GC tag methods for tables */
  226. luaC_strcallIM(freestr); /* GC tag methods for userdata */
  227. luaD_gcIM(&luaO_nilobject); /* GC tag method for nil (signal end of GC) */
  228. luaH_free(freetable);
  229. luaS_free(freestr);
  230. luaF_freeproto(freefunc);
  231. luaF_freeclosure(freeclos);
  232. recovered = recovered-L->nblocks;
  233. L->GCthreshold = (limit == 0) ? 2*L->nblocks : L->nblocks+limit;
  234. return recovered;
  235. }
  236. void luaC_checkGC (void)
  237. {
  238. if (L->nblocks >= L->GCthreshold)
  239. lua_collectgarbage(0);
  240. }