diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 1997-09-16 16:25:59 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 1997-09-16 16:25:59 -0300 |
| commit | 189d64409b5f7e09fb7650e7217d55277b1fccba (patch) | |
| tree | f08f8ba854b92a061435f191e0f0d87fdc06701e | |
| parent | 60cc473bcfce079d1525fcffcfdfbeb66e35afa2 (diff) | |
| download | lua-189d64409b5f7e09fb7650e7217d55277b1fccba.tar.gz lua-189d64409b5f7e09fb7650e7217d55277b1fccba.tar.bz2 lua-189d64409b5f7e09fb7650e7217d55277b1fccba.zip | |
Garbage Collector
| -rw-r--r-- | lgc.c | 295 | ||||
| -rw-r--r-- | lgc.h | 21 |
2 files changed, 316 insertions, 0 deletions
| @@ -0,0 +1,295 @@ | |||
| 1 | /* | ||
| 2 | ** $Id: $ | ||
| 3 | ** Garbage Collector | ||
| 4 | ** See Copyright Notice in lua.h | ||
| 5 | */ | ||
| 6 | |||
| 7 | |||
| 8 | #include "ldo.h" | ||
| 9 | #include "lfunc.h" | ||
| 10 | #include "lgc.h" | ||
| 11 | #include "lglobal.h" | ||
| 12 | #include "lmem.h" | ||
| 13 | #include "lobject.h" | ||
| 14 | #include "lstring.h" | ||
| 15 | #include "ltable.h" | ||
| 16 | #include "ltm.h" | ||
| 17 | #include "lua.h" | ||
| 18 | |||
| 19 | |||
| 20 | |||
| 21 | static int markobject (TObject *o); | ||
| 22 | |||
| 23 | |||
| 24 | |||
| 25 | /* | ||
| 26 | ** ======================================================= | ||
| 27 | ** REF mechanism | ||
| 28 | ** ======================================================= | ||
| 29 | */ | ||
| 30 | |||
| 31 | static struct ref { | ||
| 32 | TObject o; | ||
| 33 | enum {LOCK, HOLD, FREE, COLLECTED} status; | ||
| 34 | } *refArray = NULL; | ||
| 35 | static int refSize = 0; | ||
| 36 | |||
| 37 | |||
| 38 | int luaC_ref (TObject *o, int lock) | ||
| 39 | { | ||
| 40 | int ref; | ||
| 41 | if (ttype(o) == LUA_T_NIL) | ||
| 42 | ref = -1; /* special ref for nil */ | ||
| 43 | else { | ||
| 44 | for (ref=0; ref<refSize; ref++) | ||
| 45 | if (refArray[ref].status == FREE) | ||
| 46 | goto found; | ||
| 47 | /* no more empty spaces */ { | ||
| 48 | int oldSize = refSize; | ||
| 49 | refSize = luaM_growvector(&refArray, refSize, struct ref, refEM, MAX_WORD); | ||
| 50 | for (ref=oldSize; ref<refSize; ref++) | ||
| 51 | refArray[ref].status = FREE; | ||
| 52 | ref = oldSize; | ||
| 53 | } found: | ||
| 54 | refArray[ref].o = *o; | ||
| 55 | refArray[ref].status = lock ? LOCK : HOLD; | ||
| 56 | } | ||
| 57 | return ref; | ||
| 58 | } | ||
| 59 | |||
| 60 | |||
| 61 | void lua_unref (int ref) | ||
| 62 | { | ||
| 63 | if (ref >= 0 && ref < refSize) | ||
| 64 | refArray[ref].status = FREE; | ||
| 65 | } | ||
| 66 | |||
| 67 | |||
| 68 | TObject* luaC_getref (int ref) | ||
| 69 | { | ||
| 70 | static TObject nul = {LUA_T_NIL, {0}}; | ||
| 71 | if (ref == -1) | ||
| 72 | return &nul; | ||
| 73 | if (ref >= 0 && ref < refSize && | ||
| 74 | (refArray[ref].status == LOCK || refArray[ref].status == HOLD)) | ||
| 75 | return &refArray[ref].o; | ||
| 76 | else | ||
| 77 | return NULL; | ||
| 78 | } | ||
| 79 | |||
| 80 | |||
| 81 | static void travlock (void) | ||
| 82 | { | ||
| 83 | int i; | ||
| 84 | for (i=0; i<refSize; i++) | ||
| 85 | if (refArray[i].status == LOCK) | ||
| 86 | markobject(&refArray[i].o); | ||
| 87 | } | ||
| 88 | |||
| 89 | |||
| 90 | static int ismarked (TObject *o) | ||
| 91 | { | ||
| 92 | switch (o->ttype) { | ||
| 93 | case LUA_T_STRING: case LUA_T_USERDATA: | ||
| 94 | return o->value.ts->marked; | ||
| 95 | case LUA_T_FUNCTION: | ||
| 96 | return o->value.cl->head.marked; | ||
| 97 | case LUA_T_PROTO: | ||
| 98 | return o->value.tf->head.marked; | ||
| 99 | case LUA_T_ARRAY: | ||
| 100 | return o->value.a->head.marked; | ||
| 101 | default: /* nil, number or cfunction */ | ||
| 102 | return 1; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | |||
| 107 | static void invalidaterefs (void) | ||
| 108 | { | ||
| 109 | int i; | ||
| 110 | for (i=0; i<refSize; i++) | ||
| 111 | if (refArray[i].status == HOLD && !ismarked(&refArray[i].o)) | ||
| 112 | refArray[i].status = COLLECTED; | ||
| 113 | } | ||
| 114 | |||
| 115 | |||
| 116 | |||
| 117 | static void hashcallIM (Hash *l) | ||
| 118 | { | ||
| 119 | TObject t; | ||
| 120 | ttype(&t) = LUA_T_ARRAY; | ||
| 121 | for (; l; l=(Hash *)l->head.next) { | ||
| 122 | avalue(&t) = l; | ||
| 123 | luaD_gcIM(&t); | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | |||
| 128 | static void strcallIM (TaggedString *l) | ||
| 129 | { | ||
| 130 | TObject o; | ||
| 131 | ttype(&o) = LUA_T_USERDATA; | ||
| 132 | for (; l; l=l->uu.next) { | ||
| 133 | tsvalue(&o) = l; | ||
| 134 | luaD_gcIM(&o); | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | |||
| 139 | |||
| 140 | static GCnode *listcollect (GCnode **root) | ||
| 141 | { | ||
| 142 | GCnode *curr = *root, *prev = NULL, *frees = NULL; | ||
| 143 | while (curr) { | ||
| 144 | GCnode *next = curr->next; | ||
| 145 | if (!curr->marked) { | ||
| 146 | if (prev == NULL) | ||
| 147 | *root = next; | ||
| 148 | else | ||
| 149 | prev->next = next; | ||
| 150 | curr->next = frees; | ||
| 151 | frees = curr; | ||
| 152 | --luaO_nentities; | ||
| 153 | } | ||
| 154 | else { | ||
| 155 | curr->marked = 0; | ||
| 156 | prev = curr; | ||
| 157 | } | ||
| 158 | curr = next; | ||
| 159 | } | ||
| 160 | return frees; | ||
| 161 | } | ||
| 162 | |||
| 163 | |||
| 164 | |||
| 165 | static void strmark (TaggedString *s) | ||
| 166 | { | ||
| 167 | if (!s->marked) | ||
| 168 | s->marked = 1; | ||
| 169 | } | ||
| 170 | |||
| 171 | |||
| 172 | static void protomark (TProtoFunc *f) | ||
| 173 | { | ||
| 174 | if (!f->head.marked) { | ||
| 175 | LocVar *v = f->locvars; | ||
| 176 | int i; | ||
| 177 | f->head.marked = 1; | ||
| 178 | if (f->fileName) | ||
| 179 | strmark(f->fileName); | ||
| 180 | for (i=0; i<f->nconsts; i++) | ||
| 181 | markobject(&f->consts[i]); | ||
| 182 | if (v) { | ||
| 183 | for (; v->line != -1; v++) | ||
| 184 | if (v->varname) | ||
| 185 | strmark(v->varname); | ||
| 186 | } | ||
| 187 | } | ||
| 188 | } | ||
| 189 | |||
| 190 | |||
| 191 | static void funcmark (Closure *f) | ||
| 192 | { | ||
| 193 | if (!f->head.marked) { | ||
| 194 | int i; | ||
| 195 | f->head.marked = 1; | ||
| 196 | for (i=f->consts[0].value.tf->nupvalues; i>=0; i--) | ||
| 197 | markobject(&f->consts[i]); | ||
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 201 | |||
| 202 | static void hashmark (Hash *h) | ||
| 203 | { | ||
| 204 | if (!h->head.marked) { | ||
| 205 | int i; | ||
| 206 | h->head.marked = 1; | ||
| 207 | for (i=0; i<nhash(h); i++) { | ||
| 208 | Node *n = node(h,i); | ||
| 209 | if (ttype(ref(n)) != LUA_T_NIL) { | ||
| 210 | markobject(&n->ref); | ||
| 211 | markobject(&n->val); | ||
| 212 | } | ||
| 213 | } | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | |||
| 218 | static int markobject (TObject *o) | ||
| 219 | { | ||
| 220 | switch (ttype(o)) { | ||
| 221 | case LUA_T_USERDATA: case LUA_T_STRING: | ||
| 222 | strmark(tsvalue(o)); | ||
| 223 | break; | ||
| 224 | case LUA_T_ARRAY: | ||
| 225 | hashmark(avalue(o)); | ||
| 226 | break; | ||
| 227 | case LUA_T_FUNCTION: case LUA_T_MARK: | ||
| 228 | funcmark(o->value.cl); | ||
| 229 | break; | ||
| 230 | case LUA_T_PROTO: | ||
| 231 | protomark(o->value.tf); | ||
| 232 | break; | ||
| 233 | default: break; /* numbers, cfunctions, etc */ | ||
| 234 | } | ||
| 235 | return 0; | ||
| 236 | } | ||
| 237 | |||
| 238 | |||
| 239 | static void call_nilIM (void) | ||
| 240 | { /* signals end of garbage collection */ | ||
| 241 | TObject t; | ||
| 242 | ttype(&t) = LUA_T_NIL; | ||
| 243 | luaD_gcIM(&t); /* end of list */ | ||
| 244 | } | ||
| 245 | |||
| 246 | |||
| 247 | |||
| 248 | #define GARBAGE_BLOCK 150 | ||
| 249 | |||
| 250 | long luaC_threshold = GARBAGE_BLOCK; | ||
| 251 | |||
| 252 | |||
| 253 | static void markall (void) | ||
| 254 | { | ||
| 255 | luaD_travstack(markobject); /* mark stack objects */ | ||
| 256 | luaG_travsymbol(markobject); /* mark symbol table objects */ | ||
| 257 | travlock(); /* mark locked objects */ | ||
| 258 | luaT_travtagmethods(markobject); /* mark fallbacks */ | ||
| 259 | } | ||
| 260 | |||
| 261 | |||
| 262 | long lua_collectgarbage (long limit) | ||
| 263 | { | ||
| 264 | long recovered = luaO_nentities; /* to subtract luaM_new value after gc */ | ||
| 265 | Hash *freetable; | ||
| 266 | TaggedString *freestr; | ||
| 267 | TProtoFunc *freefunc; | ||
| 268 | Closure *freeclos; | ||
| 269 | markall(); | ||
| 270 | invalidaterefs(); | ||
| 271 | freestr = luaS_collector(); | ||
| 272 | freetable = (Hash *)listcollect((GCnode **)&luaH_root); | ||
| 273 | freefunc = (TProtoFunc *)listcollect((GCnode **)&luaF_root); | ||
| 274 | freeclos = (Closure *)listcollect((GCnode **)&luaF_rootcl); | ||
| 275 | recovered = recovered-luaO_nentities; | ||
| 276 | /*printf("==total %ld coletados %ld\n", luaO_nentities+recovered, recovered);*/ | ||
| 277 | luaC_threshold = (limit == 0) ? 2*luaO_nentities : luaO_nentities+limit; | ||
| 278 | hashcallIM(freetable); | ||
| 279 | strcallIM(freestr); | ||
| 280 | call_nilIM(); | ||
| 281 | luaH_free(freetable); | ||
| 282 | luaS_free(freestr); | ||
| 283 | luaF_freeproto(freefunc); | ||
| 284 | luaF_freeclosure(freeclos); | ||
| 285 | luaM_clearbuffer(); | ||
| 286 | return recovered; | ||
| 287 | } | ||
| 288 | |||
| 289 | |||
| 290 | void luaC_checkGC (void) | ||
| 291 | { | ||
| 292 | if (luaO_nentities >= luaC_threshold) | ||
| 293 | lua_collectgarbage(0); | ||
| 294 | } | ||
| 295 | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | /* | ||
| 2 | ** $Id: $ | ||
| 3 | ** Garbage Collector | ||
| 4 | ** See Copyright Notice in lua.h | ||
| 5 | */ | ||
| 6 | |||
| 7 | #ifndef lgc_h | ||
| 8 | #define lgc_h | ||
| 9 | |||
| 10 | |||
| 11 | #include "lobject.h" | ||
| 12 | |||
| 13 | |||
| 14 | extern long luaC_threshold; | ||
| 15 | |||
| 16 | void luaC_checkGC (void); | ||
| 17 | TObject* luaC_getref (int ref); | ||
| 18 | int luaC_ref (TObject *o, int lock); | ||
| 19 | |||
| 20 | |||
| 21 | #endif | ||
