GC
1. 怎么回收的lua 中所有已经分配的数据都会用一些指令的数据结构来记录,当需要回收时,先遍历当前栈内所有 object,把 ref 标志位打上 1,遍历符号表(这部分不能回收),反符号表中的所有对象的 ref 标志位也打上 1, 如果有其它不用回收的也同样操作。回收也比较简单,这里遍历所有内部数据结构,如果是 0 就直接释放, 如果是 1 就置 0(可能下次就回收了), 这样就结束了
2. 何时回收
这个 1.1 有个内部阀值,当新加 object 的数量到达阀值时,就会触发回收机制。
数据结构
Hash
typedef struct Hash { char mark; unsigned int nhash; Node **list; } Hash; typedef struct node { Object ref; Object val; struct node *next; } Node; typedef union { Cfunction f; real n; char *s; Byte *b; struct Hash *a; void *u; } Value; typedef struct Object { Type tag; Value value; } Object; typedef struct { char *name; Object object; } Symbol;
全局数据区
extern Symbol *lua_table; /* key - value 表*/ extern Word lua_ntable; static Symbol tablebuffer[MAXSYMBOL] = { {"type",{T_CFUNCTION,{lua_type}}}, ... }; /* list 和数组的结合使用,目地是用 list 和 array 的特性, 参考 lua_findsymbol 在 list 中查找,找到放到头(这样效率高点,下次再被用的概率大点), 没找到,就在头 节点上加一个 */ Symbol *lua_table=tablebuffer; Word lua_ntable=7; static struct List o6={ tablebuffer+6, 0}; static struct List o5={ tablebuffer+5, &o6 }; static struct List o4={ tablebuffer+4, &o5 }; static struct List o3={ tablebuffer+3, &o4 }; static struct List o2={ tablebuffer+2, &o3 }; static struct List o1={ tablebuffer+1, &o2 }; static struct List o0={ tablebuffer+0, &o1 }; static struct List *searchlist=&o0; extern char **lua_constant; /* 常量表 */ extern Word lua_nconstant; static char tm[] = " mark"; static char *constantbuffer[MAXCONSTANT] = {tm+1, ti+1, ... }; extern char **lua_string; /* 就是普通的字符指针数组 *、 extern Word lua_nstring; static char *stringbuffer[MAXSTRING]; char **lua_string = stringbuffer; Word lua_nstring=0; extern Hash **lua_array; extern Word lua_narray; extern char *lua_file[]; /* 记录指针的数组 */ extern int lua_nfile;
ps: lua_next 和 lua_nextval 可以看下,这个有点像迭代器的实现
虚拟指令
这个还是建议读下,主要就是对 stack 和 pc 的操作。
/* ** Execute the given opcode. Return 0 in success or 1 on error. */ int lua_execute (Byte *pc) { Object *oldbase = base; base = top; while (1) { OpCode opcode; switch (opcode = (OpCode)*pc++) { case PUSHNIL: tag(top++) = T_NIL; break; case PUSH0: tag(top) = T_NUMBER; nvalue(top++) = 0; break; case PUSH1: tag(top) = T_NUMBER; nvalue(top++) = 1; break; case PUSH2: tag(top) = T_NUMBER; nvalue(top++) = 2; break; case PUSHBYTE: tag(top) = T_NUMBER; nvalue(top++) = *pc++; break; case PUSHWORD: { CodeWord code; get_word(code,pc); tag(top) = T_NUMBER; nvalue(top++) = code.w; } break; case PUSHFLOAT: { CodeFloat code; get_float(code,pc); tag(top) = T_NUMBER; nvalue(top++) = code.f; } break; case PUSHSTRING: { CodeWord code; get_word(code,pc); tag(top) = T_STRING; svalue(top++) = lua_constant[code.w]; } break; case PUSHLOCAL0: case PUSHLOCAL1: case PUSHLOCAL2: case PUSHLOCAL3: case PUSHLOCAL4: case PUSHLOCAL5: case PUSHLOCAL6: case PUSHLOCAL7: case PUSHLOCAL8: case PUSHLOCAL9: *top++ = *(base + (int)(opcode-PUSHLOCAL0)); break; case PUSHLOCAL: *top++ = *(base + (*pc++)); break; case PUSHGLOBAL: { CodeWord code; get_word(code,pc); *top++ = s_object(code.w); } break; case PUSHINDEXED: --top; if (tag(top-1) != T_ARRAY) { lua_reportbug ("indexed expression not a table"); return 1; } { Object *h = lua_hashdefine (avalue(top-1), top); if (h == NULL) return 1; *(top-1) = *h; } break; case PUSHMARK: tag(top++) = T_MARK; break; case PUSHOBJECT: *top = *(top-3); top++; break; case STORELOCAL0: case STORELOCAL1: case STORELOCAL2: case STORELOCAL3: case STORELOCAL4: case STORELOCAL5: case STORELOCAL6: case STORELOCAL7: case STORELOCAL8: case STORELOCAL9: *(base + (int)(opcode-STORELOCAL0)) = *(--top); break; case STORELOCAL: *(base + (*pc++)) = *(--top); break; case STOREGLOBAL: { CodeWord code; get_word(code,pc); s_object(code.w) = *(--top); } break; case STOREINDEXED0: if (tag(top-3) != T_ARRAY) { lua_reportbug ("indexed expression not a table"); return 1; } { Object *h = lua_hashdefine (avalue(top-3), top-2); if (h == NULL) return 1; *h = *(top-1); } top -= 3; break; case STOREINDEXED: { int n = *pc++; if (tag(top-3-n) != T_ARRAY) { lua_reportbug ("indexed expression not a table"); return 1; } { Object *h = lua_hashdefine (avalue(top-3-n), top-2-n); if (h == NULL) return 1; *h = *(top-1); } top--; } break; case STORELIST0: case STORELIST: { int m, n; Object *arr; if (opcode == STORELIST0) m = 0; else m = *(pc++) * FIELDS_PER_FLUSH; n = *(pc++); arr = top-n-1; if (tag(arr) != T_ARRAY) { lua_reportbug ("internal error - table expected"); return 1; } while (n) { tag(top) = T_NUMBER; nvalue(top) = n+m; *(lua_hashdefine (avalue(arr), top)) = *(top-1); top--; n--; } } break; case STORERECORD: { int n = *(pc++); Object *arr = top-n-1; if (tag(arr) != T_ARRAY) { lua_reportbug ("internal error - table expected"); return 1; } while (n) { CodeWord code; get_word(code,pc); tag(top) = T_STRING; svalue(top) = lua_constant[code.w]; *(lua_hashdefine (avalue(arr), top)) = *(top-1); top--; n--; } } break; case ADJUST: { Object *newtop = base + *(pc++); while (top < newtop) tag(top++) = T_NIL; top = newtop; /* top could be bigger than newtop */ } break; case CREATEARRAY: if (tag(top-1) == T_NIL) nvalue(top-1) = 101; else { if (tonumber(top-1)) return 1; if (nvalue(top-1) <= 0) nvalue(top-1) = 101; } avalue(top-1) = lua_createarray(nvalue(top-1)); if (avalue(top-1) == NULL) return 1; tag(top-1) = T_ARRAY; break; case EQOP: { Object *l = top-2; Object *r = top-1; --top; if (tag(l) != tag(r)) tag(top-1) = T_NIL; else { switch (tag(l)) { case T_NIL: tag(top-1) = T_NUMBER; break; case T_NUMBER: tag(top-1) = (nvalue(l) == nvalue(r)) ? T_NUMBER : T_NIL; break; case T_ARRAY: tag(top-1) = (avalue(l) == avalue(r)) ? T_NUMBER : T_NIL; break; case T_FUNCTION: tag(top-1) = (bvalue(l) == bvalue(r)) ? T_NUMBER : T_NIL; break; case T_CFUNCTION: tag(top-1) = (fvalue(l) == fvalue(r)) ? T_NUMBER : T_NIL; break; case T_USERDATA: tag(top-1) = (uvalue(l) == uvalue(r)) ? T_NUMBER : T_NIL; break; case T_STRING: tag(top-1) = (strcmp (svalue(l), svalue(r)) == 0) ? T_NUMBER : T_NIL; break; case T_MARK: return 1; } } nvalue(top-1) = 1; } break; case LTOP: { Object *l = top-2; Object *r = top-1; --top; if (tag(l) == T_NUMBER && tag(r) == T_NUMBER) tag(top-1) = (nvalue(l) < nvalue(r)) ? T_NUMBER : T_NIL; else { if (tostring(l) || tostring(r)) return 1; tag(top-1) = (strcmp (svalue(l), svalue(r)) < 0) ? T_NUMBER : T_NIL; } nvalue(top-1) = 1; } break; case LEOP: { Object *l = top-2; Object *r = top-1; --top; if (tag(l) == T_NUMBER && tag(r) == T_NUMBER) tag(top-1) = (nvalue(l) <= nvalue(r)) ? T_NUMBER : T_NIL; else { if (tostring(l) || tostring(r)) return 1; tag(top-1) = (strcmp (svalue(l), svalue(r)) <= 0) ? T_NUMBER : T_NIL; } nvalue(top-1) = 1; } break; case ADDOP: { Object *l = top-2; Object *r = top-1; if (tonumber(r) || tonumber(l)) return 1; nvalue(l) += nvalue(r); --top; } break; case SUBOP: { Object *l = top-2; Object *r = top-1; if (tonumber(r) || tonumber(l)) return 1; nvalue(l) -= nvalue(r); --top; } break; case MULTOP: { Object *l = top-2; Object *r = top-1; if (tonumber(r) || tonumber(l)) return 1; nvalue(l) *= nvalue(r); --top; } break; case DIVOP: { Object *l = top-2; Object *r = top-1; if (tonumber(r) || tonumber(l)) return 1; nvalue(l) /= nvalue(r); --top; } break; case CONCOP: { Object *l = top-2; Object *r = top-1; if (tostring(r) || tostring(l)) return 1; svalue(l) = lua_createstring (lua_strconc(svalue(l),svalue(r))); if (svalue(l) == NULL) return 1; --top; } break; case MINUSOP: if (tonumber(top-1)) return 1; nvalue(top-1) = - nvalue(top-1); break; case NOTOP: tag(top-1) = tag(top-1) == T_NIL ? T_NUMBER : T_NIL; break; case ONTJMP: { CodeWord code; get_word(code,pc); if (tag(top-1) != T_NIL) pc += code.w; } break; case ONFJMP: { CodeWord code; get_word(code,pc); if (tag(top-1) == T_NIL) pc += code.w; } break; case JMP: { CodeWord code; get_word(code,pc); pc += code.w; } break; case UPJMP: { CodeWord code; get_word(code,pc); pc -= code.w; } break; case IFFJMP: { CodeWord code; get_word(code,pc); top--; if (tag(top) == T_NIL) pc += code.w; } break; case IFFUPJMP: { CodeWord code; get_word(code,pc); top--; if (tag(top) == T_NIL) pc -= code.w; } break; case POP: --top; break; case CALLFUNC: { Byte *newpc; Object *b = top-1; while (tag(b) != T_MARK) b--; if (tag(b-1) == T_FUNCTION) { lua_debugline = 0; /* always reset debug flag */ newpc = bvalue(b-1); bvalue(b-1) = pc; /* store return code */ nvalue(b) = (base-stack); /* store base value */ base = b+1; pc = newpc; if (MAXSTACK-(base-stack) < STACKGAP) { lua_error ("stack overflow"); return 1; } } else if (tag(b-1) == T_CFUNCTION) { int nparam; lua_debugline = 0; /* always reset debug flag */ nvalue(b) = (base-stack); /* store base value */ base = b+1; nparam = top-base; /* number of parameters */ (fvalue(b-1))(); /* call C function */ /* shift returned values */ { int i; int nretval = top - base - nparam; top = base - 2; base = stack + (int) nvalue(base-1); for (i=0; i<nretval; i++) { *top = *(top+nparam+2); ++top; } } } else { lua_reportbug ("call expression not a function"); return 1; } } break; case RETCODE: { int i; int shift = *pc++; int nretval = top - base - shift; top = base - 2; pc = bvalue(base-2); base = stack + (int) nvalue(base-1); for (i=0; i<nretval; i++) { *top = *(top+shift+2); ++top; } } break; case HALT: base = oldbase; return 0; /* success */ case SETFUNCTION: { CodeWord file, func; get_word(file,pc); get_word(func,pc); if (lua_pushfunction (file.w, func.w)) return 1; } break; case SETLINE: { CodeWord code; get_word(code,pc); lua_debugline = code.w; } break; case RESET: lua_popfunction (); break; default: lua_error ("internal error - opcode didn't match"); return 1; } } }