diff options
-rw-r--r-- | lapi.c | 105 | ||||
-rw-r--r-- | lauxlib.c | 48 | ||||
-rw-r--r-- | lauxlib.h | 2 | ||||
-rw-r--r-- | lbaselib.c | 15 | ||||
-rw-r--r-- | lcode.c | 4 | ||||
-rw-r--r-- | ldebug.c | 18 | ||||
-rw-r--r-- | ldo.c | 23 | ||||
-rw-r--r-- | ldo.h | 12 | ||||
-rw-r--r-- | ldump.c | 68 | ||||
-rw-r--r-- | lfunc.c | 8 | ||||
-rw-r--r-- | lgc.c | 416 | ||||
-rw-r--r-- | lgc.h | 58 | ||||
-rw-r--r-- | linit.c | 51 | ||||
-rw-r--r-- | llimits.h | 21 | ||||
-rw-r--r-- | lmathlib.c | 24 | ||||
-rw-r--r-- | lmem.c | 8 | ||||
-rw-r--r-- | lmem.h | 2 | ||||
-rw-r--r-- | lobject.h | 22 | ||||
-rw-r--r-- | lparser.c | 63 | ||||
-rw-r--r-- | lstate.c | 71 | ||||
-rw-r--r-- | lstate.h | 21 | ||||
-rw-r--r-- | lstrlib.c | 1 | ||||
-rw-r--r-- | ltable.c | 80 | ||||
-rw-r--r-- | ltable.h | 14 | ||||
-rw-r--r-- | ltablib.c | 31 | ||||
-rw-r--r-- | ltests.c | 65 | ||||
-rw-r--r-- | ltests.h | 7 | ||||
-rw-r--r-- | ltm.c | 2 | ||||
-rw-r--r-- | ltm.h | 4 | ||||
-rw-r--r-- | lua.c | 6 | ||||
-rw-r--r-- | lua.h | 10 | ||||
-rw-r--r-- | lualib.h | 39 | ||||
-rw-r--r-- | lundump.c | 87 | ||||
-rw-r--r-- | lundump.h | 5 | ||||
-rw-r--r-- | lvm.c | 107 | ||||
-rw-r--r-- | lzio.c | 36 | ||||
-rw-r--r-- | lzio.h | 1 | ||||
-rw-r--r-- | manual/manual.of | 179 | ||||
-rw-r--r-- | testes/all.lua | 2 | ||||
-rw-r--r-- | testes/api.lua | 65 | ||||
-rw-r--r-- | testes/attrib.lua | 2 | ||||
-rw-r--r-- | testes/calls.lua | 27 | ||||
-rw-r--r-- | testes/closure.lua | 19 | ||||
-rw-r--r-- | testes/coroutine.lua | 2 | ||||
-rw-r--r-- | testes/files.lua | 4 | ||||
-rw-r--r-- | testes/main.lua | 6 | ||||
-rw-r--r-- | testes/nextvar.lua | 14 |
47 files changed, 1024 insertions, 851 deletions
@@ -1101,16 +1101,37 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, | |||
1101 | } | 1101 | } |
1102 | 1102 | ||
1103 | 1103 | ||
1104 | /* | ||
1105 | ** Dump a function, calling 'writer' to write its parts. Because the | ||
1106 | ** writer can use the stack in unkown ways, this function should not | ||
1107 | ** push things on the stack, but it must anchor an auxiliary table | ||
1108 | ** used by 'luaU_dump'. To do so, it creates the table, anchors the | ||
1109 | ** function that is on the stack in the table, and substitutes the | ||
1110 | ** table for the function in the stack. | ||
1111 | */ | ||
1112 | |||
1104 | LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) { | 1113 | LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) { |
1105 | int status; | 1114 | int status; |
1115 | StkId fstk; /* pointer to function */ | ||
1106 | TValue *o; | 1116 | TValue *o; |
1107 | lua_lock(L); | 1117 | lua_lock(L); |
1108 | api_checknelems(L, 1); | 1118 | api_checknelems(L, 1); |
1109 | o = s2v(L->top.p - 1); | 1119 | fstk = L->top.p - 1; |
1110 | if (isLfunction(o)) | 1120 | o = s2v(fstk); |
1111 | status = luaU_dump(L, getproto(o), writer, data, strip); | 1121 | if (!isLfunction(o)) |
1112 | else | ||
1113 | status = 1; | 1122 | status = 1; |
1123 | else { | ||
1124 | LClosure *f = clLvalue(o); | ||
1125 | ptrdiff_t fidx = savestack(L, fstk); /* function index */ | ||
1126 | Table *h = luaH_new(L); /* auxiliary table used by 'luaU_dump' */ | ||
1127 | sethvalue2s(L, L->top.p, h); /* anchor it (luaH_set may call GC) */ | ||
1128 | L->top.p++; /* (assume extra slot) */ | ||
1129 | luaH_set(L, h, o, o); /* anchor function into table */ | ||
1130 | setobjs2s(L, fstk, L->top.p - 1); /* move table over function */ | ||
1131 | L->top.p--; /* stack back to initial size */ | ||
1132 | status = luaU_dump(L, f->p, writer, data, strip, h); | ||
1133 | setclLvalue2s(L, restorestack(L, fidx), f); /* put function back */ | ||
1134 | } | ||
1114 | lua_unlock(L); | 1135 | lua_unlock(L); |
1115 | return status; | 1136 | return status; |
1116 | } | 1137 | } |
@@ -1139,7 +1160,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { | |||
1139 | } | 1160 | } |
1140 | case LUA_GCRESTART: { | 1161 | case LUA_GCRESTART: { |
1141 | luaE_setdebt(g, 0); | 1162 | luaE_setdebt(g, 0); |
1142 | g->gcstp = 0; /* (GCSTPGC must be already zero here) */ | 1163 | g->gcstp = 0; /* (bit GCSTPGC must be zero here) */ |
1143 | break; | 1164 | break; |
1144 | } | 1165 | } |
1145 | case LUA_GCCOLLECT: { | 1166 | case LUA_GCCOLLECT: { |
@@ -1148,42 +1169,46 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { | |||
1148 | } | 1169 | } |
1149 | case LUA_GCCOUNT: { | 1170 | case LUA_GCCOUNT: { |
1150 | /* GC values are expressed in Kbytes: #bytes/2^10 */ | 1171 | /* GC values are expressed in Kbytes: #bytes/2^10 */ |
1151 | res = cast_int(gettotalbytes(g) >> 10); | 1172 | res = cast_int(g->totalbytes >> 10); |
1152 | break; | 1173 | break; |
1153 | } | 1174 | } |
1154 | case LUA_GCCOUNTB: { | 1175 | case LUA_GCCOUNTB: { |
1155 | res = cast_int(gettotalbytes(g) & 0x3ff); | 1176 | res = cast_int(g->totalbytes & 0x3ff); |
1156 | break; | 1177 | break; |
1157 | } | 1178 | } |
1158 | case LUA_GCSTEP: { | 1179 | case LUA_GCSTEP: { |
1159 | int data = va_arg(argp, int); | 1180 | int todo = va_arg(argp, int); /* work to be done */ |
1160 | l_mem debt = 1; /* =1 to signal that it did an actual step */ | 1181 | int didsomething = 0; |
1161 | lu_byte oldstp = g->gcstp; | 1182 | lu_byte oldstp = g->gcstp; |
1162 | g->gcstp = 0; /* allow GC to run (GCSTPGC must be zero here) */ | 1183 | g->gcstp = 0; /* allow GC to run (bit GCSTPGC must be zero here) */ |
1163 | if (data == 0) { | 1184 | if (todo == 0) |
1164 | luaE_setdebt(g, 0); /* do a basic step */ | 1185 | todo = 1 << g->gcstepsize; /* standard step size */ |
1165 | luaC_step(L); | 1186 | while (todo >= g->GCdebt) { /* enough to run a step? */ |
1166 | } | 1187 | todo -= g->GCdebt; /* decrement 'todo' */ |
1167 | else { /* add 'data' to total debt */ | 1188 | luaC_step(L); /* run one basic step */ |
1168 | debt = cast(l_mem, data) * 1024 + g->GCdebt; | 1189 | didsomething = 1; |
1169 | luaE_setdebt(g, debt); | 1190 | if (g->gckind == KGC_GEN) /* minor collections? */ |
1170 | luaC_checkGC(L); | 1191 | todo = 0; /* doesn't make sense to repeat in this case */ |
1192 | else if (g->gcstate == GCSpause) | ||
1193 | break; /* don't run more than one cycle */ | ||
1171 | } | 1194 | } |
1195 | /* remove remaining 'todo' from total debt */ | ||
1196 | luaE_setdebt(g, g->GCdebt - todo); | ||
1172 | g->gcstp = oldstp; /* restore previous state */ | 1197 | g->gcstp = oldstp; /* restore previous state */ |
1173 | if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */ | 1198 | if (didsomething && g->gcstate == GCSpause) /* end of cycle? */ |
1174 | res = 1; /* signal it */ | 1199 | res = 1; /* signal it */ |
1175 | break; | 1200 | break; |
1176 | } | 1201 | } |
1177 | case LUA_GCSETPAUSE: { | 1202 | case LUA_GCSETPAUSE: { |
1178 | int data = va_arg(argp, int); | 1203 | unsigned int data = va_arg(argp, unsigned int); |
1179 | res = getgcparam(g->gcpause); | 1204 | res = applygcparam(g, gcpause, 100); |
1180 | setgcparam(g->gcpause, data); | 1205 | setgcparam(g, gcpause, data); |
1181 | break; | 1206 | break; |
1182 | } | 1207 | } |
1183 | case LUA_GCSETSTEPMUL: { | 1208 | case LUA_GCSETSTEPMUL: { |
1184 | int data = va_arg(argp, int); | 1209 | unsigned int data = va_arg(argp, unsigned int); |
1185 | res = getgcparam(g->gcstepmul); | 1210 | res = applygcparam(g, gcstepmul, 100); |
1186 | setgcparam(g->gcstepmul, data); | 1211 | setgcparam(g, gcstepmul, data); |
1187 | break; | 1212 | break; |
1188 | } | 1213 | } |
1189 | case LUA_GCISRUNNING: { | 1214 | case LUA_GCISRUNNING: { |
@@ -1191,27 +1216,28 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { | |||
1191 | break; | 1216 | break; |
1192 | } | 1217 | } |
1193 | case LUA_GCGEN: { | 1218 | case LUA_GCGEN: { |
1194 | int minormul = va_arg(argp, int); | 1219 | unsigned int minormul = va_arg(argp, unsigned int); |
1195 | int majormul = va_arg(argp, int); | 1220 | unsigned int majormul = va_arg(argp, unsigned int); |
1196 | res = isdecGCmodegen(g) ? LUA_GCGEN : LUA_GCINC; | 1221 | res = (g->gckind == KGC_INC) ? LUA_GCINC : LUA_GCGEN; |
1197 | if (minormul != 0) | 1222 | if (minormul != 0) |
1198 | g->genminormul = minormul; | 1223 | setgcparam(g, genminormul, minormul); |
1199 | if (majormul != 0) | 1224 | if (majormul != 0) |
1200 | setgcparam(g->genmajormul, majormul); | 1225 | setgcparam(g, genmajormul, majormul); |
1201 | luaC_changemode(L, KGC_GEN); | 1226 | luaC_changemode(L, KGC_GEN); |
1202 | break; | 1227 | break; |
1203 | } | 1228 | } |
1204 | case LUA_GCINC: { | 1229 | case LUA_GCINC: { |
1205 | int pause = va_arg(argp, int); | 1230 | unsigned int pause = va_arg(argp, unsigned int); |
1206 | int stepmul = va_arg(argp, int); | 1231 | unsigned int stepmul = va_arg(argp, unsigned int); |
1207 | int stepsize = va_arg(argp, int); | 1232 | unsigned int stepsize = va_arg(argp, unsigned int); |
1208 | res = isdecGCmodegen(g) ? LUA_GCGEN : LUA_GCINC; | 1233 | res = (g->gckind == KGC_INC) ? LUA_GCINC : LUA_GCGEN; |
1209 | if (pause != 0) | 1234 | if (pause != 0) |
1210 | setgcparam(g->gcpause, pause); | 1235 | setgcparam(g, gcpause, pause); |
1211 | if (stepmul != 0) | 1236 | if (stepmul != 0) |
1212 | setgcparam(g->gcstepmul, stepmul); | 1237 | setgcparam(g, gcstepmul, stepmul); |
1213 | if (stepsize != 0) | 1238 | if (stepsize != 0) |
1214 | g->gcstepsize = stepsize; | 1239 | g->gcstepsize = (stepsize <= log2maxs(l_obj)) ? stepsize |
1240 | : log2maxs(l_obj); | ||
1215 | luaC_changemode(L, KGC_INC); | 1241 | luaC_changemode(L, KGC_INC); |
1216 | break; | 1242 | break; |
1217 | } | 1243 | } |
@@ -1279,13 +1305,14 @@ LUA_API void lua_toclose (lua_State *L, int idx) { | |||
1279 | LUA_API void lua_concat (lua_State *L, int n) { | 1305 | LUA_API void lua_concat (lua_State *L, int n) { |
1280 | lua_lock(L); | 1306 | lua_lock(L); |
1281 | api_checknelems(L, n); | 1307 | api_checknelems(L, n); |
1282 | if (n > 0) | 1308 | if (n > 0) { |
1283 | luaV_concat(L, n); | 1309 | luaV_concat(L, n); |
1310 | luaC_checkGC(L); | ||
1311 | } | ||
1284 | else { /* nothing to concatenate */ | 1312 | else { /* nothing to concatenate */ |
1285 | setsvalue2s(L, L->top.p, luaS_newlstr(L, "", 0)); /* push empty string */ | 1313 | setsvalue2s(L, L->top.p, luaS_newlstr(L, "", 0)); /* push empty string */ |
1286 | api_incr_top(L); | 1314 | api_incr_top(L); |
1287 | } | 1315 | } |
1288 | luaC_checkGC(L); | ||
1289 | lua_unlock(L); | 1316 | lua_unlock(L); |
1290 | } | 1317 | } |
1291 | 1318 | ||
@@ -1091,8 +1091,54 @@ static void warnfon (void *ud, const char *message, int tocont) { | |||
1091 | } | 1091 | } |
1092 | 1092 | ||
1093 | 1093 | ||
1094 | |||
1095 | /* | ||
1096 | ** A function to compute an unsigned int with some level of | ||
1097 | ** randomness. Rely on Address Space Layout Randomization (if present) | ||
1098 | ** and the current time. | ||
1099 | */ | ||
1100 | #if !defined(luai_makeseed) | ||
1101 | |||
1102 | #include <time.h> | ||
1103 | |||
1104 | |||
1105 | /* | ||
1106 | ** Size of 'e' measured in number of 'unsigned int's. (In the weird | ||
1107 | ** case that the division truncates, we just lose some part of the | ||
1108 | ** value, no big deal.) | ||
1109 | */ | ||
1110 | #define sof(e) (sizeof(e) / sizeof(unsigned int)) | ||
1111 | |||
1112 | |||
1113 | #define addbuff(b,v) \ | ||
1114 | (memcpy(b, &(v), sof(v) * sizeof(unsigned int)), b += sof(v)) | ||
1115 | |||
1116 | |||
1117 | static unsigned int luai_makeseed (void) { | ||
1118 | unsigned int buff[sof(void*) + sof(time_t)]; | ||
1119 | unsigned int res; | ||
1120 | unsigned int *b = buff; | ||
1121 | time_t t = time(NULL); | ||
1122 | void *h = buff; | ||
1123 | addbuff(b, h); /* local variable's address */ | ||
1124 | addbuff(b, t); /* time */ | ||
1125 | res = buff[0]; | ||
1126 | for (b = buff + 1; b < buff + sof(buff); b++) | ||
1127 | res ^= (res >> 3) + (res << 7) + *b; | ||
1128 | return res; | ||
1129 | } | ||
1130 | |||
1131 | #endif | ||
1132 | |||
1133 | |||
1134 | LUALIB_API unsigned int luaL_makeseed (lua_State *L) { | ||
1135 | (void)L; /* unused */ | ||
1136 | return luai_makeseed(); | ||
1137 | } | ||
1138 | |||
1139 | |||
1094 | LUALIB_API lua_State *luaL_newstate (void) { | 1140 | LUALIB_API lua_State *luaL_newstate (void) { |
1095 | lua_State *L = lua_newstate(l_alloc, NULL); | 1141 | lua_State *L = lua_newstate(l_alloc, NULL, luai_makeseed()); |
1096 | if (l_likely(L)) { | 1142 | if (l_likely(L)) { |
1097 | lua_atpanic(L, &panic); | 1143 | lua_atpanic(L, &panic); |
1098 | lua_setwarnf(L, warnfoff, L); /* default is warnings off */ | 1144 | lua_setwarnf(L, warnfoff, L); /* default is warnings off */ |
@@ -100,6 +100,8 @@ LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); | |||
100 | 100 | ||
101 | LUALIB_API lua_State *(luaL_newstate) (void); | 101 | LUALIB_API lua_State *(luaL_newstate) (void); |
102 | 102 | ||
103 | LUALIB_API unsigned int luaL_makeseed (lua_State *L); | ||
104 | |||
103 | LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx); | 105 | LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx); |
104 | 106 | ||
105 | LUALIB_API void (luaL_addgsub) (luaL_Buffer *b, const char *s, | 107 | LUALIB_API void (luaL_addgsub) (luaL_Buffer *b, const char *s, |
@@ -337,9 +337,20 @@ static int load_aux (lua_State *L, int status, int envidx) { | |||
337 | } | 337 | } |
338 | 338 | ||
339 | 339 | ||
340 | static const char *getmode (lua_State *L, int idx) { | ||
341 | const char *mode = luaL_optstring(L, idx, "bt"); | ||
342 | int i = 0; | ||
343 | if (mode[i] == 'b') i++; | ||
344 | if (mode[i] == 't') i++; | ||
345 | if (mode[i] != '\0') | ||
346 | luaL_argerror(L, idx, "invalid mode"); | ||
347 | return mode; | ||
348 | } | ||
349 | |||
350 | |||
340 | static int luaB_loadfile (lua_State *L) { | 351 | static int luaB_loadfile (lua_State *L) { |
341 | const char *fname = luaL_optstring(L, 1, NULL); | 352 | const char *fname = luaL_optstring(L, 1, NULL); |
342 | const char *mode = luaL_optstring(L, 2, NULL); | 353 | const char *mode = getmode(L, 2); |
343 | int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */ | 354 | int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */ |
344 | int status = luaL_loadfilex(L, fname, mode); | 355 | int status = luaL_loadfilex(L, fname, mode); |
345 | return load_aux(L, status, env); | 356 | return load_aux(L, status, env); |
@@ -388,7 +399,7 @@ static int luaB_load (lua_State *L) { | |||
388 | int status; | 399 | int status; |
389 | size_t l; | 400 | size_t l; |
390 | const char *s = lua_tolstring(L, 1, &l); | 401 | const char *s = lua_tolstring(L, 1, &l); |
391 | const char *mode = luaL_optstring(L, 3, "bt"); | 402 | const char *mode = getmode(L, 3); |
392 | int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */ | 403 | int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */ |
393 | if (s != NULL) { /* loading a string? */ | 404 | if (s != NULL) { /* loading a string? */ |
394 | const char *chunkname = luaL_optstring(L, 2, s); | 405 | const char *chunkname = luaL_optstring(L, 2, s); |
@@ -1849,7 +1849,7 @@ void luaK_finish (FuncState *fs) { | |||
1849 | lua_assert(i == 0 || isOT(*(pc - 1)) == isIT(*pc)); | 1849 | lua_assert(i == 0 || isOT(*(pc - 1)) == isIT(*pc)); |
1850 | switch (GET_OPCODE(*pc)) { | 1850 | switch (GET_OPCODE(*pc)) { |
1851 | case OP_RETURN0: case OP_RETURN1: { | 1851 | case OP_RETURN0: case OP_RETURN1: { |
1852 | if (!(fs->needclose || p->is_vararg)) | 1852 | if (!(fs->needclose || (p->flag & PF_ISVARARG))) |
1853 | break; /* no extra work */ | 1853 | break; /* no extra work */ |
1854 | /* else use OP_RETURN to do the extra work */ | 1854 | /* else use OP_RETURN to do the extra work */ |
1855 | SET_OPCODE(*pc, OP_RETURN); | 1855 | SET_OPCODE(*pc, OP_RETURN); |
@@ -1857,7 +1857,7 @@ void luaK_finish (FuncState *fs) { | |||
1857 | case OP_RETURN: case OP_TAILCALL: { | 1857 | case OP_RETURN: case OP_TAILCALL: { |
1858 | if (fs->needclose) | 1858 | if (fs->needclose) |
1859 | SETARG_k(*pc, 1); /* signal that it needs to close */ | 1859 | SETARG_k(*pc, 1); /* signal that it needs to close */ |
1860 | if (p->is_vararg) | 1860 | if (p->flag & PF_ISVARARG) |
1861 | SETARG_C(*pc, p->numparams + 1); /* signal that it is vararg */ | 1861 | SETARG_C(*pc, p->numparams + 1); /* signal that it is vararg */ |
1862 | break; | 1862 | break; |
1863 | } | 1863 | } |
@@ -182,7 +182,7 @@ static const char *upvalname (const Proto *p, int uv) { | |||
182 | 182 | ||
183 | 183 | ||
184 | static const char *findvararg (CallInfo *ci, int n, StkId *pos) { | 184 | static const char *findvararg (CallInfo *ci, int n, StkId *pos) { |
185 | if (clLvalue(s2v(ci->func.p))->p->is_vararg) { | 185 | if (clLvalue(s2v(ci->func.p))->p->flag & PF_ISVARARG) { |
186 | int nextra = ci->u.l.nextraargs; | 186 | int nextra = ci->u.l.nextraargs; |
187 | if (n >= -nextra) { /* 'n' is negative */ | 187 | if (n >= -nextra) { /* 'n' is negative */ |
188 | *pos = ci->func.p - nextra - (n + 1); | 188 | *pos = ci->func.p - nextra - (n + 1); |
@@ -264,8 +264,7 @@ static void funcinfo (lua_Debug *ar, Closure *cl) { | |||
264 | else { | 264 | else { |
265 | const Proto *p = cl->l.p; | 265 | const Proto *p = cl->l.p; |
266 | if (p->source) { | 266 | if (p->source) { |
267 | ar->source = getstr(p->source); | 267 | ar->source = getlstr(p->source, ar->srclen); |
268 | ar->srclen = tsslen(p->source); | ||
269 | } | 268 | } |
270 | else { | 269 | else { |
271 | ar->source = "=?"; | 270 | ar->source = "=?"; |
@@ -301,7 +300,7 @@ static void collectvalidlines (lua_State *L, Closure *f) { | |||
301 | sethvalue2s(L, L->top.p, t); /* push it on stack */ | 300 | sethvalue2s(L, L->top.p, t); /* push it on stack */ |
302 | api_incr_top(L); | 301 | api_incr_top(L); |
303 | setbtvalue(&v); /* boolean 'true' to be the value of all indices */ | 302 | setbtvalue(&v); /* boolean 'true' to be the value of all indices */ |
304 | if (!p->is_vararg) /* regular function? */ | 303 | if (!(p->flag & PF_ISVARARG)) /* regular function? */ |
305 | i = 0; /* consider all instructions */ | 304 | i = 0; /* consider all instructions */ |
306 | else { /* vararg function */ | 305 | else { /* vararg function */ |
307 | lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP); | 306 | lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP); |
@@ -344,7 +343,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, | |||
344 | ar->nparams = 0; | 343 | ar->nparams = 0; |
345 | } | 344 | } |
346 | else { | 345 | else { |
347 | ar->isvararg = f->l.p->is_vararg; | 346 | ar->isvararg = f->l.p->flag & PF_ISVARARG; |
348 | ar->nparams = f->l.p->numparams; | 347 | ar->nparams = f->l.p->numparams; |
349 | } | 348 | } |
350 | break; | 349 | break; |
@@ -812,8 +811,11 @@ l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { | |||
812 | const char *luaG_addinfo (lua_State *L, const char *msg, TString *src, | 811 | const char *luaG_addinfo (lua_State *L, const char *msg, TString *src, |
813 | int line) { | 812 | int line) { |
814 | char buff[LUA_IDSIZE]; | 813 | char buff[LUA_IDSIZE]; |
815 | if (src) | 814 | if (src) { |
816 | luaO_chunkid(buff, getstr(src), tsslen(src)); | 815 | size_t idlen; |
816 | const char *id = getlstr(src, idlen); | ||
817 | luaO_chunkid(buff, id, idlen); | ||
818 | } | ||
817 | else { /* no source available; use "?" instead */ | 819 | else { /* no source available; use "?" instead */ |
818 | buff[0] = '?'; buff[1] = '\0'; | 820 | buff[0] = '?'; buff[1] = '\0'; |
819 | } | 821 | } |
@@ -893,7 +895,7 @@ int luaG_tracecall (lua_State *L) { | |||
893 | Proto *p = ci_func(ci)->p; | 895 | Proto *p = ci_func(ci)->p; |
894 | ci->u.l.trap = 1; /* ensure hooks will be checked */ | 896 | ci->u.l.trap = 1; /* ensure hooks will be checked */ |
895 | if (ci->u.l.savedpc == p->code) { /* first instruction (not resuming)? */ | 897 | if (ci->u.l.savedpc == p->code) { /* first instruction (not resuming)? */ |
896 | if (p->is_vararg) | 898 | if (p->flag & PF_ISVARARG) |
897 | return 0; /* hooks will start at VARARGPREP instruction */ | 899 | return 0; /* hooks will start at VARARGPREP instruction */ |
898 | else if (!(ci->callstatus & CIST_HOOKYIELD)) /* not yieded? */ | 900 | else if (!(ci->callstatus & CIST_HOOKYIELD)) /* not yieded? */ |
899 | luaD_hookcall(L, ci); /* check 'call' hook */ | 901 | luaD_hookcall(L, ci); /* check 'call' hook */ |
@@ -391,7 +391,7 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) { | |||
391 | int ftransfer; | 391 | int ftransfer; |
392 | if (isLua(ci)) { | 392 | if (isLua(ci)) { |
393 | Proto *p = ci_func(ci)->p; | 393 | Proto *p = ci_func(ci)->p; |
394 | if (p->is_vararg) | 394 | if (p->flag & PF_ISVARARG) |
395 | delta = ci->u.l.nextraargs + p->numparams + 1; | 395 | delta = ci->u.l.nextraargs + p->numparams + 1; |
396 | } | 396 | } |
397 | ci->func.p += delta; /* if vararg, back to virtual 'func' */ | 397 | ci->func.p += delta; /* if vararg, back to virtual 'func' */ |
@@ -412,7 +412,7 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) { | |||
412 | static StkId tryfuncTM (lua_State *L, StkId func) { | 412 | static StkId tryfuncTM (lua_State *L, StkId func) { |
413 | const TValue *tm; | 413 | const TValue *tm; |
414 | StkId p; | 414 | StkId p; |
415 | checkstackGCp(L, 1, func); /* space for metamethod */ | 415 | checkstackp(L, 1, func); /* space for metamethod */ |
416 | tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); /* (after previous GC) */ | 416 | tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); /* (after previous GC) */ |
417 | if (l_unlikely(ttisnil(tm))) | 417 | if (l_unlikely(ttisnil(tm))) |
418 | luaG_callerror(L, s2v(func)); /* nothing to call */ | 418 | luaG_callerror(L, s2v(func)); /* nothing to call */ |
@@ -517,7 +517,7 @@ l_sinline int precallC (lua_State *L, StkId func, int nresults, | |||
517 | lua_CFunction f) { | 517 | lua_CFunction f) { |
518 | int n; /* number of returns */ | 518 | int n; /* number of returns */ |
519 | CallInfo *ci; | 519 | CallInfo *ci; |
520 | checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ | 520 | checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ |
521 | L->ci = ci = prepCallInfo(L, func, nresults, CIST_C, | 521 | L->ci = ci = prepCallInfo(L, func, nresults, CIST_C, |
522 | L->top.p + LUA_MINSTACK); | 522 | L->top.p + LUA_MINSTACK); |
523 | lua_assert(ci->top.p <= L->stack_last.p); | 523 | lua_assert(ci->top.p <= L->stack_last.p); |
@@ -553,7 +553,7 @@ int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, | |||
553 | int fsize = p->maxstacksize; /* frame size */ | 553 | int fsize = p->maxstacksize; /* frame size */ |
554 | int nfixparams = p->numparams; | 554 | int nfixparams = p->numparams; |
555 | int i; | 555 | int i; |
556 | checkstackGCp(L, fsize - delta, func); | 556 | checkstackp(L, fsize - delta, func); |
557 | ci->func.p -= delta; /* restore 'func' (if vararg) */ | 557 | ci->func.p -= delta; /* restore 'func' (if vararg) */ |
558 | for (i = 0; i < narg1; i++) /* move down function and arguments */ | 558 | for (i = 0; i < narg1; i++) /* move down function and arguments */ |
559 | setobjs2s(L, ci->func.p + i, func + i); | 559 | setobjs2s(L, ci->func.p + i, func + i); |
@@ -600,7 +600,7 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { | |||
600 | int narg = cast_int(L->top.p - func) - 1; /* number of real arguments */ | 600 | int narg = cast_int(L->top.p - func) - 1; /* number of real arguments */ |
601 | int nfixparams = p->numparams; | 601 | int nfixparams = p->numparams; |
602 | int fsize = p->maxstacksize; /* frame size */ | 602 | int fsize = p->maxstacksize; /* frame size */ |
603 | checkstackGCp(L, fsize, func); | 603 | checkstackp(L, fsize, func); |
604 | L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize); | 604 | L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize); |
605 | ci->u.l.savedpc = p->code; /* starting point */ | 605 | ci->u.l.savedpc = p->code; /* starting point */ |
606 | for (; narg < nfixparams; narg++) | 606 | for (; narg < nfixparams; narg++) |
@@ -977,7 +977,7 @@ struct SParser { /* data to 'f_parser' */ | |||
977 | 977 | ||
978 | 978 | ||
979 | static void checkmode (lua_State *L, const char *mode, const char *x) { | 979 | static void checkmode (lua_State *L, const char *mode, const char *x) { |
980 | if (mode && strchr(mode, x[0]) == NULL) { | 980 | if (strchr(mode, x[0]) == NULL) { |
981 | luaO_pushfstring(L, | 981 | luaO_pushfstring(L, |
982 | "attempt to load a %s chunk (mode is '%s')", x, mode); | 982 | "attempt to load a %s chunk (mode is '%s')", x, mode); |
983 | luaD_throw(L, LUA_ERRSYNTAX); | 983 | luaD_throw(L, LUA_ERRSYNTAX); |
@@ -988,13 +988,18 @@ static void checkmode (lua_State *L, const char *mode, const char *x) { | |||
988 | static void f_parser (lua_State *L, void *ud) { | 988 | static void f_parser (lua_State *L, void *ud) { |
989 | LClosure *cl; | 989 | LClosure *cl; |
990 | struct SParser *p = cast(struct SParser *, ud); | 990 | struct SParser *p = cast(struct SParser *, ud); |
991 | const char *mode = p->mode ? p->mode : "bt"; | ||
991 | int c = zgetc(p->z); /* read first character */ | 992 | int c = zgetc(p->z); /* read first character */ |
992 | if (c == LUA_SIGNATURE[0]) { | 993 | if (c == LUA_SIGNATURE[0]) { |
993 | checkmode(L, p->mode, "binary"); | 994 | int fixed = 0; |
994 | cl = luaU_undump(L, p->z, p->name); | 995 | if (strchr(mode, 'B') != NULL) |
996 | fixed = 1; | ||
997 | else | ||
998 | checkmode(L, mode, "binary"); | ||
999 | cl = luaU_undump(L, p->z, p->name, fixed); | ||
995 | } | 1000 | } |
996 | else { | 1001 | else { |
997 | checkmode(L, p->mode, "text"); | 1002 | checkmode(L, mode, "text"); |
998 | cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); | 1003 | cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); |
999 | } | 1004 | } |
1000 | lua_assert(cl->nupvalues == cl->p->sizeupvalues); | 1005 | lua_assert(cl->nupvalues == cl->p->sizeupvalues); |
@@ -44,18 +44,6 @@ | |||
44 | p = restorestack(L, t__)) /* 'pos' part: restore 'p' */ | 44 | p = restorestack(L, t__)) /* 'pos' part: restore 'p' */ |
45 | 45 | ||
46 | 46 | ||
47 | /* macro to check stack size and GC, preserving 'p' */ | ||
48 | #define checkstackGCp(L,n,p) \ | ||
49 | luaD_checkstackaux(L, n, \ | ||
50 | ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \ | ||
51 | luaC_checkGC(L), /* stack grow uses memory */ \ | ||
52 | p = restorestack(L, t__)) /* 'pos' part: restore 'p' */ | ||
53 | |||
54 | |||
55 | /* macro to check stack size and GC */ | ||
56 | #define checkstackGC(L,fsize) \ | ||
57 | luaD_checkstackaux(L, (fsize), luaC_checkGC(L), (void)0) | ||
58 | |||
59 | 47 | ||
60 | /* type of protected functions, to be ran by 'runprotected' */ | 48 | /* type of protected functions, to be ran by 'runprotected' */ |
61 | typedef void (*Pfunc) (lua_State *L, void *ud); | 49 | typedef void (*Pfunc) (lua_State *L, void *ud); |
@@ -15,8 +15,10 @@ | |||
15 | 15 | ||
16 | #include "lua.h" | 16 | #include "lua.h" |
17 | 17 | ||
18 | #include "lgc.h" | ||
18 | #include "lobject.h" | 19 | #include "lobject.h" |
19 | #include "lstate.h" | 20 | #include "lstate.h" |
21 | #include "ltable.h" | ||
20 | #include "lundump.h" | 22 | #include "lundump.h" |
21 | 23 | ||
22 | 24 | ||
@@ -24,8 +26,11 @@ typedef struct { | |||
24 | lua_State *L; | 26 | lua_State *L; |
25 | lua_Writer writer; | 27 | lua_Writer writer; |
26 | void *data; | 28 | void *data; |
29 | lu_mem offset; /* current position relative to beginning of dump */ | ||
27 | int strip; | 30 | int strip; |
28 | int status; | 31 | int status; |
32 | Table *h; /* table to track saved strings */ | ||
33 | lua_Integer nstr; /* counter to number saved strings */ | ||
29 | } DumpState; | 34 | } DumpState; |
30 | 35 | ||
31 | 36 | ||
@@ -43,6 +48,17 @@ static void dumpBlock (DumpState *D, const void *b, size_t size) { | |||
43 | lua_unlock(D->L); | 48 | lua_unlock(D->L); |
44 | D->status = (*D->writer)(D->L, b, size, D->data); | 49 | D->status = (*D->writer)(D->L, b, size, D->data); |
45 | lua_lock(D->L); | 50 | lua_lock(D->L); |
51 | D->offset += size; | ||
52 | } | ||
53 | } | ||
54 | |||
55 | |||
56 | static void dumpAlign (DumpState *D, int align) { | ||
57 | int padding = align - (D->offset % align); | ||
58 | if (padding < align) { /* apd == align means no padding */ | ||
59 | static lua_Integer paddingContent = 0; | ||
60 | dumpBlock(D, &paddingContent, padding); | ||
61 | lua_assert(D->offset % align == 0); | ||
46 | } | 62 | } |
47 | } | 63 | } |
48 | 64 | ||
@@ -89,25 +105,46 @@ static void dumpInteger (DumpState *D, lua_Integer x) { | |||
89 | } | 105 | } |
90 | 106 | ||
91 | 107 | ||
92 | static void dumpString (DumpState *D, const TString *s) { | 108 | /* |
93 | if (s == NULL) | 109 | ** Dump a String. First dump its "size": size==0 means NULL; |
110 | ** size==1 is followed by an index and means "reuse saved string with | ||
111 | ** that index"; size>=2 is followed by the string contents with real | ||
112 | ** size==size-2 and means that string, which will be saved with | ||
113 | ** the next available index. | ||
114 | */ | ||
115 | static void dumpString (DumpState *D, TString *ts) { | ||
116 | if (ts == NULL) | ||
94 | dumpSize(D, 0); | 117 | dumpSize(D, 0); |
95 | else { | 118 | else { |
96 | size_t size = tsslen(s); | 119 | const TValue *idx = luaH_getstr(D->h, ts); |
97 | const char *str = getstr(s); | 120 | if (ttisinteger(idx)) { /* string already saved? */ |
98 | dumpSize(D, size + 1); | 121 | dumpSize(D, 1); /* reuse a saved string */ |
99 | dumpVector(D, str, size); | 122 | dumpInt(D, ivalue(idx)); /* index of saved string */ |
123 | } | ||
124 | else { /* must write and save the string */ | ||
125 | TValue key, value; /* to save the string in the hash */ | ||
126 | size_t size; | ||
127 | const char *s = getlstr(ts, size); | ||
128 | dumpSize(D, size + 2); | ||
129 | dumpVector(D, s, size); | ||
130 | D->nstr++; /* one more saved string */ | ||
131 | setsvalue(D->L, &key, ts); /* the string is the key */ | ||
132 | setivalue(&value, D->nstr); /* its index is the value */ | ||
133 | luaH_finishset(D->L, D->h, &key, idx, &value); /* h[ts] = nstr */ | ||
134 | /* integer value does not need barrier */ | ||
135 | } | ||
100 | } | 136 | } |
101 | } | 137 | } |
102 | 138 | ||
103 | 139 | ||
104 | static void dumpCode (DumpState *D, const Proto *f) { | 140 | static void dumpCode (DumpState *D, const Proto *f) { |
105 | dumpInt(D, f->sizecode); | 141 | dumpInt(D, f->sizecode); |
142 | dumpAlign(D, sizeof(f->code[0])); | ||
106 | dumpVector(D, f->code, f->sizecode); | 143 | dumpVector(D, f->code, f->sizecode); |
107 | } | 144 | } |
108 | 145 | ||
109 | 146 | ||
110 | static void dumpFunction(DumpState *D, const Proto *f, TString *psource); | 147 | static void dumpFunction(DumpState *D, const Proto *f); |
111 | 148 | ||
112 | static void dumpConstants (DumpState *D, const Proto *f) { | 149 | static void dumpConstants (DumpState *D, const Proto *f) { |
113 | int i; | 150 | int i; |
@@ -140,7 +177,7 @@ static void dumpProtos (DumpState *D, const Proto *f) { | |||
140 | int n = f->sizep; | 177 | int n = f->sizep; |
141 | dumpInt(D, n); | 178 | dumpInt(D, n); |
142 | for (i = 0; i < n; i++) | 179 | for (i = 0; i < n; i++) |
143 | dumpFunction(D, f->p[i], f->source); | 180 | dumpFunction(D, f->p[i]); |
144 | } | 181 | } |
145 | 182 | ||
146 | 183 | ||
@@ -180,15 +217,15 @@ static void dumpDebug (DumpState *D, const Proto *f) { | |||
180 | } | 217 | } |
181 | 218 | ||
182 | 219 | ||
183 | static void dumpFunction (DumpState *D, const Proto *f, TString *psource) { | 220 | static void dumpFunction (DumpState *D, const Proto *f) { |
184 | if (D->strip || f->source == psource) | 221 | if (D->strip) |
185 | dumpString(D, NULL); /* no debug info or same source as its parent */ | 222 | dumpString(D, NULL); /* no debug info */ |
186 | else | 223 | else |
187 | dumpString(D, f->source); | 224 | dumpString(D, f->source); |
188 | dumpInt(D, f->linedefined); | 225 | dumpInt(D, f->linedefined); |
189 | dumpInt(D, f->lastlinedefined); | 226 | dumpInt(D, f->lastlinedefined); |
190 | dumpByte(D, f->numparams); | 227 | dumpByte(D, f->numparams); |
191 | dumpByte(D, f->is_vararg); | 228 | dumpByte(D, f->flag); |
192 | dumpByte(D, f->maxstacksize); | 229 | dumpByte(D, f->maxstacksize); |
193 | dumpCode(D, f); | 230 | dumpCode(D, f); |
194 | dumpConstants(D, f); | 231 | dumpConstants(D, f); |
@@ -215,16 +252,19 @@ static void dumpHeader (DumpState *D) { | |||
215 | ** dump Lua function as precompiled chunk | 252 | ** dump Lua function as precompiled chunk |
216 | */ | 253 | */ |
217 | int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data, | 254 | int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data, |
218 | int strip) { | 255 | int strip, Table *h) { |
219 | DumpState D; | 256 | DumpState D; |
220 | D.L = L; | 257 | D.L = L; |
221 | D.writer = w; | 258 | D.writer = w; |
259 | D.offset = 0; | ||
222 | D.data = data; | 260 | D.data = data; |
223 | D.strip = strip; | 261 | D.strip = strip; |
224 | D.status = 0; | 262 | D.status = 0; |
263 | D.h = h; | ||
264 | D.nstr = 0; | ||
225 | dumpHeader(&D); | 265 | dumpHeader(&D); |
226 | dumpByte(&D, f->sizeupvalues); | 266 | dumpByte(&D, f->sizeupvalues); |
227 | dumpFunction(&D, f, NULL); | 267 | dumpFunction(&D, f); |
228 | return D.status; | 268 | return D.status; |
229 | } | 269 | } |
230 | 270 | ||
@@ -253,7 +253,7 @@ Proto *luaF_newproto (lua_State *L) { | |||
253 | f->upvalues = NULL; | 253 | f->upvalues = NULL; |
254 | f->sizeupvalues = 0; | 254 | f->sizeupvalues = 0; |
255 | f->numparams = 0; | 255 | f->numparams = 0; |
256 | f->is_vararg = 0; | 256 | f->flag = 0; |
257 | f->maxstacksize = 0; | 257 | f->maxstacksize = 0; |
258 | f->locvars = NULL; | 258 | f->locvars = NULL; |
259 | f->sizelocvars = 0; | 259 | f->sizelocvars = 0; |
@@ -265,10 +265,12 @@ Proto *luaF_newproto (lua_State *L) { | |||
265 | 265 | ||
266 | 266 | ||
267 | void luaF_freeproto (lua_State *L, Proto *f) { | 267 | void luaF_freeproto (lua_State *L, Proto *f) { |
268 | luaM_freearray(L, f->code, f->sizecode); | 268 | if (!(f->flag & PF_FIXED)) { |
269 | luaM_freearray(L, f->code, f->sizecode); | ||
270 | luaM_freearray(L, f->lineinfo, f->sizelineinfo); | ||
271 | } | ||
269 | luaM_freearray(L, f->p, f->sizep); | 272 | luaM_freearray(L, f->p, f->sizep); |
270 | luaM_freearray(L, f->k, f->sizek); | 273 | luaM_freearray(L, f->k, f->sizek); |
271 | luaM_freearray(L, f->lineinfo, f->sizelineinfo); | ||
272 | luaM_freearray(L, f->abslineinfo, f->sizeabslineinfo); | 274 | luaM_freearray(L, f->abslineinfo, f->sizeabslineinfo); |
273 | luaM_freearray(L, f->locvars, f->sizelocvars); | 275 | luaM_freearray(L, f->locvars, f->sizelocvars); |
274 | luaM_freearray(L, f->upvalues, f->sizeupvalues); | 276 | luaM_freearray(L, f->upvalues, f->sizeupvalues); |
@@ -9,7 +9,6 @@ | |||
9 | 9 | ||
10 | #include "lprefix.h" | 10 | #include "lprefix.h" |
11 | 11 | ||
12 | #include <stdio.h> | ||
13 | #include <string.h> | 12 | #include <string.h> |
14 | 13 | ||
15 | 14 | ||
@@ -19,6 +18,7 @@ | |||
19 | #include "ldo.h" | 18 | #include "ldo.h" |
20 | #include "lfunc.h" | 19 | #include "lfunc.h" |
21 | #include "lgc.h" | 20 | #include "lgc.h" |
21 | #include "llex.h" | ||
22 | #include "lmem.h" | 22 | #include "lmem.h" |
23 | #include "lobject.h" | 23 | #include "lobject.h" |
24 | #include "lstate.h" | 24 | #include "lstate.h" |
@@ -28,36 +28,18 @@ | |||
28 | 28 | ||
29 | 29 | ||
30 | /* | 30 | /* |
31 | ** Maximum number of elements to sweep in each single step. | 31 | ** Number of fixed (luaC_fix) objects in a Lua state: metafield names, |
32 | ** (Large enough to dissipate fixed overheads but small enough | 32 | ** plus reserved words, plus "_ENV", plus the memory-error message. |
33 | ** to allow small steps for the collector.) | ||
34 | */ | ||
35 | #define GCSWEEPMAX 100 | ||
36 | |||
37 | /* | ||
38 | ** Maximum number of finalizers to call in each single step. | ||
39 | */ | ||
40 | #define GCFINMAX 10 | ||
41 | |||
42 | |||
43 | /* | ||
44 | ** Cost of calling one finalizer. | ||
45 | */ | ||
46 | #define GCFINALIZECOST 50 | ||
47 | |||
48 | |||
49 | /* | ||
50 | ** The equivalent, in bytes, of one unit of "work" (visiting a slot, | ||
51 | ** sweeping an object, etc.) | ||
52 | */ | 33 | */ |
53 | #define WORK2MEM sizeof(TValue) | 34 | #define NFIXED (TM_N + NUM_RESERVED + 2) |
54 | 35 | ||
55 | 36 | ||
56 | /* | 37 | /* |
57 | ** macro to adjust 'pause': 'pause' is actually used like | 38 | ** Maximum number of elements to sweep in each single step. |
58 | ** 'pause / PAUSEADJ' (value chosen by tests) | 39 | ** (Large enough to dissipate fixed overheads but small enough |
40 | ** to allow small steps for the collector.) | ||
59 | */ | 41 | */ |
60 | #define PAUSEADJ 100 | 42 | #define GCSWEEPMAX 20 |
61 | 43 | ||
62 | 44 | ||
63 | /* mask with all color bits */ | 45 | /* mask with all color bits */ |
@@ -112,7 +94,7 @@ | |||
112 | #define markobjectN(g,t) { if (t) markobject(g,t); } | 94 | #define markobjectN(g,t) { if (t) markobject(g,t); } |
113 | 95 | ||
114 | static void reallymarkobject (global_State *g, GCObject *o); | 96 | static void reallymarkobject (global_State *g, GCObject *o); |
115 | static lu_mem atomic (lua_State *L); | 97 | static l_obj atomic (lua_State *L); |
116 | static void entersweep (lua_State *L); | 98 | static void entersweep (lua_State *L); |
117 | 99 | ||
118 | 100 | ||
@@ -224,7 +206,7 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { | |||
224 | } | 206 | } |
225 | else { /* sweep phase */ | 207 | else { /* sweep phase */ |
226 | lua_assert(issweepphase(g)); | 208 | lua_assert(issweepphase(g)); |
227 | if (g->gckind == KGC_INC) /* incremental mode? */ | 209 | if (g->gckind != KGC_GEN) /* incremental mode? */ |
228 | makewhite(g, o); /* mark 'o' as white to avoid other barriers */ | 210 | makewhite(g, o); /* mark 'o' as white to avoid other barriers */ |
229 | } | 211 | } |
230 | } | 212 | } |
@@ -266,6 +248,7 @@ GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, size_t offset) { | |||
266 | global_State *g = G(L); | 248 | global_State *g = G(L); |
267 | char *p = cast_charp(luaM_newobject(L, novariant(tt), sz)); | 249 | char *p = cast_charp(luaM_newobject(L, novariant(tt), sz)); |
268 | GCObject *o = cast(GCObject *, p + offset); | 250 | GCObject *o = cast(GCObject *, p + offset); |
251 | g->GCdebt--; | ||
269 | o->marked = luaC_white(g); | 252 | o->marked = luaC_white(g); |
270 | o->tt = tt; | 253 | o->tt = tt; |
271 | o->next = g->allgc; | 254 | o->next = g->allgc; |
@@ -274,6 +257,9 @@ GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, size_t offset) { | |||
274 | } | 257 | } |
275 | 258 | ||
276 | 259 | ||
260 | /* | ||
261 | ** create a new collectable object with no offset. | ||
262 | */ | ||
277 | GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { | 263 | GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { |
278 | return luaC_newobjdt(L, tt, sz, 0); | 264 | return luaC_newobjdt(L, tt, sz, 0); |
279 | } | 265 | } |
@@ -302,6 +288,7 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { | |||
302 | ** (only closures can), and a userdata's metatable must be a table. | 288 | ** (only closures can), and a userdata's metatable must be a table. |
303 | */ | 289 | */ |
304 | static void reallymarkobject (global_State *g, GCObject *o) { | 290 | static void reallymarkobject (global_State *g, GCObject *o) { |
291 | g->marked++; | ||
305 | switch (o->tt) { | 292 | switch (o->tt) { |
306 | case LUA_VSHRSTR: | 293 | case LUA_VSHRSTR: |
307 | case LUA_VLNGSTR: { | 294 | case LUA_VLNGSTR: { |
@@ -349,9 +336,9 @@ static void markmt (global_State *g) { | |||
349 | /* | 336 | /* |
350 | ** mark all objects in list of being-finalized | 337 | ** mark all objects in list of being-finalized |
351 | */ | 338 | */ |
352 | static lu_mem markbeingfnz (global_State *g) { | 339 | static l_obj markbeingfnz (global_State *g) { |
353 | GCObject *o; | 340 | GCObject *o; |
354 | lu_mem count = 0; | 341 | l_obj count = 0; |
355 | for (o = g->tobefnz; o != NULL; o = o->next) { | 342 | for (o = g->tobefnz; o != NULL; o = o->next) { |
356 | count++; | 343 | count++; |
357 | markobject(g, o); | 344 | markobject(g, o); |
@@ -371,12 +358,11 @@ static lu_mem markbeingfnz (global_State *g) { | |||
371 | ** upvalues, as they have nothing to be checked. (If the thread gets an | 358 | ** upvalues, as they have nothing to be checked. (If the thread gets an |
372 | ** upvalue later, it will be linked in the list again.) | 359 | ** upvalue later, it will be linked in the list again.) |
373 | */ | 360 | */ |
374 | static int remarkupvals (global_State *g) { | 361 | static l_obj remarkupvals (global_State *g) { |
362 | l_obj work = 0; | ||
375 | lua_State *thread; | 363 | lua_State *thread; |
376 | lua_State **p = &g->twups; | 364 | lua_State **p = &g->twups; |
377 | int work = 0; /* estimate of how much work was done here */ | ||
378 | while ((thread = *p) != NULL) { | 365 | while ((thread = *p) != NULL) { |
379 | work++; | ||
380 | if (!iswhite(thread) && thread->openupval != NULL) | 366 | if (!iswhite(thread) && thread->openupval != NULL) |
381 | p = &thread->twups; /* keep marked thread with upvalues in the list */ | 367 | p = &thread->twups; /* keep marked thread with upvalues in the list */ |
382 | else { /* thread is not marked or without upvalues */ | 368 | else { /* thread is not marked or without upvalues */ |
@@ -386,13 +372,13 @@ static int remarkupvals (global_State *g) { | |||
386 | thread->twups = thread; /* mark that it is out of list */ | 372 | thread->twups = thread; /* mark that it is out of list */ |
387 | for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { | 373 | for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { |
388 | lua_assert(getage(uv) <= getage(thread)); | 374 | lua_assert(getage(uv) <= getage(thread)); |
389 | work++; | ||
390 | if (!iswhite(uv)) { /* upvalue already visited? */ | 375 | if (!iswhite(uv)) { /* upvalue already visited? */ |
391 | lua_assert(upisopen(uv) && isgray(uv)); | 376 | lua_assert(upisopen(uv) && isgray(uv)); |
392 | markvalue(g, uv->v.p); /* mark its value */ | 377 | markvalue(g, uv->v.p); /* mark its value */ |
393 | } | 378 | } |
394 | } | 379 | } |
395 | } | 380 | } |
381 | work++; | ||
396 | } | 382 | } |
397 | return work; | 383 | return work; |
398 | } | 384 | } |
@@ -405,10 +391,15 @@ static void cleargraylists (global_State *g) { | |||
405 | 391 | ||
406 | 392 | ||
407 | /* | 393 | /* |
408 | ** mark root set and reset all gray lists, to start a new collection | 394 | ** mark root set and reset all gray lists, to start a new collection. |
395 | ** 'marked' is initialized with the number of fixed objects in the state, | ||
396 | ** to count the total number of live objects during a cycle. (That is | ||
397 | ** the metafield names, plus the reserved words, plus "_ENV" plus the | ||
398 | ** memory-error message.) | ||
409 | */ | 399 | */ |
410 | static void restartcollection (global_State *g) { | 400 | static void restartcollection (global_State *g) { |
411 | cleargraylists(g); | 401 | cleargraylists(g); |
402 | g->marked = NFIXED; | ||
412 | markobject(g, g->mainthread); | 403 | markobject(g, g->mainthread); |
413 | markvalue(g, &g->l_registry); | 404 | markvalue(g, &g->l_registry); |
414 | markmt(g); | 405 | markmt(g); |
@@ -550,7 +541,7 @@ static void traversestrongtable (global_State *g, Table *h) { | |||
550 | } | 541 | } |
551 | 542 | ||
552 | 543 | ||
553 | static lu_mem traversetable (global_State *g, Table *h) { | 544 | static void traversetable (global_State *g, Table *h) { |
554 | const char *weakkey, *weakvalue; | 545 | const char *weakkey, *weakvalue; |
555 | const TValue *mode = gfasttm(g, h->metatable, TM_MODE); | 546 | const TValue *mode = gfasttm(g, h->metatable, TM_MODE); |
556 | TString *smode; | 547 | TString *smode; |
@@ -569,17 +560,15 @@ static lu_mem traversetable (global_State *g, Table *h) { | |||
569 | } | 560 | } |
570 | else /* not weak */ | 561 | else /* not weak */ |
571 | traversestrongtable(g, h); | 562 | traversestrongtable(g, h); |
572 | return 1 + h->alimit + 2 * allocsizenode(h); | ||
573 | } | 563 | } |
574 | 564 | ||
575 | 565 | ||
576 | static int traverseudata (global_State *g, Udata *u) { | 566 | static void traverseudata (global_State *g, Udata *u) { |
577 | int i; | 567 | int i; |
578 | markobjectN(g, u->metatable); /* mark its metatable */ | 568 | markobjectN(g, u->metatable); /* mark its metatable */ |
579 | for (i = 0; i < u->nuvalue; i++) | 569 | for (i = 0; i < u->nuvalue; i++) |
580 | markvalue(g, &u->uv[i].uv); | 570 | markvalue(g, &u->uv[i].uv); |
581 | genlink(g, obj2gco(u)); | 571 | genlink(g, obj2gco(u)); |
582 | return 1 + u->nuvalue; | ||
583 | } | 572 | } |
584 | 573 | ||
585 | 574 | ||
@@ -588,7 +577,7 @@ static int traverseudata (global_State *g, Udata *u) { | |||
588 | ** arrays can be larger than needed; the extra slots are filled with | 577 | ** arrays can be larger than needed; the extra slots are filled with |
589 | ** NULL, so the use of 'markobjectN') | 578 | ** NULL, so the use of 'markobjectN') |
590 | */ | 579 | */ |
591 | static int traverseproto (global_State *g, Proto *f) { | 580 | static void traverseproto (global_State *g, Proto *f) { |
592 | int i; | 581 | int i; |
593 | markobjectN(g, f->source); | 582 | markobjectN(g, f->source); |
594 | for (i = 0; i < f->sizek; i++) /* mark literals */ | 583 | for (i = 0; i < f->sizek; i++) /* mark literals */ |
@@ -599,29 +588,26 @@ static int traverseproto (global_State *g, Proto *f) { | |||
599 | markobjectN(g, f->p[i]); | 588 | markobjectN(g, f->p[i]); |
600 | for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ | 589 | for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ |
601 | markobjectN(g, f->locvars[i].varname); | 590 | markobjectN(g, f->locvars[i].varname); |
602 | return 1 + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars; | ||
603 | } | 591 | } |
604 | 592 | ||
605 | 593 | ||
606 | static int traverseCclosure (global_State *g, CClosure *cl) { | 594 | static void traverseCclosure (global_State *g, CClosure *cl) { |
607 | int i; | 595 | int i; |
608 | for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ | 596 | for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ |
609 | markvalue(g, &cl->upvalue[i]); | 597 | markvalue(g, &cl->upvalue[i]); |
610 | return 1 + cl->nupvalues; | ||
611 | } | 598 | } |
612 | 599 | ||
613 | /* | 600 | /* |
614 | ** Traverse a Lua closure, marking its prototype and its upvalues. | 601 | ** Traverse a Lua closure, marking its prototype and its upvalues. |
615 | ** (Both can be NULL while closure is being created.) | 602 | ** (Both can be NULL while closure is being created.) |
616 | */ | 603 | */ |
617 | static int traverseLclosure (global_State *g, LClosure *cl) { | 604 | static void traverseLclosure (global_State *g, LClosure *cl) { |
618 | int i; | 605 | int i; |
619 | markobjectN(g, cl->p); /* mark its prototype */ | 606 | markobjectN(g, cl->p); /* mark its prototype */ |
620 | for (i = 0; i < cl->nupvalues; i++) { /* visit its upvalues */ | 607 | for (i = 0; i < cl->nupvalues; i++) { /* visit its upvalues */ |
621 | UpVal *uv = cl->upvals[i]; | 608 | UpVal *uv = cl->upvals[i]; |
622 | markobjectN(g, uv); /* mark upvalue */ | 609 | markobjectN(g, uv); /* mark upvalue */ |
623 | } | 610 | } |
624 | return 1 + cl->nupvalues; | ||
625 | } | 611 | } |
626 | 612 | ||
627 | 613 | ||
@@ -637,13 +623,13 @@ static int traverseLclosure (global_State *g, LClosure *cl) { | |||
637 | ** (which can only happen in generational mode) or if the traverse is in | 623 | ** (which can only happen in generational mode) or if the traverse is in |
638 | ** the propagate phase (which can only happen in incremental mode). | 624 | ** the propagate phase (which can only happen in incremental mode). |
639 | */ | 625 | */ |
640 | static int traversethread (global_State *g, lua_State *th) { | 626 | static void traversethread (global_State *g, lua_State *th) { |
641 | UpVal *uv; | 627 | UpVal *uv; |
642 | StkId o = th->stack.p; | 628 | StkId o = th->stack.p; |
643 | if (isold(th) || g->gcstate == GCSpropagate) | 629 | if (isold(th) || g->gcstate == GCSpropagate) |
644 | linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ | 630 | linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ |
645 | if (o == NULL) | 631 | if (o == NULL) |
646 | return 1; /* stack not completely built yet */ | 632 | return; /* stack not completely built yet */ |
647 | lua_assert(g->gcstate == GCSatomic || | 633 | lua_assert(g->gcstate == GCSatomic || |
648 | th->openupval == NULL || isintwups(th)); | 634 | th->openupval == NULL || isintwups(th)); |
649 | for (; o < th->top.p; o++) /* mark live elements in the stack */ | 635 | for (; o < th->top.p; o++) /* mark live elements in the stack */ |
@@ -661,34 +647,35 @@ static int traversethread (global_State *g, lua_State *th) { | |||
661 | g->twups = th; | 647 | g->twups = th; |
662 | } | 648 | } |
663 | } | 649 | } |
664 | return 1 + stacksize(th); | ||
665 | } | 650 | } |
666 | 651 | ||
667 | 652 | ||
668 | /* | 653 | /* |
669 | ** traverse one gray object, turning it to black. | 654 | ** traverse one gray object, turning it to black. |
670 | */ | 655 | */ |
671 | static lu_mem propagatemark (global_State *g) { | 656 | static void propagatemark (global_State *g) { |
672 | GCObject *o = g->gray; | 657 | GCObject *o = g->gray; |
673 | nw2black(o); | 658 | nw2black(o); |
674 | g->gray = *getgclist(o); /* remove from 'gray' list */ | 659 | g->gray = *getgclist(o); /* remove from 'gray' list */ |
675 | switch (o->tt) { | 660 | switch (o->tt) { |
676 | case LUA_VTABLE: return traversetable(g, gco2t(o)); | 661 | case LUA_VTABLE: traversetable(g, gco2t(o)); break; |
677 | case LUA_VUSERDATA: return traverseudata(g, gco2u(o)); | 662 | case LUA_VUSERDATA: traverseudata(g, gco2u(o)); break; |
678 | case LUA_VLCL: return traverseLclosure(g, gco2lcl(o)); | 663 | case LUA_VLCL: traverseLclosure(g, gco2lcl(o)); break; |
679 | case LUA_VCCL: return traverseCclosure(g, gco2ccl(o)); | 664 | case LUA_VCCL: traverseCclosure(g, gco2ccl(o)); break; |
680 | case LUA_VPROTO: return traverseproto(g, gco2p(o)); | 665 | case LUA_VPROTO: traverseproto(g, gco2p(o)); break; |
681 | case LUA_VTHREAD: return traversethread(g, gco2th(o)); | 666 | case LUA_VTHREAD: traversethread(g, gco2th(o)); break; |
682 | default: lua_assert(0); return 0; | 667 | default: lua_assert(0); |
683 | } | 668 | } |
684 | } | 669 | } |
685 | 670 | ||
686 | 671 | ||
687 | static lu_mem propagateall (global_State *g) { | 672 | static l_obj propagateall (global_State *g) { |
688 | lu_mem tot = 0; | 673 | l_obj work = 0; |
689 | while (g->gray) | 674 | while (g->gray) { |
690 | tot += propagatemark(g); | 675 | propagatemark(g); |
691 | return tot; | 676 | work++; |
677 | } | ||
678 | return work; | ||
692 | } | 679 | } |
693 | 680 | ||
694 | 681 | ||
@@ -697,10 +684,10 @@ static lu_mem propagateall (global_State *g) { | |||
697 | ** Repeat until it converges, that is, nothing new is marked. 'dir' | 684 | ** Repeat until it converges, that is, nothing new is marked. 'dir' |
698 | ** inverts the direction of the traversals, trying to speed up | 685 | ** inverts the direction of the traversals, trying to speed up |
699 | ** convergence on chains in the same table. | 686 | ** convergence on chains in the same table. |
700 | ** | ||
701 | */ | 687 | */ |
702 | static void convergeephemerons (global_State *g) { | 688 | static l_obj convergeephemerons (global_State *g) { |
703 | int changed; | 689 | int changed; |
690 | l_obj work = 0; | ||
704 | int dir = 0; | 691 | int dir = 0; |
705 | do { | 692 | do { |
706 | GCObject *w; | 693 | GCObject *w; |
@@ -715,9 +702,11 @@ static void convergeephemerons (global_State *g) { | |||
715 | propagateall(g); /* propagate changes */ | 702 | propagateall(g); /* propagate changes */ |
716 | changed = 1; /* will have to revisit all ephemeron tables */ | 703 | changed = 1; /* will have to revisit all ephemeron tables */ |
717 | } | 704 | } |
705 | work++; | ||
718 | } | 706 | } |
719 | dir = !dir; /* invert direction next time */ | 707 | dir = !dir; /* invert direction next time */ |
720 | } while (changed); /* repeat until no more changes */ | 708 | } while (changed); /* repeat until no more changes */ |
709 | return work; | ||
721 | } | 710 | } |
722 | 711 | ||
723 | /* }====================================================== */ | 712 | /* }====================================================== */ |
@@ -733,7 +722,8 @@ static void convergeephemerons (global_State *g) { | |||
733 | /* | 722 | /* |
734 | ** clear entries with unmarked keys from all weaktables in list 'l' | 723 | ** clear entries with unmarked keys from all weaktables in list 'l' |
735 | */ | 724 | */ |
736 | static void clearbykeys (global_State *g, GCObject *l) { | 725 | static l_obj clearbykeys (global_State *g, GCObject *l) { |
726 | l_obj work = 0; | ||
737 | for (; l; l = gco2t(l)->gclist) { | 727 | for (; l; l = gco2t(l)->gclist) { |
738 | Table *h = gco2t(l); | 728 | Table *h = gco2t(l); |
739 | Node *limit = gnodelast(h); | 729 | Node *limit = gnodelast(h); |
@@ -744,7 +734,9 @@ static void clearbykeys (global_State *g, GCObject *l) { | |||
744 | if (isempty(gval(n))) /* is entry empty? */ | 734 | if (isempty(gval(n))) /* is entry empty? */ |
745 | clearkey(n); /* clear its key */ | 735 | clearkey(n); /* clear its key */ |
746 | } | 736 | } |
737 | work++; | ||
747 | } | 738 | } |
739 | return work; | ||
748 | } | 740 | } |
749 | 741 | ||
750 | 742 | ||
@@ -752,7 +744,8 @@ static void clearbykeys (global_State *g, GCObject *l) { | |||
752 | ** clear entries with unmarked values from all weaktables in list 'l' up | 744 | ** clear entries with unmarked values from all weaktables in list 'l' up |
753 | ** to element 'f' | 745 | ** to element 'f' |
754 | */ | 746 | */ |
755 | static void clearbyvalues (global_State *g, GCObject *l, GCObject *f) { | 747 | static l_obj clearbyvalues (global_State *g, GCObject *l, GCObject *f) { |
748 | l_obj work = 0; | ||
756 | for (; l != f; l = gco2t(l)->gclist) { | 749 | for (; l != f; l = gco2t(l)->gclist) { |
757 | Table *h = gco2t(l); | 750 | Table *h = gco2t(l); |
758 | Node *n, *limit = gnodelast(h); | 751 | Node *n, *limit = gnodelast(h); |
@@ -769,7 +762,9 @@ static void clearbyvalues (global_State *g, GCObject *l, GCObject *f) { | |||
769 | if (isempty(gval(n))) /* is entry empty? */ | 762 | if (isempty(gval(n))) /* is entry empty? */ |
770 | clearkey(n); /* clear its key */ | 763 | clearkey(n); /* clear its key */ |
771 | } | 764 | } |
765 | work++; | ||
772 | } | 766 | } |
767 | return work; | ||
773 | } | 768 | } |
774 | 769 | ||
775 | 770 | ||
@@ -781,6 +776,7 @@ static void freeupval (lua_State *L, UpVal *uv) { | |||
781 | 776 | ||
782 | 777 | ||
783 | static void freeobj (lua_State *L, GCObject *o) { | 778 | static void freeobj (lua_State *L, GCObject *o) { |
779 | G(L)->totalobjs--; | ||
784 | switch (o->tt) { | 780 | switch (o->tt) { |
785 | case LUA_VPROTO: | 781 | case LUA_VPROTO: |
786 | luaF_freeproto(L, gco2p(o)); | 782 | luaF_freeproto(L, gco2p(o)); |
@@ -830,10 +826,9 @@ static void freeobj (lua_State *L, GCObject *o) { | |||
830 | ** objects, where a dead object is one marked with the old (non current) | 826 | ** objects, where a dead object is one marked with the old (non current) |
831 | ** white; change all non-dead objects back to white, preparing for next | 827 | ** white; change all non-dead objects back to white, preparing for next |
832 | ** collection cycle. Return where to continue the traversal or NULL if | 828 | ** collection cycle. Return where to continue the traversal or NULL if |
833 | ** list is finished. ('*countout' gets the number of elements traversed.) | 829 | ** list is finished. |
834 | */ | 830 | */ |
835 | static GCObject **sweeplist (lua_State *L, GCObject **p, int countin, | 831 | static GCObject **sweeplist (lua_State *L, GCObject **p, int countin) { |
836 | int *countout) { | ||
837 | global_State *g = G(L); | 832 | global_State *g = G(L); |
838 | int ow = otherwhite(g); | 833 | int ow = otherwhite(g); |
839 | int i; | 834 | int i; |
@@ -850,8 +845,6 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, int countin, | |||
850 | p = &curr->next; /* go to next element */ | 845 | p = &curr->next; /* go to next element */ |
851 | } | 846 | } |
852 | } | 847 | } |
853 | if (countout) | ||
854 | *countout = i; /* number of elements traversed */ | ||
855 | return (*p == NULL) ? NULL : p; | 848 | return (*p == NULL) ? NULL : p; |
856 | } | 849 | } |
857 | 850 | ||
@@ -862,7 +855,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, int countin, | |||
862 | static GCObject **sweeptolive (lua_State *L, GCObject **p) { | 855 | static GCObject **sweeptolive (lua_State *L, GCObject **p) { |
863 | GCObject **old = p; | 856 | GCObject **old = p; |
864 | do { | 857 | do { |
865 | p = sweeplist(L, p, 1, NULL); | 858 | p = sweeplist(L, p, 1); |
866 | } while (p == old); | 859 | } while (p == old); |
867 | return p; | 860 | return p; |
868 | } | 861 | } |
@@ -881,11 +874,8 @@ static GCObject **sweeptolive (lua_State *L, GCObject **p) { | |||
881 | */ | 874 | */ |
882 | static void checkSizes (lua_State *L, global_State *g) { | 875 | static void checkSizes (lua_State *L, global_State *g) { |
883 | if (!g->gcemergency) { | 876 | if (!g->gcemergency) { |
884 | if (g->strt.nuse < g->strt.size / 4) { /* string table too big? */ | 877 | if (g->strt.nuse < g->strt.size / 4) /* string table too big? */ |
885 | l_mem olddebt = g->GCdebt; | ||
886 | luaS_resize(L, g->strt.size / 2); | 878 | luaS_resize(L, g->strt.size / 2); |
887 | g->GCestimate += g->GCdebt - olddebt; /* correct estimate */ | ||
888 | } | ||
889 | } | 879 | } |
890 | } | 880 | } |
891 | 881 | ||
@@ -944,18 +934,6 @@ static void GCTM (lua_State *L) { | |||
944 | 934 | ||
945 | 935 | ||
946 | /* | 936 | /* |
947 | ** Call a few finalizers | ||
948 | */ | ||
949 | static int runafewfinalizers (lua_State *L, int n) { | ||
950 | global_State *g = G(L); | ||
951 | int i; | ||
952 | for (i = 0; i < n && g->tobefnz; i++) | ||
953 | GCTM(L); /* call one finalizer */ | ||
954 | return i; | ||
955 | } | ||
956 | |||
957 | |||
958 | /* | ||
959 | ** call all pending finalizers | 937 | ** call all pending finalizers |
960 | */ | 938 | */ |
961 | static void callallpendingfinalizers (lua_State *L) { | 939 | static void callallpendingfinalizers (lua_State *L) { |
@@ -1063,20 +1041,13 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { | |||
1063 | 1041 | ||
1064 | /* | 1042 | /* |
1065 | ** Set the "time" to wait before starting a new GC cycle; cycle will | 1043 | ** Set the "time" to wait before starting a new GC cycle; cycle will |
1066 | ** start when memory use hits the threshold of ('estimate' * pause / | 1044 | ** start when number of objects in use hits the threshold of |
1067 | ** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero, | 1045 | ** approximately (marked * pause / 100). |
1068 | ** because Lua cannot even start with less than PAUSEADJ bytes). | ||
1069 | */ | 1046 | */ |
1070 | static void setpause (global_State *g) { | 1047 | static void setpause (global_State *g) { |
1071 | l_mem threshold, debt; | 1048 | l_obj threshold = applygcparam(g, gcpause, g->marked); |
1072 | int pause = getgcparam(g->gcpause); | 1049 | l_obj debt = threshold - gettotalobjs(g); |
1073 | l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */ | 1050 | if (debt < 0) debt = 0; |
1074 | lua_assert(estimate > 0); | ||
1075 | threshold = (pause < MAX_LMEM / estimate) /* overflow? */ | ||
1076 | ? estimate * pause /* no overflow */ | ||
1077 | : MAX_LMEM; /* overflow; truncate to maximum */ | ||
1078 | debt = gettotalbytes(g) - threshold; | ||
1079 | if (debt > 0) debt = 0; | ||
1080 | luaE_setdebt(g, debt); | 1051 | luaE_setdebt(g, debt); |
1081 | } | 1052 | } |
1082 | 1053 | ||
@@ -1316,18 +1287,17 @@ static void atomic2gen (lua_State *L, global_State *g) { | |||
1316 | sweep2old(L, &g->tobefnz); | 1287 | sweep2old(L, &g->tobefnz); |
1317 | 1288 | ||
1318 | g->gckind = KGC_GEN; | 1289 | g->gckind = KGC_GEN; |
1319 | g->lastatomic = 0; | 1290 | g->GClastmajor = gettotalobjs(g); /* base for memory control */ |
1320 | g->GCestimate = gettotalbytes(g); /* base for memory control */ | ||
1321 | finishgencycle(L, g); | 1291 | finishgencycle(L, g); |
1322 | } | 1292 | } |
1323 | 1293 | ||
1324 | 1294 | ||
1325 | /* | 1295 | /* |
1326 | ** Set debt for the next minor collection, which will happen when | 1296 | ** Set debt for the next minor collection, which will happen when |
1327 | ** memory grows 'genminormul'%. | 1297 | ** total number of objects grows 'genminormul'%. |
1328 | */ | 1298 | */ |
1329 | static void setminordebt (global_State *g) { | 1299 | static void setminordebt (global_State *g) { |
1330 | luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul)); | 1300 | luaE_setdebt(g, applygcparam(g, genminormul, gettotalobjs(g))); |
1331 | } | 1301 | } |
1332 | 1302 | ||
1333 | 1303 | ||
@@ -1337,14 +1307,12 @@ static void setminordebt (global_State *g) { | |||
1337 | ** are cleared. Then, turn all objects into old and finishes the | 1307 | ** are cleared. Then, turn all objects into old and finishes the |
1338 | ** collection. | 1308 | ** collection. |
1339 | */ | 1309 | */ |
1340 | static lu_mem entergen (lua_State *L, global_State *g) { | 1310 | static void entergen (lua_State *L, global_State *g) { |
1341 | lu_mem numobjs; | ||
1342 | luaC_runtilstate(L, bitmask(GCSpause)); /* prepare to start a new cycle */ | 1311 | luaC_runtilstate(L, bitmask(GCSpause)); /* prepare to start a new cycle */ |
1343 | luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ | 1312 | luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ |
1344 | numobjs = atomic(L); /* propagates all and then do the atomic stuff */ | 1313 | atomic(L); /* propagates all and then do the atomic stuff */ |
1345 | atomic2gen(L, g); | 1314 | atomic2gen(L, g); |
1346 | setminordebt(g); /* set debt assuming next cycle will be minor */ | 1315 | setminordebt(g); /* set debt assuming next cycle will be minor */ |
1347 | return numobjs; | ||
1348 | } | 1316 | } |
1349 | 1317 | ||
1350 | 1318 | ||
@@ -1361,7 +1329,6 @@ static void enterinc (global_State *g) { | |||
1361 | g->finobjrold = g->finobjold1 = g->finobjsur = NULL; | 1329 | g->finobjrold = g->finobjold1 = g->finobjsur = NULL; |
1362 | g->gcstate = GCSpause; | 1330 | g->gcstate = GCSpause; |
1363 | g->gckind = KGC_INC; | 1331 | g->gckind = KGC_INC; |
1364 | g->lastatomic = 0; | ||
1365 | } | 1332 | } |
1366 | 1333 | ||
1367 | 1334 | ||
@@ -1370,111 +1337,75 @@ static void enterinc (global_State *g) { | |||
1370 | */ | 1337 | */ |
1371 | void luaC_changemode (lua_State *L, int newmode) { | 1338 | void luaC_changemode (lua_State *L, int newmode) { |
1372 | global_State *g = G(L); | 1339 | global_State *g = G(L); |
1373 | if (newmode != g->gckind) { | 1340 | if (newmode != g->gckind) { /* does it need to change? */ |
1374 | if (newmode == KGC_GEN) /* entering generational mode? */ | 1341 | if (newmode == KGC_INC) { /* entering incremental mode? */ |
1342 | if (g->gckind == KGC_GENMAJOR) | ||
1343 | g->gckind = KGC_INC; /* already incremental but in name */ | ||
1344 | else | ||
1345 | enterinc(g); /* entering incremental mode */ | ||
1346 | } | ||
1347 | else { | ||
1348 | lua_assert(newmode == KGC_GEN); | ||
1375 | entergen(L, g); | 1349 | entergen(L, g); |
1376 | else | 1350 | } |
1377 | enterinc(g); /* entering incremental mode */ | ||
1378 | } | 1351 | } |
1379 | g->lastatomic = 0; | ||
1380 | } | 1352 | } |
1381 | 1353 | ||
1382 | 1354 | ||
1383 | /* | 1355 | /* |
1384 | ** Does a full collection in generational mode. | 1356 | ** Does a full collection in generational mode. |
1385 | */ | 1357 | */ |
1386 | static lu_mem fullgen (lua_State *L, global_State *g) { | 1358 | static void fullgen (lua_State *L, global_State *g) { |
1387 | enterinc(g); | 1359 | enterinc(g); |
1388 | return entergen(L, g); | 1360 | entergen(L, g); |
1389 | } | 1361 | } |
1390 | 1362 | ||
1391 | 1363 | ||
1392 | /* | 1364 | /* |
1393 | ** Does a major collection after last collection was a "bad collection". | 1365 | ** Does a major collector up to the atomic phase and then either |
1394 | ** | 1366 | ** returns to minor collections or stays doing major ones. If the |
1395 | ** When the program is building a big structure, it allocates lots of | 1367 | ** number of objects collected this time (numobjs - marked) is more than |
1396 | ** memory but generates very little garbage. In those scenarios, | 1368 | ** half the number of objects created since the last major collection |
1397 | ** the generational mode just wastes time doing small collections, and | 1369 | ** (numobjs - lastmajor), it goes back to minor collections. |
1398 | ** major collections are frequently what we call a "bad collection", a | 1370 | */ |
1399 | ** collection that frees too few objects. To avoid the cost of switching | 1371 | static void genmajorstep (lua_State *L, global_State *g) { |
1400 | ** between generational mode and the incremental mode needed for full | 1372 | l_obj lastmajor = g->GClastmajor; /* count from last collection */ |
1401 | ** (major) collections, the collector tries to stay in incremental mode | 1373 | l_obj numobjs = gettotalobjs(g); /* current count */ |
1402 | ** after a bad collection, and to switch back to generational mode only | ||
1403 | ** after a "good" collection (one that traverses less than 9/8 objects | ||
1404 | ** of the previous one). | ||
1405 | ** The collector must choose whether to stay in incremental mode or to | ||
1406 | ** switch back to generational mode before sweeping. At this point, it | ||
1407 | ** does not know the real memory in use, so it cannot use memory to | ||
1408 | ** decide whether to return to generational mode. Instead, it uses the | ||
1409 | ** number of objects traversed (returned by 'atomic') as a proxy. The | ||
1410 | ** field 'g->lastatomic' keeps this count from the last collection. | ||
1411 | ** ('g->lastatomic != 0' also means that the last collection was bad.) | ||
1412 | */ | ||
1413 | static void stepgenfull (lua_State *L, global_State *g) { | ||
1414 | lu_mem newatomic; /* count of traversed objects */ | ||
1415 | lu_mem lastatomic = g->lastatomic; /* count from last collection */ | ||
1416 | if (g->gckind == KGC_GEN) /* still in generational mode? */ | ||
1417 | enterinc(g); /* enter incremental mode */ | ||
1418 | luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ | 1374 | luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ |
1419 | newatomic = atomic(L); /* mark everybody */ | 1375 | atomic(L); /* mark everybody */ |
1420 | if (newatomic < lastatomic + (lastatomic >> 3)) { /* good collection? */ | 1376 | if ((numobjs - g->marked) > ((numobjs - lastmajor) >> 1)) { |
1421 | atomic2gen(L, g); /* return to generational mode */ | 1377 | atomic2gen(L, g); /* return to generational mode */ |
1422 | setminordebt(g); | 1378 | setminordebt(g); |
1423 | } | 1379 | } |
1424 | else { /* another bad collection; stay in incremental mode */ | 1380 | else { /* bad collection; stay in major mode */ |
1425 | g->GCestimate = gettotalbytes(g); /* first estimate */ | ||
1426 | entersweep(L); | 1381 | entersweep(L); |
1427 | luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ | 1382 | luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ |
1428 | setpause(g); | 1383 | setpause(g); |
1429 | g->lastatomic = newatomic; | 1384 | g->GClastmajor = gettotalobjs(g); |
1430 | } | 1385 | } |
1431 | } | 1386 | } |
1432 | 1387 | ||
1433 | 1388 | ||
1434 | /* | 1389 | /* |
1435 | ** Does a generational "step". | 1390 | ** Does a generational "step". If the total number of objects grew |
1436 | ** Usually, this means doing a minor collection and setting the debt to | 1391 | ** more than 'majormul'% since the last major collection, does a |
1437 | ** make another collection when memory grows 'genminormul'% larger. | 1392 | ** major collection. Otherwise, does a minor collection. |
1438 | ** | ||
1439 | ** However, there are exceptions. If memory grows 'genmajormul'% | ||
1440 | ** larger than it was at the end of the last major collection (kept | ||
1441 | ** in 'g->GCestimate'), the function does a major collection. At the | ||
1442 | ** end, it checks whether the major collection was able to free a | ||
1443 | ** decent amount of memory (at least half the growth in memory since | ||
1444 | ** previous major collection). If so, the collector keeps its state, | ||
1445 | ** and the next collection will probably be minor again. Otherwise, | ||
1446 | ** we have what we call a "bad collection". In that case, set the field | ||
1447 | ** 'g->lastatomic' to signal that fact, so that the next collection will | ||
1448 | ** go to 'stepgenfull'. | ||
1449 | ** | ||
1450 | ** 'GCdebt <= 0' means an explicit call to GC step with "size" zero; | ||
1451 | ** in that case, do a minor collection. | ||
1452 | */ | 1393 | */ |
1453 | static void genstep (lua_State *L, global_State *g) { | 1394 | static void genstep (lua_State *L, global_State *g) { |
1454 | if (g->lastatomic != 0) /* last collection was a bad one? */ | 1395 | l_obj majorbase = g->GClastmajor; /* count after last major collection */ |
1455 | stepgenfull(L, g); /* do a full step */ | 1396 | l_obj majorinc = applygcparam(g, genmajormul, majorbase); |
1456 | else { | 1397 | if (gettotalobjs(g) > majorbase + majorinc && 0) { |
1457 | lu_mem majorbase = g->GCestimate; /* memory after last major collection */ | 1398 | /* do a major collection */ |
1458 | lu_mem majorinc = (majorbase / 100) * getgcparam(g->genmajormul); | 1399 | enterinc(g); |
1459 | if (g->GCdebt > 0 && gettotalbytes(g) > majorbase + majorinc) { | 1400 | g->gckind = KGC_GENMAJOR; |
1460 | lu_mem numobjs = fullgen(L, g); /* do a major collection */ | 1401 | genmajorstep(L, g); |
1461 | if (gettotalbytes(g) < majorbase + (majorinc / 2)) { | 1402 | } |
1462 | /* collected at least half of memory growth since last major | 1403 | else { /* regular case; do a minor collection */ |
1463 | collection; keep doing minor collections. */ | 1404 | g->marked = 0; |
1464 | lua_assert(g->lastatomic == 0); | 1405 | youngcollection(L, g); |
1465 | } | 1406 | setminordebt(g); |
1466 | else { /* bad collection */ | 1407 | lua_assert(g->GClastmajor == majorbase); |
1467 | g->lastatomic = numobjs; /* signal that last collection was bad */ | ||
1468 | setpause(g); /* do a long wait for next (major) collection */ | ||
1469 | } | ||
1470 | } | ||
1471 | else { /* regular case; do a minor collection */ | ||
1472 | youngcollection(L, g); | ||
1473 | setminordebt(g); | ||
1474 | g->GCestimate = majorbase; /* preserve base value */ | ||
1475 | } | ||
1476 | } | 1408 | } |
1477 | lua_assert(isdecGCmodegen(g)); | ||
1478 | } | 1409 | } |
1479 | 1410 | ||
1480 | /* }====================================================== */ | 1411 | /* }====================================================== */ |
@@ -1533,9 +1464,9 @@ void luaC_freeallobjects (lua_State *L) { | |||
1533 | } | 1464 | } |
1534 | 1465 | ||
1535 | 1466 | ||
1536 | static lu_mem atomic (lua_State *L) { | 1467 | static l_obj atomic (lua_State *L) { |
1468 | l_obj work = 0; | ||
1537 | global_State *g = G(L); | 1469 | global_State *g = G(L); |
1538 | lu_mem work = 0; | ||
1539 | GCObject *origweak, *origall; | 1470 | GCObject *origweak, *origall; |
1540 | GCObject *grayagain = g->grayagain; /* save original list */ | 1471 | GCObject *grayagain = g->grayagain; /* save original list */ |
1541 | g->grayagain = NULL; | 1472 | g->grayagain = NULL; |
@@ -1552,50 +1483,44 @@ static lu_mem atomic (lua_State *L) { | |||
1552 | work += propagateall(g); /* propagate changes */ | 1483 | work += propagateall(g); /* propagate changes */ |
1553 | g->gray = grayagain; | 1484 | g->gray = grayagain; |
1554 | work += propagateall(g); /* traverse 'grayagain' list */ | 1485 | work += propagateall(g); /* traverse 'grayagain' list */ |
1555 | convergeephemerons(g); | 1486 | work += convergeephemerons(g); |
1556 | /* at this point, all strongly accessible objects are marked. */ | 1487 | /* at this point, all strongly accessible objects are marked. */ |
1557 | /* Clear values from weak tables, before checking finalizers */ | 1488 | /* Clear values from weak tables, before checking finalizers */ |
1558 | clearbyvalues(g, g->weak, NULL); | 1489 | work += clearbyvalues(g, g->weak, NULL); |
1559 | clearbyvalues(g, g->allweak, NULL); | 1490 | work += clearbyvalues(g, g->allweak, NULL); |
1560 | origweak = g->weak; origall = g->allweak; | 1491 | origweak = g->weak; origall = g->allweak; |
1561 | separatetobefnz(g, 0); /* separate objects to be finalized */ | 1492 | separatetobefnz(g, 0); /* separate objects to be finalized */ |
1562 | work += markbeingfnz(g); /* mark objects that will be finalized */ | 1493 | work += markbeingfnz(g); /* mark objects that will be finalized */ |
1563 | work += propagateall(g); /* remark, to propagate 'resurrection' */ | 1494 | work += propagateall(g); /* remark, to propagate 'resurrection' */ |
1564 | convergeephemerons(g); | 1495 | work += convergeephemerons(g); |
1565 | /* at this point, all resurrected objects are marked. */ | 1496 | /* at this point, all resurrected objects are marked. */ |
1566 | /* remove dead objects from weak tables */ | 1497 | /* remove dead objects from weak tables */ |
1567 | clearbykeys(g, g->ephemeron); /* clear keys from all ephemeron tables */ | 1498 | work += clearbykeys(g, g->ephemeron); /* clear keys from all ephemeron */ |
1568 | clearbykeys(g, g->allweak); /* clear keys from all 'allweak' tables */ | 1499 | work += clearbykeys(g, g->allweak); /* clear keys from all 'allweak' */ |
1569 | /* clear values from resurrected weak tables */ | 1500 | /* clear values from resurrected weak tables */ |
1570 | clearbyvalues(g, g->weak, origweak); | 1501 | work += clearbyvalues(g, g->weak, origweak); |
1571 | clearbyvalues(g, g->allweak, origall); | 1502 | work += clearbyvalues(g, g->allweak, origall); |
1572 | luaS_clearcache(g); | 1503 | luaS_clearcache(g); |
1573 | g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ | 1504 | g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ |
1574 | lua_assert(g->gray == NULL); | 1505 | lua_assert(g->gray == NULL); |
1575 | return work; /* estimate of slots marked by 'atomic' */ | 1506 | return work; |
1576 | } | 1507 | } |
1577 | 1508 | ||
1578 | 1509 | ||
1579 | static int sweepstep (lua_State *L, global_State *g, | 1510 | static void sweepstep (lua_State *L, global_State *g, |
1580 | int nextstate, GCObject **nextlist) { | 1511 | int nextstate, GCObject **nextlist) { |
1581 | if (g->sweepgc) { | 1512 | if (g->sweepgc) |
1582 | l_mem olddebt = g->GCdebt; | 1513 | g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); |
1583 | int count; | ||
1584 | g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX, &count); | ||
1585 | g->GCestimate += g->GCdebt - olddebt; /* update estimate */ | ||
1586 | return count; | ||
1587 | } | ||
1588 | else { /* enter next state */ | 1514 | else { /* enter next state */ |
1589 | g->gcstate = nextstate; | 1515 | g->gcstate = nextstate; |
1590 | g->sweepgc = nextlist; | 1516 | g->sweepgc = nextlist; |
1591 | return 0; /* no work done */ | ||
1592 | } | 1517 | } |
1593 | } | 1518 | } |
1594 | 1519 | ||
1595 | 1520 | ||
1596 | static lu_mem singlestep (lua_State *L) { | 1521 | static l_obj singlestep (lua_State *L) { |
1597 | global_State *g = G(L); | 1522 | global_State *g = G(L); |
1598 | lu_mem work; | 1523 | l_obj work; |
1599 | lua_assert(!g->gcstopem); /* collector is not reentrant */ | 1524 | lua_assert(!g->gcstopem); /* collector is not reentrant */ |
1600 | g->gcstopem = 1; /* no emergency collections while collecting */ | 1525 | g->gcstopem = 1; /* no emergency collections while collecting */ |
1601 | switch (g->gcstate) { | 1526 | switch (g->gcstate) { |
@@ -1610,26 +1535,30 @@ static lu_mem singlestep (lua_State *L) { | |||
1610 | g->gcstate = GCSenteratomic; /* finish propagate phase */ | 1535 | g->gcstate = GCSenteratomic; /* finish propagate phase */ |
1611 | work = 0; | 1536 | work = 0; |
1612 | } | 1537 | } |
1613 | else | 1538 | else { |
1614 | work = propagatemark(g); /* traverse one gray object */ | 1539 | propagatemark(g); /* traverse one gray object */ |
1540 | work = 1; | ||
1541 | } | ||
1615 | break; | 1542 | break; |
1616 | } | 1543 | } |
1617 | case GCSenteratomic: { | 1544 | case GCSenteratomic: { |
1618 | work = atomic(L); /* work is what was traversed by 'atomic' */ | 1545 | work = atomic(L); |
1619 | entersweep(L); | 1546 | entersweep(L); |
1620 | g->GCestimate = gettotalbytes(g); /* first estimate */ | ||
1621 | break; | 1547 | break; |
1622 | } | 1548 | } |
1623 | case GCSswpallgc: { /* sweep "regular" objects */ | 1549 | case GCSswpallgc: { /* sweep "regular" objects */ |
1624 | work = sweepstep(L, g, GCSswpfinobj, &g->finobj); | 1550 | sweepstep(L, g, GCSswpfinobj, &g->finobj); |
1551 | work = GCSWEEPMAX; | ||
1625 | break; | 1552 | break; |
1626 | } | 1553 | } |
1627 | case GCSswpfinobj: { /* sweep objects with finalizers */ | 1554 | case GCSswpfinobj: { /* sweep objects with finalizers */ |
1628 | work = sweepstep(L, g, GCSswptobefnz, &g->tobefnz); | 1555 | sweepstep(L, g, GCSswptobefnz, &g->tobefnz); |
1556 | work = GCSWEEPMAX; | ||
1629 | break; | 1557 | break; |
1630 | } | 1558 | } |
1631 | case GCSswptobefnz: { /* sweep objects to be finalized */ | 1559 | case GCSswptobefnz: { /* sweep objects to be finalized */ |
1632 | work = sweepstep(L, g, GCSswpend, NULL); | 1560 | sweepstep(L, g, GCSswpend, NULL); |
1561 | work = GCSWEEPMAX; | ||
1633 | break; | 1562 | break; |
1634 | } | 1563 | } |
1635 | case GCSswpend: { /* finish sweeps */ | 1564 | case GCSswpend: { /* finish sweeps */ |
@@ -1638,10 +1567,11 @@ static lu_mem singlestep (lua_State *L) { | |||
1638 | work = 0; | 1567 | work = 0; |
1639 | break; | 1568 | break; |
1640 | } | 1569 | } |
1641 | case GCScallfin: { /* call remaining finalizers */ | 1570 | case GCScallfin: { /* call finalizers */ |
1642 | if (g->tobefnz && !g->gcemergency) { | 1571 | if (g->tobefnz && !g->gcemergency) { |
1643 | g->gcstopem = 0; /* ok collections during finalizers */ | 1572 | g->gcstopem = 0; /* ok collections during finalizers */ |
1644 | work = runafewfinalizers(L, GCFINMAX) * GCFINALIZECOST; | 1573 | GCTM(L); /* call one finalizer */ |
1574 | work = 1; | ||
1645 | } | 1575 | } |
1646 | else { /* emergency mode or no more finalizers */ | 1576 | else { /* emergency mode or no more finalizers */ |
1647 | g->gcstate = GCSpause; /* finish collection */ | 1577 | g->gcstate = GCSpause; /* finish collection */ |
@@ -1676,20 +1606,16 @@ void luaC_runtilstate (lua_State *L, int statesmask) { | |||
1676 | ** controls when next step will be performed. | 1606 | ** controls when next step will be performed. |
1677 | */ | 1607 | */ |
1678 | static void incstep (lua_State *L, global_State *g) { | 1608 | static void incstep (lua_State *L, global_State *g) { |
1679 | int stepmul = (getgcparam(g->gcstepmul) | 1); /* avoid division by 0 */ | 1609 | l_obj stepsize = cast(l_obj, 1) << g->gcstepsize; |
1680 | l_mem debt = (g->GCdebt / WORK2MEM) * stepmul; | 1610 | l_obj work2do = applygcparam(g, gcstepmul, stepsize); |
1681 | l_mem stepsize = (g->gcstepsize <= log2maxs(l_mem)) | ||
1682 | ? ((cast(l_mem, 1) << g->gcstepsize) / WORK2MEM) * stepmul | ||
1683 | : MAX_LMEM; /* overflow; keep maximum value */ | ||
1684 | do { /* repeat until pause or enough "credit" (negative debt) */ | 1611 | do { /* repeat until pause or enough "credit" (negative debt) */ |
1685 | lu_mem work = singlestep(L); /* perform one single step */ | 1612 | l_obj work = singlestep(L); /* perform one single step */ |
1686 | debt -= work; | 1613 | work2do -= work; |
1687 | } while (debt > -stepsize && g->gcstate != GCSpause); | 1614 | } while (work2do > 0 && g->gcstate != GCSpause); |
1688 | if (g->gcstate == GCSpause) | 1615 | if (g->gcstate == GCSpause) |
1689 | setpause(g); /* pause until next cycle */ | 1616 | setpause(g); /* pause until next cycle */ |
1690 | else { | 1617 | else { |
1691 | debt = (debt / stepmul) * WORK2MEM; /* convert 'work units' to bytes */ | 1618 | luaE_setdebt(g, stepsize); |
1692 | luaE_setdebt(g, debt); | ||
1693 | } | 1619 | } |
1694 | } | 1620 | } |
1695 | 1621 | ||
@@ -1700,13 +1626,21 @@ static void incstep (lua_State *L, global_State *g) { | |||
1700 | */ | 1626 | */ |
1701 | void luaC_step (lua_State *L) { | 1627 | void luaC_step (lua_State *L) { |
1702 | global_State *g = G(L); | 1628 | global_State *g = G(L); |
1629 | lua_assert(!g->gcemergency); | ||
1703 | if (!gcrunning(g)) /* not running? */ | 1630 | if (!gcrunning(g)) /* not running? */ |
1704 | luaE_setdebt(g, -2000); | 1631 | luaE_setdebt(g, 2000); |
1705 | else { | 1632 | else { |
1706 | if(isdecGCmodegen(g)) | 1633 | switch (g->gckind) { |
1707 | genstep(L, g); | 1634 | case KGC_INC: |
1708 | else | 1635 | incstep(L, g); |
1709 | incstep(L, g); | 1636 | break; |
1637 | case KGC_GEN: | ||
1638 | genstep(L, g); | ||
1639 | break; | ||
1640 | case KGC_GENMAJOR: | ||
1641 | genmajorstep(L, g); | ||
1642 | break; | ||
1643 | } | ||
1710 | } | 1644 | } |
1711 | } | 1645 | } |
1712 | 1646 | ||
@@ -1726,8 +1660,8 @@ static void fullinc (lua_State *L, global_State *g) { | |||
1726 | luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ | 1660 | luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ |
1727 | g->gcstate = GCSenteratomic; /* go straight to atomic phase ??? */ | 1661 | g->gcstate = GCSenteratomic; /* go straight to atomic phase ??? */ |
1728 | luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ | 1662 | luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ |
1729 | /* estimate must be correct after a full GC cycle */ | 1663 | /* 'marked' must be correct after a full GC cycle */ |
1730 | lua_assert(g->GCestimate == gettotalbytes(g)); | 1664 | lua_assert(g->marked == gettotalobjs(g)); |
1731 | luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ | 1665 | luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ |
1732 | setpause(g); | 1666 | setpause(g); |
1733 | } | 1667 | } |
@@ -1742,10 +1676,10 @@ void luaC_fullgc (lua_State *L, int isemergency) { | |||
1742 | global_State *g = G(L); | 1676 | global_State *g = G(L); |
1743 | lua_assert(!g->gcemergency); | 1677 | lua_assert(!g->gcemergency); |
1744 | g->gcemergency = isemergency; /* set flag */ | 1678 | g->gcemergency = isemergency; /* set flag */ |
1745 | if (g->gckind == KGC_INC) | 1679 | if (g->gckind == KGC_GEN) |
1746 | fullinc(L, g); | ||
1747 | else | ||
1748 | fullgen(L, g); | 1680 | fullgen(L, g); |
1681 | else | ||
1682 | fullinc(L, g); | ||
1749 | g->gcemergency = 0; | 1683 | g->gcemergency = 0; |
1750 | } | 1684 | } |
1751 | 1685 | ||
@@ -8,6 +8,9 @@ | |||
8 | #define lgc_h | 8 | #define lgc_h |
9 | 9 | ||
10 | 10 | ||
11 | #include <stddef.h> | ||
12 | |||
13 | |||
11 | #include "lobject.h" | 14 | #include "lobject.h" |
12 | #include "lstate.h" | 15 | #include "lstate.h" |
13 | 16 | ||
@@ -122,31 +125,21 @@ | |||
122 | 125 | ||
123 | 126 | ||
124 | /* Default Values for GC parameters */ | 127 | /* Default Values for GC parameters */ |
125 | #define LUAI_GENMAJORMUL 100 | ||
126 | #define LUAI_GENMINORMUL 20 | ||
127 | 128 | ||
128 | /* wait memory to double before starting new cycle */ | 129 | /* generational */ |
129 | #define LUAI_GCPAUSE 200 | ||
130 | 130 | ||
131 | /* | 131 | #define LUAI_GENMAJORMUL 100 /* major multiplier */ |
132 | ** some gc parameters are stored divided by 4 to allow a maximum value | 132 | #define LUAI_GENMINORMUL 20 /* minor multiplier */ |
133 | ** up to 1023 in a 'lu_byte'. | ||
134 | */ | ||
135 | #define getgcparam(p) ((p) * 4) | ||
136 | #define setgcparam(p,v) ((p) = (v) / 4) | ||
137 | 133 | ||
138 | #define LUAI_GCMUL 100 | 134 | /* incremental */ |
139 | 135 | ||
140 | /* how much to allocate before next GC step (log2) */ | 136 | /* wait memory to double before starting new cycle */ |
141 | #define LUAI_GCSTEPSIZE 13 /* 8 KB */ | 137 | #define LUAI_GCPAUSE 200 |
142 | 138 | ||
139 | #define LUAI_GCMUL 300 /* step multiplier */ | ||
143 | 140 | ||
144 | /* | 141 | /* how many objects to allocate before next GC step (log2) */ |
145 | ** Check whether the declared GC mode is generational. While in | 142 | #define LUAI_GCSTEPSIZE 8 /* 256 objects */ |
146 | ** generational mode, the collector can go temporarily to incremental | ||
147 | ** mode to improve performance. This is signaled by 'g->lastatomic != 0'. | ||
148 | */ | ||
149 | #define isdecGCmodegen(g) (g->gckind == KGC_GEN || g->lastatomic != 0) | ||
150 | 143 | ||
151 | 144 | ||
152 | /* | 145 | /* |
@@ -157,15 +150,38 @@ | |||
157 | #define GCSTPCLS 4 /* bit true when closing Lua state */ | 150 | #define GCSTPCLS 4 /* bit true when closing Lua state */ |
158 | #define gcrunning(g) ((g)->gcstp == 0) | 151 | #define gcrunning(g) ((g)->gcstp == 0) |
159 | 152 | ||
153 | /* | ||
154 | ** Macros to set and apply GC parameters. GC parameters are given in | ||
155 | ** percentage points, but are stored as lu_byte. To reduce their | ||
156 | ** values and avoid repeated divisions by 100, these macros store | ||
157 | ** the original parameter multiplied by 2^n and divided by 100. | ||
158 | ** To apply them, the value is divided by 2^n (a shift) and then | ||
159 | ** multiplied by the stored parameter, yielding | ||
160 | ** value / 2^n * (original parameter * 2^n / 100), or approximately | ||
161 | ** (value * original parameter / 100). | ||
162 | ** | ||
163 | ** For most parameters, which are typically larger than 100%, 2^n is | ||
164 | ** 16 (2^4), allowing maximum values up to 1599. For the minor | ||
165 | ** multiplier, which is typically smaller, 2^n is 64 (2^6) to allow more | ||
166 | ** precision. | ||
167 | */ | ||
168 | #define gcparamshift(p) \ | ||
169 | (offsetof(global_State, p) == offsetof(global_State, genminormul) ? 6 : 4) | ||
170 | |||
171 | #define setgcparam(g,p,v) \ | ||
172 | (g->p = (cast_uint(v) << gcparamshift(p)) / 100u) | ||
173 | #define applygcparam(g,p,v) (((v) >> gcparamshift(p)) * g->p) | ||
174 | |||
175 | |||
160 | 176 | ||
161 | /* | 177 | /* |
162 | ** Does one step of collection when debt becomes positive. 'pre'/'pos' | 178 | ** Does one step of collection when debt becomes zero. 'pre'/'pos' |
163 | ** allows some adjustments to be done only when needed. macro | 179 | ** allows some adjustments to be done only when needed. macro |
164 | ** 'condchangemem' is used only for heavy tests (forcing a full | 180 | ** 'condchangemem' is used only for heavy tests (forcing a full |
165 | ** GC cycle on every opportunity) | 181 | ** GC cycle on every opportunity) |
166 | */ | 182 | */ |
167 | #define luaC_condGC(L,pre,pos) \ | 183 | #define luaC_condGC(L,pre,pos) \ |
168 | { if (G(L)->GCdebt > 0) { pre; luaC_step(L); pos;}; \ | 184 | { if (G(L)->GCdebt <= 0) { pre; luaC_step(L); pos;}; \ |
169 | condchangemem(L,pre,pos); } | 185 | condchangemem(L,pre,pos); } |
170 | 186 | ||
171 | /* more often than not, 'pre'/'pos' are empty */ | 187 | /* more often than not, 'pre'/'pos' are empty */ |
@@ -8,21 +8,6 @@ | |||
8 | #define linit_c | 8 | #define linit_c |
9 | #define LUA_LIB | 9 | #define LUA_LIB |
10 | 10 | ||
11 | /* | ||
12 | ** If you embed Lua in your program and need to open the standard | ||
13 | ** libraries, call luaL_openlibs in your program. If you need a | ||
14 | ** different set of libraries, copy this file to your project and edit | ||
15 | ** it to suit your needs. | ||
16 | ** | ||
17 | ** You can also *preload* libraries, so that a later 'require' can | ||
18 | ** open the library, which is already linked to the application. | ||
19 | ** For that, do the following code: | ||
20 | ** | ||
21 | ** luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); | ||
22 | ** lua_pushcfunction(L, luaopen_modname); | ||
23 | ** lua_setfield(L, -2, modname); | ||
24 | ** lua_pop(L, 1); // remove PRELOAD table | ||
25 | */ | ||
26 | 11 | ||
27 | #include "lprefix.h" | 12 | #include "lprefix.h" |
28 | 13 | ||
@@ -36,30 +21,44 @@ | |||
36 | 21 | ||
37 | 22 | ||
38 | /* | 23 | /* |
39 | ** these libs are loaded by lua.c and are readily available to any Lua | 24 | ** Standard Libraries |
40 | ** program | ||
41 | */ | 25 | */ |
42 | static const luaL_Reg loadedlibs[] = { | 26 | static const luaL_Reg stdlibs[] = { |
43 | {LUA_GNAME, luaopen_base}, | 27 | {LUA_GNAME, luaopen_base}, |
44 | {LUA_LOADLIBNAME, luaopen_package}, | 28 | {LUA_LOADLIBNAME, luaopen_package}, |
29 | |||
45 | {LUA_COLIBNAME, luaopen_coroutine}, | 30 | {LUA_COLIBNAME, luaopen_coroutine}, |
46 | {LUA_TABLIBNAME, luaopen_table}, | 31 | {LUA_DBLIBNAME, luaopen_debug}, |
47 | {LUA_IOLIBNAME, luaopen_io}, | 32 | {LUA_IOLIBNAME, luaopen_io}, |
33 | {LUA_MATHLIBNAME, luaopen_math}, | ||
48 | {LUA_OSLIBNAME, luaopen_os}, | 34 | {LUA_OSLIBNAME, luaopen_os}, |
49 | {LUA_STRLIBNAME, luaopen_string}, | 35 | {LUA_STRLIBNAME, luaopen_string}, |
50 | {LUA_MATHLIBNAME, luaopen_math}, | 36 | {LUA_TABLIBNAME, luaopen_table}, |
51 | {LUA_UTF8LIBNAME, luaopen_utf8}, | 37 | {LUA_UTF8LIBNAME, luaopen_utf8}, |
52 | {LUA_DBLIBNAME, luaopen_debug}, | 38 | |
53 | {NULL, NULL} | 39 | {NULL, NULL} |
54 | }; | 40 | }; |
55 | 41 | ||
56 | 42 | ||
57 | LUALIB_API void luaL_openlibs (lua_State *L) { | 43 | /* |
44 | ** require selected standard libraries and add the others to the | ||
45 | ** preload table. | ||
46 | */ | ||
47 | LUALIB_API void luaL_openselectedlibs (lua_State *L, int what) { | ||
48 | int mask = 1; | ||
58 | const luaL_Reg *lib; | 49 | const luaL_Reg *lib; |
59 | /* "require" functions from 'loadedlibs' and set results to global table */ | 50 | luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); |
60 | for (lib = loadedlibs; lib->func; lib++) { | 51 | for (lib = stdlibs; lib->func; (lib++, mask <<= 1)) { |
61 | luaL_requiref(L, lib->name, lib->func, 1); | 52 | if (what & mask) { /* selected? */ |
62 | lua_pop(L, 1); /* remove lib */ | 53 | luaL_requiref(L, lib->name, lib->func, 1); /* require library */ |
54 | lua_pop(L, 1); /* remove result from the stack */ | ||
55 | } | ||
56 | else { /* add library to PRELOAD table */ | ||
57 | lua_pushcfunction(L, lib->func); | ||
58 | lua_setfield(L, -2, lib->name); | ||
59 | } | ||
63 | } | 60 | } |
61 | lua_assert((mask >> 1) == LUA_UTF8LIBK); | ||
62 | lua_pop(L, 1); // remove PRELOAD table | ||
64 | } | 63 | } |
65 | 64 | ||
@@ -16,21 +16,25 @@ | |||
16 | 16 | ||
17 | 17 | ||
18 | /* | 18 | /* |
19 | ** 'lu_mem' and 'l_mem' are unsigned/signed integers big enough to count | 19 | ** 'lu_mem' is an unsigned integer big enough to count the total memory |
20 | ** the total memory used by Lua (in bytes). Usually, 'size_t' and | 20 | ** used by Lua (in bytes). 'l_obj' is a signed integer big enough to |
21 | ** count the total number of objects used by Lua. (It is signed due | ||
22 | ** to the use of debt in several computations.) Usually, 'size_t' and | ||
21 | ** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines. | 23 | ** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines. |
22 | */ | 24 | */ |
23 | #if defined(LUAI_MEM) /* { external definitions? */ | 25 | #if defined(LUAI_MEM) /* { external definitions? */ |
24 | typedef LUAI_UMEM lu_mem; | 26 | typedef LUAI_UMEM lu_mem; |
25 | typedef LUAI_MEM l_mem; | 27 | typedef LUAI_MEM l_obj; |
26 | #elif LUAI_IS32INT /* }{ */ | 28 | #elif LUAI_IS32INT /* }{ */ |
27 | typedef size_t lu_mem; | 29 | typedef size_t lu_mem; |
28 | typedef ptrdiff_t l_mem; | 30 | typedef ptrdiff_t l_obj; |
29 | #else /* 16-bit ints */ /* }{ */ | 31 | #else /* 16-bit ints */ /* }{ */ |
30 | typedef unsigned long lu_mem; | 32 | typedef unsigned long lu_mem; |
31 | typedef long l_mem; | 33 | typedef long l_obj; |
32 | #endif /* } */ | 34 | #endif /* } */ |
33 | 35 | ||
36 | #define MAX_LOBJ cast(l_obj, ~cast(lu_mem, 0) >> 1) | ||
37 | |||
34 | 38 | ||
35 | /* chars used as small naturals (so that 'char' is reserved for characters) */ | 39 | /* chars used as small naturals (so that 'char' is reserved for characters) */ |
36 | typedef unsigned char lu_byte; | 40 | typedef unsigned char lu_byte; |
@@ -45,11 +49,6 @@ typedef signed char ls_byte; | |||
45 | : (size_t)(LUA_MAXINTEGER)) | 49 | : (size_t)(LUA_MAXINTEGER)) |
46 | 50 | ||
47 | 51 | ||
48 | #define MAX_LUMEM ((lu_mem)(~(lu_mem)0)) | ||
49 | |||
50 | #define MAX_LMEM ((l_mem)(MAX_LUMEM >> 1)) | ||
51 | |||
52 | |||
53 | #define MAX_INT INT_MAX /* maximum value of an int */ | 52 | #define MAX_INT INT_MAX /* maximum value of an int */ |
54 | 53 | ||
55 | 54 | ||
@@ -57,7 +56,7 @@ typedef signed char ls_byte; | |||
57 | ** floor of the log2 of the maximum signed value for integral type 't'. | 56 | ** floor of the log2 of the maximum signed value for integral type 't'. |
58 | ** (That is, maximum 'n' such that '2^n' fits in the given signed type.) | 57 | ** (That is, maximum 'n' such that '2^n' fits in the given signed type.) |
59 | */ | 58 | */ |
60 | #define log2maxs(t) (sizeof(t) * 8 - 2) | 59 | #define log2maxs(t) cast_int(sizeof(t) * 8 - 2) |
61 | 60 | ||
62 | 61 | ||
63 | /* | 62 | /* |
@@ -620,28 +620,18 @@ static void setseed (lua_State *L, Rand64 *state, | |||
620 | } | 620 | } |
621 | 621 | ||
622 | 622 | ||
623 | /* | ||
624 | ** Set a "random" seed. To get some randomness, use the current time | ||
625 | ** and the address of 'L' (in case the machine does address space layout | ||
626 | ** randomization). | ||
627 | */ | ||
628 | static void randseed (lua_State *L, RanState *state) { | ||
629 | lua_Unsigned seed1 = (lua_Unsigned)time(NULL); | ||
630 | lua_Unsigned seed2 = (lua_Unsigned)(size_t)L; | ||
631 | setseed(L, state->s, seed1, seed2); | ||
632 | } | ||
633 | |||
634 | |||
635 | static int math_randomseed (lua_State *L) { | 623 | static int math_randomseed (lua_State *L) { |
636 | RanState *state = (RanState *)lua_touserdata(L, lua_upvalueindex(1)); | 624 | RanState *state = (RanState *)lua_touserdata(L, lua_upvalueindex(1)); |
625 | lua_Unsigned n1, n2; | ||
637 | if (lua_isnone(L, 1)) { | 626 | if (lua_isnone(L, 1)) { |
638 | randseed(L, state); | 627 | n1 = luaL_makeseed(L); /* "random" seed */ |
628 | n2 = I2UInt(nextrand(state->s)); /* in case seed is not that random... */ | ||
639 | } | 629 | } |
640 | else { | 630 | else { |
641 | lua_Integer n1 = luaL_checkinteger(L, 1); | 631 | n1 = luaL_checkinteger(L, 1); |
642 | lua_Integer n2 = luaL_optinteger(L, 2, 0); | 632 | n2 = luaL_optinteger(L, 2, 0); |
643 | setseed(L, state->s, n1, n2); | ||
644 | } | 633 | } |
634 | setseed(L, state->s, n1, n2); | ||
645 | return 2; /* return seeds */ | 635 | return 2; /* return seeds */ |
646 | } | 636 | } |
647 | 637 | ||
@@ -658,7 +648,7 @@ static const luaL_Reg randfuncs[] = { | |||
658 | */ | 648 | */ |
659 | static void setrandfunc (lua_State *L) { | 649 | static void setrandfunc (lua_State *L) { |
660 | RanState *state = (RanState *)lua_newuserdatauv(L, sizeof(RanState), 0); | 650 | RanState *state = (RanState *)lua_newuserdatauv(L, sizeof(RanState), 0); |
661 | randseed(L, state); /* initialize with a "random" seed */ | 651 | setseed(L, state->s, luaL_makeseed(L), 0); /* initialize with random seed */ |
662 | lua_pop(L, 2); /* remove pushed seeds */ | 652 | lua_pop(L, 2); /* remove pushed seeds */ |
663 | luaL_setfuncs(L, randfuncs, 1); | 653 | luaL_setfuncs(L, randfuncs, 1); |
664 | } | 654 | } |
@@ -151,7 +151,7 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) { | |||
151 | global_State *g = G(L); | 151 | global_State *g = G(L); |
152 | lua_assert((osize == 0) == (block == NULL)); | 152 | lua_assert((osize == 0) == (block == NULL)); |
153 | callfrealloc(g, block, osize, 0); | 153 | callfrealloc(g, block, osize, 0); |
154 | g->GCdebt -= osize; | 154 | g->totalbytes -= osize; |
155 | } | 155 | } |
156 | 156 | ||
157 | 157 | ||
@@ -181,10 +181,10 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { | |||
181 | if (l_unlikely(newblock == NULL && nsize > 0)) { | 181 | if (l_unlikely(newblock == NULL && nsize > 0)) { |
182 | newblock = tryagain(L, block, osize, nsize); | 182 | newblock = tryagain(L, block, osize, nsize); |
183 | if (newblock == NULL) /* still no memory? */ | 183 | if (newblock == NULL) /* still no memory? */ |
184 | return NULL; /* do not update 'GCdebt' */ | 184 | return NULL; /* do not update 'totalbytes' */ |
185 | } | 185 | } |
186 | lua_assert((nsize == 0) == (newblock == NULL)); | 186 | lua_assert((nsize == 0) == (newblock == NULL)); |
187 | g->GCdebt = (g->GCdebt + nsize) - osize; | 187 | g->totalbytes += nsize - osize; |
188 | return newblock; | 188 | return newblock; |
189 | } | 189 | } |
190 | 190 | ||
@@ -209,7 +209,7 @@ void *luaM_malloc_ (lua_State *L, size_t size, int tag) { | |||
209 | if (newblock == NULL) | 209 | if (newblock == NULL) |
210 | luaM_error(L); | 210 | luaM_error(L); |
211 | } | 211 | } |
212 | g->GCdebt += size; | 212 | g->totalbytes += size; |
213 | return newblock; | 213 | return newblock; |
214 | } | 214 | } |
215 | } | 215 | } |
@@ -63,6 +63,8 @@ | |||
63 | 63 | ||
64 | #define luaM_newobject(L,tag,s) luaM_malloc_(L, (s), tag) | 64 | #define luaM_newobject(L,tag,s) luaM_malloc_(L, (s), tag) |
65 | 65 | ||
66 | #define luaM_newblock(L, size) luaM_newvector(L, size, char) | ||
67 | |||
66 | #define luaM_growvector(L,v,nelems,size,t,limit,e) \ | 68 | #define luaM_growvector(L,v,nelems,size,t,limit,e) \ |
67 | ((v)=cast(t *, luaM_growaux_(L,v,nelems,&(size),sizeof(t), \ | 69 | ((v)=cast(t *, luaM_growaux_(L,v,nelems,&(size),sizeof(t), \ |
68 | luaM_limitN(limit,t),e))) | 70 | luaM_limitN(limit,t),e))) |
@@ -394,7 +394,7 @@ typedef struct TString { | |||
394 | size_t lnglen; /* length for long strings */ | 394 | size_t lnglen; /* length for long strings */ |
395 | struct TString *hnext; /* linked list for hash table */ | 395 | struct TString *hnext; /* linked list for hash table */ |
396 | } u; | 396 | } u; |
397 | char contents[1]; | 397 | char contents[1]; /* string body starts here */ |
398 | } TString; | 398 | } TString; |
399 | 399 | ||
400 | 400 | ||
@@ -403,15 +403,22 @@ typedef struct TString { | |||
403 | ** Get the actual string (array of bytes) from a 'TString'. (Generic | 403 | ** Get the actual string (array of bytes) from a 'TString'. (Generic |
404 | ** version and specialized versions for long and short strings.) | 404 | ** version and specialized versions for long and short strings.) |
405 | */ | 405 | */ |
406 | #define getstr(ts) ((ts)->contents) | ||
407 | #define getlngstr(ts) check_exp((ts)->shrlen == 0xFF, (ts)->contents) | 406 | #define getlngstr(ts) check_exp((ts)->shrlen == 0xFF, (ts)->contents) |
408 | #define getshrstr(ts) check_exp((ts)->shrlen != 0xFF, (ts)->contents) | 407 | #define getshrstr(ts) check_exp((ts)->shrlen != 0xFF, (ts)->contents) |
408 | #define getstr(ts) ((ts)->contents) | ||
409 | 409 | ||
410 | 410 | ||
411 | /* get string length from 'TString *s' */ | 411 | /* get string length from 'TString *s' */ |
412 | #define tsslen(s) \ | 412 | #define tsslen(s) \ |
413 | ((s)->shrlen != 0xFF ? (s)->shrlen : (s)->u.lnglen) | 413 | ((s)->shrlen != 0xFF ? (s)->shrlen : (s)->u.lnglen) |
414 | 414 | ||
415 | /* | ||
416 | ** Get string and length */ | ||
417 | #define getlstr(ts, len) \ | ||
418 | ((ts)->shrlen != 0xFF \ | ||
419 | ? (cast_void(len = (ts)->shrlen), (ts)->contents) \ | ||
420 | : (cast_void(len = (ts)->u.lnglen), (ts)->contents)) | ||
421 | |||
415 | /* }================================================================== */ | 422 | /* }================================================================== */ |
416 | 423 | ||
417 | 424 | ||
@@ -546,13 +553,21 @@ typedef struct AbsLineInfo { | |||
546 | int line; | 553 | int line; |
547 | } AbsLineInfo; | 554 | } AbsLineInfo; |
548 | 555 | ||
556 | |||
557 | /* | ||
558 | ** Flags in Prototypes | ||
559 | */ | ||
560 | #define PF_ISVARARG 1 | ||
561 | #define PF_FIXED 2 /* prototype has parts in fixed memory */ | ||
562 | |||
563 | |||
549 | /* | 564 | /* |
550 | ** Function Prototypes | 565 | ** Function Prototypes |
551 | */ | 566 | */ |
552 | typedef struct Proto { | 567 | typedef struct Proto { |
553 | CommonHeader; | 568 | CommonHeader; |
554 | lu_byte numparams; /* number of fixed (named) parameters */ | 569 | lu_byte numparams; /* number of fixed (named) parameters */ |
555 | lu_byte is_vararg; | 570 | lu_byte flag; |
556 | lu_byte maxstacksize; /* number of registers needed by this function */ | 571 | lu_byte maxstacksize; /* number of registers needed by this function */ |
557 | int sizeupvalues; /* size of 'upvalues' */ | 572 | int sizeupvalues; /* size of 'upvalues' */ |
558 | int sizek; /* size of 'k' */ | 573 | int sizek; /* size of 'k' */ |
@@ -746,7 +761,6 @@ typedef struct Table { | |||
746 | unsigned int alimit; /* "limit" of 'array' array */ | 761 | unsigned int alimit; /* "limit" of 'array' array */ |
747 | ArrayCell *array; /* array part */ | 762 | ArrayCell *array; /* array part */ |
748 | Node *node; | 763 | Node *node; |
749 | Node *lastfree; /* any free position is before this position */ | ||
750 | struct Table *metatable; | 764 | struct Table *metatable; |
751 | GCObject *gclist; | 765 | GCObject *gclist; |
752 | } Table; | 766 | } Table; |
@@ -187,10 +187,10 @@ static int registerlocalvar (LexState *ls, FuncState *fs, TString *varname) { | |||
187 | 187 | ||
188 | 188 | ||
189 | /* | 189 | /* |
190 | ** Create a new local variable with the given 'name'. Return its index | 190 | ** Create a new local variable with the given 'name' and given 'kind'. |
191 | ** in the function. | 191 | ** Return its index in the function. |
192 | */ | 192 | */ |
193 | static int new_localvar (LexState *ls, TString *name) { | 193 | static int new_localvarkind (LexState *ls, TString *name, int kind) { |
194 | lua_State *L = ls->L; | 194 | lua_State *L = ls->L; |
195 | FuncState *fs = ls->fs; | 195 | FuncState *fs = ls->fs; |
196 | Dyndata *dyd = ls->dyd; | 196 | Dyndata *dyd = ls->dyd; |
@@ -200,11 +200,19 @@ static int new_localvar (LexState *ls, TString *name) { | |||
200 | luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1, | 200 | luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1, |
201 | dyd->actvar.size, Vardesc, USHRT_MAX, "local variables"); | 201 | dyd->actvar.size, Vardesc, USHRT_MAX, "local variables"); |
202 | var = &dyd->actvar.arr[dyd->actvar.n++]; | 202 | var = &dyd->actvar.arr[dyd->actvar.n++]; |
203 | var->vd.kind = VDKREG; /* default */ | 203 | var->vd.kind = kind; /* default */ |
204 | var->vd.name = name; | 204 | var->vd.name = name; |
205 | return dyd->actvar.n - 1 - fs->firstlocal; | 205 | return dyd->actvar.n - 1 - fs->firstlocal; |
206 | } | 206 | } |
207 | 207 | ||
208 | |||
209 | /* | ||
210 | ** Create a new local variable with the given 'name' and regular kind. | ||
211 | */ | ||
212 | static int new_localvar (LexState *ls, TString *name) { | ||
213 | return new_localvarkind(ls, name, VDKREG); | ||
214 | } | ||
215 | |||
208 | #define new_localvarliteral(ls,v) \ | 216 | #define new_localvarliteral(ls,v) \ |
209 | new_localvar(ls, \ | 217 | new_localvar(ls, \ |
210 | luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char)) - 1)); | 218 | luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char)) - 1)); |
@@ -512,7 +520,8 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { | |||
512 | ** local variable. | 520 | ** local variable. |
513 | */ | 521 | */ |
514 | static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) { | 522 | static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) { |
515 | const char *varname = getstr(getlocalvardesc(ls->fs, gt->nactvar)->vd.name); | 523 | TString *tsname = getlocalvardesc(ls->fs, gt->nactvar)->vd.name; |
524 | const char *varname = getstr(tsname); | ||
516 | const char *msg = "<goto %s> at line %d jumps into the scope of local '%s'"; | 525 | const char *msg = "<goto %s> at line %d jumps into the scope of local '%s'"; |
517 | msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line, varname); | 526 | msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line, varname); |
518 | luaK_semerror(ls, msg); /* raise the error */ | 527 | luaK_semerror(ls, msg); /* raise the error */ |
@@ -951,7 +960,7 @@ static void constructor (LexState *ls, expdesc *t) { | |||
951 | 960 | ||
952 | 961 | ||
953 | static void setvararg (FuncState *fs, int nparams) { | 962 | static void setvararg (FuncState *fs, int nparams) { |
954 | fs->f->is_vararg = 1; | 963 | fs->f->flag |= PF_ISVARARG; |
955 | luaK_codeABC(fs, OP_VARARGPREP, nparams, 0, 0); | 964 | luaK_codeABC(fs, OP_VARARGPREP, nparams, 0, 0); |
956 | } | 965 | } |
957 | 966 | ||
@@ -1169,7 +1178,7 @@ static void simpleexp (LexState *ls, expdesc *v) { | |||
1169 | } | 1178 | } |
1170 | case TK_DOTS: { /* vararg */ | 1179 | case TK_DOTS: { /* vararg */ |
1171 | FuncState *fs = ls->fs; | 1180 | FuncState *fs = ls->fs; |
1172 | check_condition(ls, fs->f->is_vararg, | 1181 | check_condition(ls, fs->f->flag & PF_ISVARARG, |
1173 | "cannot use '...' outside a vararg function"); | 1182 | "cannot use '...' outside a vararg function"); |
1174 | init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 0, 1)); | 1183 | init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 0, 1)); |
1175 | break; | 1184 | break; |
@@ -1550,6 +1559,7 @@ static void forbody (LexState *ls, int base, int line, int nvars, int isgen) { | |||
1550 | int prep, endfor; | 1559 | int prep, endfor; |
1551 | checknext(ls, TK_DO); | 1560 | checknext(ls, TK_DO); |
1552 | prep = luaK_codeABx(fs, forprep[isgen], base, 0); | 1561 | prep = luaK_codeABx(fs, forprep[isgen], base, 0); |
1562 | fs->freereg--; /* both 'forprep' remove one register from the stack */ | ||
1553 | enterblock(fs, &bl, 0); /* scope for declared variables */ | 1563 | enterblock(fs, &bl, 0); /* scope for declared variables */ |
1554 | adjustlocalvars(ls, nvars); | 1564 | adjustlocalvars(ls, nvars); |
1555 | luaK_reserveregs(fs, nvars); | 1565 | luaK_reserveregs(fs, nvars); |
@@ -1572,8 +1582,7 @@ static void fornum (LexState *ls, TString *varname, int line) { | |||
1572 | int base = fs->freereg; | 1582 | int base = fs->freereg; |
1573 | new_localvarliteral(ls, "(for state)"); | 1583 | new_localvarliteral(ls, "(for state)"); |
1574 | new_localvarliteral(ls, "(for state)"); | 1584 | new_localvarliteral(ls, "(for state)"); |
1575 | new_localvarliteral(ls, "(for state)"); | 1585 | new_localvarkind(ls, varname, RDKCONST); /* control variable */ |
1576 | new_localvar(ls, varname); | ||
1577 | checknext(ls, '='); | 1586 | checknext(ls, '='); |
1578 | exp1(ls); /* initial value */ | 1587 | exp1(ls); /* initial value */ |
1579 | checknext(ls, ','); | 1588 | checknext(ls, ','); |
@@ -1584,7 +1593,7 @@ static void fornum (LexState *ls, TString *varname, int line) { | |||
1584 | luaK_int(fs, fs->freereg, 1); | 1593 | luaK_int(fs, fs->freereg, 1); |
1585 | luaK_reserveregs(fs, 1); | 1594 | luaK_reserveregs(fs, 1); |
1586 | } | 1595 | } |
1587 | adjustlocalvars(ls, 3); /* control variables */ | 1596 | adjustlocalvars(ls, 2); /* start scope for internal variables */ |
1588 | forbody(ls, base, line, 1, 0); | 1597 | forbody(ls, base, line, 1, 0); |
1589 | } | 1598 | } |
1590 | 1599 | ||
@@ -1593,16 +1602,15 @@ static void forlist (LexState *ls, TString *indexname) { | |||
1593 | /* forlist -> NAME {,NAME} IN explist forbody */ | 1602 | /* forlist -> NAME {,NAME} IN explist forbody */ |
1594 | FuncState *fs = ls->fs; | 1603 | FuncState *fs = ls->fs; |
1595 | expdesc e; | 1604 | expdesc e; |
1596 | int nvars = 5; /* gen, state, control, toclose, 'indexname' */ | 1605 | int nvars = 4; /* function, state, closing, control */ |
1597 | int line; | 1606 | int line; |
1598 | int base = fs->freereg; | 1607 | int base = fs->freereg; |
1599 | /* create control variables */ | 1608 | /* create internal variables */ |
1600 | new_localvarliteral(ls, "(for state)"); | 1609 | new_localvarliteral(ls, "(for state)"); /* iterator function */ |
1601 | new_localvarliteral(ls, "(for state)"); | 1610 | new_localvarliteral(ls, "(for state)"); /* state */ |
1602 | new_localvarliteral(ls, "(for state)"); | 1611 | new_localvarliteral(ls, "(for state)"); /* closing var. (after swap) */ |
1603 | new_localvarliteral(ls, "(for state)"); | 1612 | new_localvarkind(ls, indexname, RDKCONST); /* control variable */ |
1604 | /* create declared variables */ | 1613 | /* other declared variables */ |
1605 | new_localvar(ls, indexname); | ||
1606 | while (testnext(ls, ',')) { | 1614 | while (testnext(ls, ',')) { |
1607 | new_localvar(ls, str_checkname(ls)); | 1615 | new_localvar(ls, str_checkname(ls)); |
1608 | nvars++; | 1616 | nvars++; |
@@ -1610,10 +1618,10 @@ static void forlist (LexState *ls, TString *indexname) { | |||
1610 | checknext(ls, TK_IN); | 1618 | checknext(ls, TK_IN); |
1611 | line = ls->linenumber; | 1619 | line = ls->linenumber; |
1612 | adjust_assign(ls, 4, explist(ls, &e), &e); | 1620 | adjust_assign(ls, 4, explist(ls, &e), &e); |
1613 | adjustlocalvars(ls, 4); /* control variables */ | 1621 | adjustlocalvars(ls, 3); /* start scope for internal variables */ |
1614 | marktobeclosed(fs); /* last control var. must be closed */ | 1622 | marktobeclosed(fs); /* last internal var. must be closed */ |
1615 | luaK_checkstack(fs, 3); /* extra space to call generator */ | 1623 | luaK_checkstack(fs, 2); /* extra space to call iterator */ |
1616 | forbody(ls, base, line, nvars - 4, 1); | 1624 | forbody(ls, base, line, nvars - 3, 1); |
1617 | } | 1625 | } |
1618 | 1626 | ||
1619 | 1627 | ||
@@ -1701,7 +1709,8 @@ static void localfunc (LexState *ls) { | |||
1701 | static int getlocalattribute (LexState *ls) { | 1709 | static int getlocalattribute (LexState *ls) { |
1702 | /* ATTRIB -> ['<' Name '>'] */ | 1710 | /* ATTRIB -> ['<' Name '>'] */ |
1703 | if (testnext(ls, '<')) { | 1711 | if (testnext(ls, '<')) { |
1704 | const char *attr = getstr(str_checkname(ls)); | 1712 | TString *ts = str_checkname(ls); |
1713 | const char *attr = getstr(ts); | ||
1705 | checknext(ls, '>'); | 1714 | checknext(ls, '>'); |
1706 | if (strcmp(attr, "const") == 0) | 1715 | if (strcmp(attr, "const") == 0) |
1707 | return RDKCONST; /* read-only variable */ | 1716 | return RDKCONST; /* read-only variable */ |
@@ -1728,14 +1737,14 @@ static void localstat (LexState *ls) { | |||
1728 | FuncState *fs = ls->fs; | 1737 | FuncState *fs = ls->fs; |
1729 | int toclose = -1; /* index of to-be-closed variable (if any) */ | 1738 | int toclose = -1; /* index of to-be-closed variable (if any) */ |
1730 | Vardesc *var; /* last variable */ | 1739 | Vardesc *var; /* last variable */ |
1731 | int vidx, kind; /* index and kind of last variable */ | 1740 | int vidx; /* index of last variable */ |
1732 | int nvars = 0; | 1741 | int nvars = 0; |
1733 | int nexps; | 1742 | int nexps; |
1734 | expdesc e; | 1743 | expdesc e; |
1735 | do { | 1744 | do { |
1736 | vidx = new_localvar(ls, str_checkname(ls)); | 1745 | TString *vname = str_checkname(ls); |
1737 | kind = getlocalattribute(ls); | 1746 | int kind = getlocalattribute(ls); |
1738 | getlocalvardesc(fs, vidx)->vd.kind = kind; | 1747 | vidx = new_localvarkind(ls, vname, kind); |
1739 | if (kind == RDKTOCLOSE) { /* to-be-closed? */ | 1748 | if (kind == RDKTOCLOSE) { /* to-be-closed? */ |
1740 | if (toclose != -1) /* one already present? */ | 1749 | if (toclose != -1) /* one already present? */ |
1741 | luaK_semerror(ls, "multiple to-be-closed variables in local list"); | 1750 | luaK_semerror(ls, "multiple to-be-closed variables in local list"); |
@@ -52,46 +52,15 @@ typedef struct LG { | |||
52 | 52 | ||
53 | 53 | ||
54 | /* | 54 | /* |
55 | ** A macro to create a "random" seed when a state is created; | 55 | ** set GCdebt to a new value keeping the value (totalobjs + GCdebt) |
56 | ** the seed is used to randomize string hashes. | 56 | ** invariant (and avoiding underflows in 'totalobjs') |
57 | */ | 57 | */ |
58 | #if !defined(luai_makeseed) | 58 | void luaE_setdebt (global_State *g, l_obj debt) { |
59 | 59 | l_obj tb = gettotalobjs(g); | |
60 | #include <time.h> | ||
61 | |||
62 | /* | ||
63 | ** Compute an initial seed with some level of randomness. | ||
64 | ** Rely on Address Space Layout Randomization (if present) and | ||
65 | ** current time. | ||
66 | */ | ||
67 | #define addbuff(b,p,e) \ | ||
68 | { size_t t = cast_sizet(e); \ | ||
69 | memcpy(b + p, &t, sizeof(t)); p += sizeof(t); } | ||
70 | |||
71 | static unsigned int luai_makeseed (lua_State *L) { | ||
72 | char buff[3 * sizeof(size_t)]; | ||
73 | unsigned int h = cast_uint(time(NULL)); | ||
74 | int p = 0; | ||
75 | addbuff(buff, p, L); /* heap variable */ | ||
76 | addbuff(buff, p, &h); /* local variable */ | ||
77 | addbuff(buff, p, &lua_newstate); /* public function */ | ||
78 | lua_assert(p == sizeof(buff)); | ||
79 | return luaS_hash(buff, p, h); | ||
80 | } | ||
81 | |||
82 | #endif | ||
83 | |||
84 | |||
85 | /* | ||
86 | ** set GCdebt to a new value keeping the value (totalbytes + GCdebt) | ||
87 | ** invariant (and avoiding underflows in 'totalbytes') | ||
88 | */ | ||
89 | void luaE_setdebt (global_State *g, l_mem debt) { | ||
90 | l_mem tb = gettotalbytes(g); | ||
91 | lua_assert(tb > 0); | 60 | lua_assert(tb > 0); |
92 | if (debt < tb - MAX_LMEM) | 61 | if (debt > MAX_LOBJ - tb) |
93 | debt = tb - MAX_LMEM; /* will make 'totalbytes == MAX_LMEM' */ | 62 | debt = MAX_LOBJ - tb; /* will make 'totalobjs == MAX_LMEM' */ |
94 | g->totalbytes = tb - debt; | 63 | g->totalobjs = tb + debt; |
95 | g->GCdebt = debt; | 64 | g->GCdebt = debt; |
96 | } | 65 | } |
97 | 66 | ||
@@ -281,7 +250,8 @@ static void close_state (lua_State *L) { | |||
281 | } | 250 | } |
282 | luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); | 251 | luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); |
283 | freestack(L); | 252 | freestack(L); |
284 | lua_assert(gettotalbytes(g) == sizeof(LG)); | 253 | lua_assert(g->totalbytes == sizeof(LG)); |
254 | lua_assert(gettotalobjs(g) == 1); | ||
285 | (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ | 255 | (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ |
286 | } | 256 | } |
287 | 257 | ||
@@ -352,15 +322,7 @@ LUA_API int lua_closethread (lua_State *L, lua_State *from) { | |||
352 | } | 322 | } |
353 | 323 | ||
354 | 324 | ||
355 | /* | 325 | LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud, unsigned int seed) { |
356 | ** Deprecated! Use 'lua_closethread' instead. | ||
357 | */ | ||
358 | LUA_API int lua_resetthread (lua_State *L) { | ||
359 | return lua_closethread(L, NULL); | ||
360 | } | ||
361 | |||
362 | |||
363 | LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | ||
364 | int i; | 326 | int i; |
365 | lua_State *L; | 327 | lua_State *L; |
366 | global_State *g; | 328 | global_State *g; |
@@ -380,7 +342,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
380 | g->warnf = NULL; | 342 | g->warnf = NULL; |
381 | g->ud_warn = NULL; | 343 | g->ud_warn = NULL; |
382 | g->mainthread = L; | 344 | g->mainthread = L; |
383 | g->seed = luai_makeseed(L); | 345 | g->seed = seed; |
384 | g->gcstp = GCSTPGC; /* no GC while building state */ | 346 | g->gcstp = GCSTPGC; /* no GC while building state */ |
385 | g->strt.size = g->strt.nuse = 0; | 347 | g->strt.size = g->strt.nuse = 0; |
386 | g->strt.hash = NULL; | 348 | g->strt.hash = NULL; |
@@ -398,14 +360,15 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
398 | g->weak = g->ephemeron = g->allweak = NULL; | 360 | g->weak = g->ephemeron = g->allweak = NULL; |
399 | g->twups = NULL; | 361 | g->twups = NULL; |
400 | g->totalbytes = sizeof(LG); | 362 | g->totalbytes = sizeof(LG); |
363 | g->totalobjs = 1; | ||
364 | g->marked = 0; | ||
401 | g->GCdebt = 0; | 365 | g->GCdebt = 0; |
402 | g->lastatomic = 0; | ||
403 | setivalue(&g->nilvalue, 0); /* to signal that state is not yet built */ | 366 | setivalue(&g->nilvalue, 0); /* to signal that state is not yet built */ |
404 | setgcparam(g->gcpause, LUAI_GCPAUSE); | 367 | setgcparam(g, gcpause, LUAI_GCPAUSE); |
405 | setgcparam(g->gcstepmul, LUAI_GCMUL); | 368 | setgcparam(g, gcstepmul, LUAI_GCMUL); |
406 | g->gcstepsize = LUAI_GCSTEPSIZE; | 369 | g->gcstepsize = LUAI_GCSTEPSIZE; |
407 | setgcparam(g->genmajormul, LUAI_GENMAJORMUL); | 370 | setgcparam(g, genmajormul, LUAI_GENMAJORMUL); |
408 | g->genminormul = LUAI_GENMINORMUL; | 371 | setgcparam(g, genminormul, LUAI_GENMINORMUL); |
409 | for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; | 372 | for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; |
410 | if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { | 373 | if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { |
411 | /* memory allocation error: free partial state */ | 374 | /* memory allocation error: free partial state */ |
@@ -150,12 +150,13 @@ struct lua_longjmp; /* defined in ldo.c */ | |||
150 | /* kinds of Garbage Collection */ | 150 | /* kinds of Garbage Collection */ |
151 | #define KGC_INC 0 /* incremental gc */ | 151 | #define KGC_INC 0 /* incremental gc */ |
152 | #define KGC_GEN 1 /* generational gc */ | 152 | #define KGC_GEN 1 /* generational gc */ |
153 | #define KGC_GENMAJOR 2 /* generational in "major" mode */ | ||
153 | 154 | ||
154 | 155 | ||
155 | typedef struct stringtable { | 156 | typedef struct stringtable { |
156 | TString **hash; | 157 | TString **hash; /* array of buckets (linked lists of strings) */ |
157 | int nuse; /* number of elements */ | 158 | int nuse; /* number of elements */ |
158 | int size; | 159 | int size; /* number of buckets */ |
159 | } stringtable; | 160 | } stringtable; |
160 | 161 | ||
161 | 162 | ||
@@ -254,10 +255,11 @@ struct CallInfo { | |||
254 | typedef struct global_State { | 255 | typedef struct global_State { |
255 | lua_Alloc frealloc; /* function to reallocate memory */ | 256 | lua_Alloc frealloc; /* function to reallocate memory */ |
256 | void *ud; /* auxiliary data to 'frealloc' */ | 257 | void *ud; /* auxiliary data to 'frealloc' */ |
257 | l_mem totalbytes; /* number of bytes currently allocated - GCdebt */ | 258 | lu_mem totalbytes; /* number of bytes currently allocated */ |
258 | l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ | 259 | l_obj totalobjs; /* total number of objects allocated + GCdebt */ |
259 | lu_mem GCestimate; /* an estimate of the non-garbage memory in use */ | 260 | l_obj GCdebt; /* objects counted but not yet allocated */ |
260 | lu_mem lastatomic; /* see function 'genstep' in file 'lgc.c' */ | 261 | l_obj marked; /* number of objects marked in a GC cycle */ |
262 | l_obj GClastmajor; /* objects at last major collection */ | ||
261 | stringtable strt; /* hash table for strings */ | 263 | stringtable strt; /* hash table for strings */ |
262 | TValue l_registry; | 264 | TValue l_registry; |
263 | TValue nilvalue; /* a nil value */ | 265 | TValue nilvalue; /* a nil value */ |
@@ -390,10 +392,11 @@ union GCUnion { | |||
390 | #define obj2gco(v) check_exp((v)->tt >= LUA_TSTRING, &(cast_u(v)->gc)) | 392 | #define obj2gco(v) check_exp((v)->tt >= LUA_TSTRING, &(cast_u(v)->gc)) |
391 | 393 | ||
392 | 394 | ||
393 | /* actual number of total bytes allocated */ | 395 | /* actual number of total objects allocated */ |
394 | #define gettotalbytes(g) cast(lu_mem, (g)->totalbytes + (g)->GCdebt) | 396 | #define gettotalobjs(g) ((g)->totalobjs - (g)->GCdebt) |
395 | 397 | ||
396 | LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt); | 398 | |
399 | LUAI_FUNC void luaE_setdebt (global_State *g, l_obj debt); | ||
397 | LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); | 400 | LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); |
398 | LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); | 401 | LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); |
399 | LUAI_FUNC void luaE_shrinkCI (lua_State *L); | 402 | LUAI_FUNC void luaE_shrinkCI (lua_State *L); |
@@ -239,6 +239,7 @@ static int str_dump (lua_State *L) { | |||
239 | if (l_unlikely(lua_dump(L, writer, &state, strip) != 0)) | 239 | if (l_unlikely(lua_dump(L, writer, &state, strip) != 0)) |
240 | return luaL_error(L, "unable to dump given function"); | 240 | return luaL_error(L, "unable to dump given function"); |
241 | luaL_pushresult(&state.B); | 241 | luaL_pushresult(&state.B); |
242 | lua_assert(lua_isfunction(L, 1)); /* lua_dump kept that value */ | ||
242 | return 1; | 243 | return 1; |
243 | } | 244 | } |
244 | 245 | ||
@@ -40,6 +40,27 @@ | |||
40 | 40 | ||
41 | 41 | ||
42 | /* | 42 | /* |
43 | ** Only tables with hash parts larget than LIMFORLAST has a 'lastfree' | ||
44 | ** field that optimizes finding a free slot. Smaller tables do a | ||
45 | ** complete search when looking for a free slot. | ||
46 | */ | ||
47 | #define LLIMFORLAST 2 /* log2 of LIMTFORLAST */ | ||
48 | #define LIMFORLAST twoto(LLIMFORLAST) | ||
49 | |||
50 | /* | ||
51 | ** Union to store an int field ensuring that what follows it in | ||
52 | ** memory is properly aligned to store a TValue. | ||
53 | */ | ||
54 | typedef union { | ||
55 | int lastfree; | ||
56 | char padding[offsetof(struct { int i; TValue v; }, v)]; | ||
57 | } Limbox; | ||
58 | |||
59 | #define haslastfree(t) ((t)->lsizenode > LLIMFORLAST) | ||
60 | #define getlastfree(t) (&((cast(Limbox *, (t)->node) - 1)->lastfree)) | ||
61 | |||
62 | |||
63 | /* | ||
43 | ** MAXABITS is the largest integer such that MAXASIZE fits in an | 64 | ** MAXABITS is the largest integer such that MAXASIZE fits in an |
44 | ** unsigned int. | 65 | ** unsigned int. |
45 | */ | 66 | */ |
@@ -370,8 +391,15 @@ int luaH_next (lua_State *L, Table *t, StkId key) { | |||
370 | 391 | ||
371 | 392 | ||
372 | static void freehash (lua_State *L, Table *t) { | 393 | static void freehash (lua_State *L, Table *t) { |
373 | if (!isdummy(t)) | 394 | if (!isdummy(t)) { |
374 | luaM_freearray(L, t->node, cast_sizet(sizenode(t))); | 395 | size_t bsize = sizenode(t) * sizeof(Node); /* 'node' size in bytes */ |
396 | char *arr = cast_charp(t->node); | ||
397 | if (haslastfree(t)) { | ||
398 | bsize += sizeof(Limbox); | ||
399 | arr -= sizeof(Limbox); | ||
400 | } | ||
401 | luaM_freearray(L, arr, bsize); | ||
402 | } | ||
375 | } | 403 | } |
376 | 404 | ||
377 | 405 | ||
@@ -550,7 +578,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) { | |||
550 | if (size == 0) { /* no elements to hash part? */ | 578 | if (size == 0) { /* no elements to hash part? */ |
551 | t->node = cast(Node *, dummynode); /* use common 'dummynode' */ | 579 | t->node = cast(Node *, dummynode); /* use common 'dummynode' */ |
552 | t->lsizenode = 0; | 580 | t->lsizenode = 0; |
553 | t->lastfree = NULL; /* signal that it is using dummy node */ | 581 | setdummy(t); /* signal that it is using dummy node */ |
554 | } | 582 | } |
555 | else { | 583 | else { |
556 | int i; | 584 | int i; |
@@ -558,15 +586,22 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) { | |||
558 | if (lsize > MAXHBITS || (1u << lsize) > MAXHSIZE) | 586 | if (lsize > MAXHBITS || (1u << lsize) > MAXHSIZE) |
559 | luaG_runerror(L, "table overflow"); | 587 | luaG_runerror(L, "table overflow"); |
560 | size = twoto(lsize); | 588 | size = twoto(lsize); |
561 | t->node = luaM_newvector(L, size, Node); | 589 | if (lsize <= LLIMFORLAST) /* no 'lastfree' field? */ |
590 | t->node = luaM_newvector(L, size, Node); | ||
591 | else { | ||
592 | size_t bsize = size * sizeof(Node) + sizeof(Limbox); | ||
593 | char *node = luaM_newblock(L, bsize); | ||
594 | t->node = cast(Node *, node + sizeof(Limbox)); | ||
595 | *getlastfree(t) = size; /* all positions are free */ | ||
596 | } | ||
597 | t->lsizenode = cast_byte(lsize); | ||
598 | setnodummy(t); | ||
562 | for (i = 0; i < cast_int(size); i++) { | 599 | for (i = 0; i < cast_int(size); i++) { |
563 | Node *n = gnode(t, i); | 600 | Node *n = gnode(t, i); |
564 | gnext(n) = 0; | 601 | gnext(n) = 0; |
565 | setnilkey(n); | 602 | setnilkey(n); |
566 | setempty(gval(n)); | 603 | setempty(gval(n)); |
567 | } | 604 | } |
568 | t->lsizenode = cast_byte(lsize); | ||
569 | t->lastfree = gnode(t, size); /* all positions are free */ | ||
570 | } | 605 | } |
571 | } | 606 | } |
572 | 607 | ||
@@ -591,18 +626,21 @@ static void reinsert (lua_State *L, Table *ot, Table *t) { | |||
591 | 626 | ||
592 | 627 | ||
593 | /* | 628 | /* |
594 | ** Exchange the hash part of 't1' and 't2'. | 629 | ** Exchange the hash part of 't1' and 't2'. (In 'flags', only the |
630 | ** dummy bit must be exchanged: The 'isrealasize' is not related | ||
631 | ** to the hash part, and the metamethod bits do not change during | ||
632 | ** a resize, so the "real" table can keep their values.) | ||
595 | */ | 633 | */ |
596 | static void exchangehashpart (Table *t1, Table *t2) { | 634 | static void exchangehashpart (Table *t1, Table *t2) { |
597 | lu_byte lsizenode = t1->lsizenode; | 635 | lu_byte lsizenode = t1->lsizenode; |
598 | Node *node = t1->node; | 636 | Node *node = t1->node; |
599 | Node *lastfree = t1->lastfree; | 637 | int bitdummy1 = t1->flags & BITDUMMY; |
600 | t1->lsizenode = t2->lsizenode; | 638 | t1->lsizenode = t2->lsizenode; |
601 | t1->node = t2->node; | 639 | t1->node = t2->node; |
602 | t1->lastfree = t2->lastfree; | 640 | t1->flags = (t1->flags & NOTBITDUMMY) | (t2->flags & BITDUMMY); |
603 | t2->lsizenode = lsizenode; | 641 | t2->lsizenode = lsizenode; |
604 | t2->node = node; | 642 | t2->node = node; |
605 | t2->lastfree = lastfree; | 643 | t2->flags = (t2->flags & NOTBITDUMMY) | bitdummy1; |
606 | } | 644 | } |
607 | 645 | ||
608 | 646 | ||
@@ -626,6 +664,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize, | |||
626 | unsigned int oldasize = setlimittosize(t); | 664 | unsigned int oldasize = setlimittosize(t); |
627 | ArrayCell *newarray; | 665 | ArrayCell *newarray; |
628 | /* create new hash part with appropriate size into 'newt' */ | 666 | /* create new hash part with appropriate size into 'newt' */ |
667 | newt.flags = 0; | ||
629 | setnodevector(L, &newt, nhsize); | 668 | setnodevector(L, &newt, nhsize); |
630 | if (newasize < oldasize) { /* will array shrink? */ | 669 | if (newasize < oldasize) { /* will array shrink? */ |
631 | t->alimit = newasize; /* pretend array has new size... */ | 670 | t->alimit = newasize; /* pretend array has new size... */ |
@@ -717,11 +756,22 @@ void luaH_free (lua_State *L, Table *t) { | |||
717 | 756 | ||
718 | 757 | ||
719 | static Node *getfreepos (Table *t) { | 758 | static Node *getfreepos (Table *t) { |
720 | if (!isdummy(t)) { | 759 | if (haslastfree(t)) { /* does it have 'lastfree' information? */ |
721 | while (t->lastfree > t->node) { | 760 | /* look for a spot before 'lastfree', updating 'lastfree' */ |
722 | t->lastfree--; | 761 | while (*getlastfree(t) > 0) { |
723 | if (keyisnil(t->lastfree)) | 762 | Node *free = gnode(t, --(*getlastfree(t))); |
724 | return t->lastfree; | 763 | if (keyisnil(free)) |
764 | return free; | ||
765 | } | ||
766 | } | ||
767 | else { /* no 'lastfree' information */ | ||
768 | if (!isdummy(t)) { | ||
769 | int i = sizenode(t); | ||
770 | while (i--) { /* do a linear search */ | ||
771 | Node *free = gnode(t, i); | ||
772 | if (keyisnil(free)) | ||
773 | return free; | ||
774 | } | ||
725 | } | 775 | } |
726 | } | 776 | } |
727 | return NULL; /* could not find a free place */ | 777 | return NULL; /* could not find a free place */ |
@@ -23,8 +23,18 @@ | |||
23 | #define invalidateTMcache(t) ((t)->flags &= ~maskflags) | 23 | #define invalidateTMcache(t) ((t)->flags &= ~maskflags) |
24 | 24 | ||
25 | 25 | ||
26 | /* true when 't' is using 'dummynode' as its hash part */ | 26 | /* |
27 | #define isdummy(t) ((t)->lastfree == NULL) | 27 | ** Bit BITDUMMY set in 'flags' means the table is using the dummy node |
28 | ** for its hash part. | ||
29 | */ | ||
30 | |||
31 | #define BITDUMMY (1 << 6) | ||
32 | #define NOTBITDUMMY cast_byte(~BITDUMMY) | ||
33 | #define isdummy(t) ((t)->flags & BITDUMMY) | ||
34 | |||
35 | #define setnodummy(t) ((t)->flags &= NOTBITDUMMY) | ||
36 | #define setdummy(t) ((t)->flags |= BITDUMMY) | ||
37 | |||
28 | 38 | ||
29 | 39 | ||
30 | /* allocated size for hash nodes */ | 40 | /* allocated size for hash nodes */ |
@@ -230,31 +230,8 @@ typedef unsigned int IdxT; | |||
230 | ** of a partition. (If you don't want/need this "randomness", ~0 is a | 230 | ** of a partition. (If you don't want/need this "randomness", ~0 is a |
231 | ** good choice.) | 231 | ** good choice.) |
232 | */ | 232 | */ |
233 | #if !defined(l_randomizePivot) /* { */ | 233 | #if !defined(l_randomizePivot) |
234 | 234 | #define l_randomizePivot(L) luaL_makeseed(L) | |
235 | #include <time.h> | ||
236 | |||
237 | /* size of 'e' measured in number of 'unsigned int's */ | ||
238 | #define sof(e) (sizeof(e) / sizeof(unsigned int)) | ||
239 | |||
240 | /* | ||
241 | ** Use 'time' and 'clock' as sources of "randomness". Because we don't | ||
242 | ** know the types 'clock_t' and 'time_t', we cannot cast them to | ||
243 | ** anything without risking overflows. A safe way to use their values | ||
244 | ** is to copy them to an array of a known type and use the array values. | ||
245 | */ | ||
246 | static unsigned int l_randomizePivot (void) { | ||
247 | clock_t c = clock(); | ||
248 | time_t t = time(NULL); | ||
249 | unsigned int buff[sof(c) + sof(t)]; | ||
250 | unsigned int i, rnd = 0; | ||
251 | memcpy(buff, &c, sof(c) * sizeof(unsigned int)); | ||
252 | memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int)); | ||
253 | for (i = 0; i < sof(buff); i++) | ||
254 | rnd += buff[i]; | ||
255 | return rnd; | ||
256 | } | ||
257 | |||
258 | #endif /* } */ | 235 | #endif /* } */ |
259 | 236 | ||
260 | 237 | ||
@@ -333,7 +310,7 @@ static IdxT partition (lua_State *L, IdxT lo, IdxT up) { | |||
333 | */ | 310 | */ |
334 | static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) { | 311 | static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) { |
335 | IdxT r4 = (up - lo) / 4; /* range/4 */ | 312 | IdxT r4 = (up - lo) / 4; /* range/4 */ |
336 | IdxT p = rnd % (r4 * 2) + (lo + r4); | 313 | IdxT p = (rnd ^ lo ^ up) % (r4 * 2) + (lo + r4); |
337 | lua_assert(lo + r4 <= p && p <= up - r4); | 314 | lua_assert(lo + r4 <= p && p <= up - r4); |
338 | return p; | 315 | return p; |
339 | } | 316 | } |
@@ -391,7 +368,7 @@ static void auxsort (lua_State *L, IdxT lo, IdxT up, | |||
391 | up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */ | 368 | up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */ |
392 | } | 369 | } |
393 | if ((up - lo) / 128 > n) /* partition too imbalanced? */ | 370 | if ((up - lo) / 128 > n) /* partition too imbalanced? */ |
394 | rnd = l_randomizePivot(); /* try a new randomization */ | 371 | rnd = l_randomizePivot(L); /* try a new randomization */ |
395 | } /* tail call auxsort(L, lo, up, rnd) */ | 372 | } /* tail call auxsort(L, lo, up, rnd) */ |
396 | } | 373 | } |
397 | 374 | ||
@@ -297,7 +297,7 @@ static int testobjref1 (global_State *g, GCObject *f, GCObject *t) { | |||
297 | if (isdead(g,t)) return 0; | 297 | if (isdead(g,t)) return 0; |
298 | if (issweepphase(g)) | 298 | if (issweepphase(g)) |
299 | return 1; /* no invariants */ | 299 | return 1; /* no invariants */ |
300 | else if (g->gckind == KGC_INC) | 300 | else if (g->gckind != KGC_GEN) |
301 | return !(isblack(f) && iswhite(t)); /* basic incremental invariant */ | 301 | return !(isblack(f) && iswhite(t)); /* basic incremental invariant */ |
302 | else { /* generational mode */ | 302 | else { /* generational mode */ |
303 | if ((getage(f) == G_OLD && isblack(f)) && !isold(t)) | 303 | if ((getage(f) == G_OLD && isblack(f)) && !isold(t)) |
@@ -534,7 +534,7 @@ static void checkobject (global_State *g, GCObject *o, int maybedead, | |||
534 | } | 534 | } |
535 | 535 | ||
536 | 536 | ||
537 | static lu_mem checkgraylist (global_State *g, GCObject *o) { | 537 | static l_obj checkgraylist (global_State *g, GCObject *o) { |
538 | int total = 0; /* count number of elements in the list */ | 538 | int total = 0; /* count number of elements in the list */ |
539 | cast_void(g); /* better to keep it if we need to print an object */ | 539 | cast_void(g); /* better to keep it if we need to print an object */ |
540 | while (o) { | 540 | while (o) { |
@@ -563,7 +563,7 @@ static lu_mem checkgraylist (global_State *g, GCObject *o) { | |||
563 | /* | 563 | /* |
564 | ** Check objects in gray lists. | 564 | ** Check objects in gray lists. |
565 | */ | 565 | */ |
566 | static lu_mem checkgrays (global_State *g) { | 566 | static l_obj checkgrays (global_State *g) { |
567 | int total = 0; /* count number of elements in all lists */ | 567 | int total = 0; /* count number of elements in all lists */ |
568 | if (!keepinvariant(g)) return total; | 568 | if (!keepinvariant(g)) return total; |
569 | total += checkgraylist(g, g->gray); | 569 | total += checkgraylist(g, g->gray); |
@@ -580,7 +580,7 @@ static lu_mem checkgrays (global_State *g) { | |||
580 | ** 'count' and check its TESTBIT. (It must have been previously set by | 580 | ** 'count' and check its TESTBIT. (It must have been previously set by |
581 | ** 'checkgraylist'.) | 581 | ** 'checkgraylist'.) |
582 | */ | 582 | */ |
583 | static void incifingray (global_State *g, GCObject *o, lu_mem *count) { | 583 | static void incifingray (global_State *g, GCObject *o, l_obj *count) { |
584 | if (!keepinvariant(g)) | 584 | if (!keepinvariant(g)) |
585 | return; /* gray lists not being kept in these phases */ | 585 | return; /* gray lists not being kept in these phases */ |
586 | if (o->tt == LUA_VUPVAL) { | 586 | if (o->tt == LUA_VUPVAL) { |
@@ -597,10 +597,10 @@ static void incifingray (global_State *g, GCObject *o, lu_mem *count) { | |||
597 | } | 597 | } |
598 | 598 | ||
599 | 599 | ||
600 | static lu_mem checklist (global_State *g, int maybedead, int tof, | 600 | static l_obj checklist (global_State *g, int maybedead, int tof, |
601 | GCObject *newl, GCObject *survival, GCObject *old, GCObject *reallyold) { | 601 | GCObject *newl, GCObject *survival, GCObject *old, GCObject *reallyold) { |
602 | GCObject *o; | 602 | GCObject *o; |
603 | lu_mem total = 0; /* number of object that should be in gray lists */ | 603 | l_obj total = 0; /* number of object that should be in gray lists */ |
604 | for (o = newl; o != survival; o = o->next) { | 604 | for (o = newl; o != survival; o = o->next) { |
605 | checkobject(g, o, maybedead, G_NEW); | 605 | checkobject(g, o, maybedead, G_NEW); |
606 | incifingray(g, o, &total); | 606 | incifingray(g, o, &total); |
@@ -629,8 +629,8 @@ int lua_checkmemory (lua_State *L) { | |||
629 | global_State *g = G(L); | 629 | global_State *g = G(L); |
630 | GCObject *o; | 630 | GCObject *o; |
631 | int maybedead; | 631 | int maybedead; |
632 | lu_mem totalin; /* total of objects that are in gray lists */ | 632 | l_obj totalin; /* total of objects that are in gray lists */ |
633 | lu_mem totalshould; /* total of objects that should be in gray lists */ | 633 | l_obj totalshould; /* total of objects that should be in gray lists */ |
634 | if (keepinvariant(g)) { | 634 | if (keepinvariant(g)) { |
635 | assert(!iswhite(g->mainthread)); | 635 | assert(!iswhite(g->mainthread)); |
636 | assert(!iswhite(gcvalue(&g->l_registry))); | 636 | assert(!iswhite(gcvalue(&g->l_registry))); |
@@ -1002,9 +1002,8 @@ static int table_query (lua_State *L) { | |||
1002 | if (i == -1) { | 1002 | if (i == -1) { |
1003 | lua_pushinteger(L, asize); | 1003 | lua_pushinteger(L, asize); |
1004 | lua_pushinteger(L, allocsizenode(t)); | 1004 | lua_pushinteger(L, allocsizenode(t)); |
1005 | lua_pushinteger(L, isdummy(t) ? 0 : t->lastfree - t->node); | ||
1006 | lua_pushinteger(L, t->alimit); | 1005 | lua_pushinteger(L, t->alimit); |
1007 | return 4; | 1006 | return 3; |
1008 | } | 1007 | } |
1009 | else if ((unsigned int)i < asize) { | 1008 | else if ((unsigned int)i < asize) { |
1010 | lua_pushinteger(L, i); | 1009 | lua_pushinteger(L, i); |
@@ -1032,6 +1031,16 @@ static int table_query (lua_State *L) { | |||
1032 | } | 1031 | } |
1033 | 1032 | ||
1034 | 1033 | ||
1034 | static int query_inc (lua_State *L) { | ||
1035 | global_State *g = G(L); | ||
1036 | lua_pushinteger(L, gettotalobjs(g)); | ||
1037 | lua_pushinteger(L, g->GCdebt); | ||
1038 | lua_pushinteger(L, applygcparam(g, gcpause, 100)); | ||
1039 | lua_pushinteger(L, applygcparam(g, gcstepmul, 100)); | ||
1040 | lua_pushinteger(L, cast(l_obj, 1) << g->gcstepsize); | ||
1041 | return 5; | ||
1042 | } | ||
1043 | |||
1035 | static int string_query (lua_State *L) { | 1044 | static int string_query (lua_State *L) { |
1036 | stringtable *tb = &G(L)->strt; | 1045 | stringtable *tb = &G(L)->strt; |
1037 | int s = cast_int(luaL_optinteger(L, 1, 0)) - 1; | 1046 | int s = cast_int(luaL_optinteger(L, 1, 0)) - 1; |
@@ -1154,7 +1163,7 @@ static int num2int (lua_State *L) { | |||
1154 | static int newstate (lua_State *L) { | 1163 | static int newstate (lua_State *L) { |
1155 | void *ud; | 1164 | void *ud; |
1156 | lua_Alloc f = lua_getallocf(L, &ud); | 1165 | lua_Alloc f = lua_getallocf(L, &ud); |
1157 | lua_State *L1 = lua_newstate(f, ud); | 1166 | lua_State *L1 = lua_newstate(f, ud, 0); |
1158 | if (L1) { | 1167 | if (L1) { |
1159 | lua_atpanic(L1, tpanic); | 1168 | lua_atpanic(L1, tpanic); |
1160 | lua_pushlightuserdata(L, L1); | 1169 | lua_pushlightuserdata(L, L1); |
@@ -1173,31 +1182,15 @@ static lua_State *getstate (lua_State *L) { | |||
1173 | 1182 | ||
1174 | 1183 | ||
1175 | static int loadlib (lua_State *L) { | 1184 | static int loadlib (lua_State *L) { |
1176 | static const luaL_Reg libs[] = { | ||
1177 | {LUA_GNAME, luaopen_base}, | ||
1178 | {"coroutine", luaopen_coroutine}, | ||
1179 | {"debug", luaopen_debug}, | ||
1180 | {"io", luaopen_io}, | ||
1181 | {"os", luaopen_os}, | ||
1182 | {"math", luaopen_math}, | ||
1183 | {"string", luaopen_string}, | ||
1184 | {"table", luaopen_table}, | ||
1185 | {"T", luaB_opentests}, | ||
1186 | {NULL, NULL} | ||
1187 | }; | ||
1188 | lua_State *L1 = getstate(L); | 1185 | lua_State *L1 = getstate(L); |
1189 | int i; | 1186 | int what = luaL_checkinteger(L, 2); |
1190 | luaL_requiref(L1, "package", luaopen_package, 0); | 1187 | luaL_openselectedlibs(L1, what); |
1188 | luaL_requiref(L1, "T", luaB_opentests, 0); | ||
1191 | lua_assert(lua_type(L1, -1) == LUA_TTABLE); | 1189 | lua_assert(lua_type(L1, -1) == LUA_TTABLE); |
1192 | /* 'requiref' should not reload module already loaded... */ | 1190 | /* 'requiref' should not reload module already loaded... */ |
1193 | luaL_requiref(L1, "package", NULL, 1); /* seg. fault if it reloads */ | 1191 | luaL_requiref(L1, "T", NULL, 1); /* seg. fault if it reloads */ |
1194 | /* ...but should return the same module */ | 1192 | /* ...but should return the same module */ |
1195 | lua_assert(lua_compare(L1, -1, -2, LUA_OPEQ)); | 1193 | lua_assert(lua_compare(L1, -1, -2, LUA_OPEQ)); |
1196 | luaL_getsubtable(L1, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); | ||
1197 | for (i = 0; libs[i].name; i++) { | ||
1198 | lua_pushcfunction(L1, libs[i].func); | ||
1199 | lua_setfield(L1, -2, libs[i].name); | ||
1200 | } | ||
1201 | return 0; | 1194 | return 0; |
1202 | } | 1195 | } |
1203 | 1196 | ||
@@ -1263,7 +1256,7 @@ static int checkpanic (lua_State *L) { | |||
1263 | lua_Alloc f = lua_getallocf(L, &ud); | 1256 | lua_Alloc f = lua_getallocf(L, &ud); |
1264 | b.paniccode = luaL_optstring(L, 2, ""); | 1257 | b.paniccode = luaL_optstring(L, 2, ""); |
1265 | b.L = L; | 1258 | b.L = L; |
1266 | L1 = lua_newstate(f, ud); /* create new state */ | 1259 | L1 = lua_newstate(f, ud, 0); /* create new state */ |
1267 | if (L1 == NULL) { /* error? */ | 1260 | if (L1 == NULL) { /* error? */ |
1268 | lua_pushnil(L); | 1261 | lua_pushnil(L); |
1269 | return 1; | 1262 | return 1; |
@@ -1524,8 +1517,11 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) { | |||
1524 | luaL_loadfile(L1, luaL_checkstring(L1, getnum)); | 1517 | luaL_loadfile(L1, luaL_checkstring(L1, getnum)); |
1525 | } | 1518 | } |
1526 | else if EQ("loadstring") { | 1519 | else if EQ("loadstring") { |
1527 | const char *s = luaL_checkstring(L1, getnum); | 1520 | size_t slen; |
1528 | luaL_loadstring(L1, s); | 1521 | const char *s = luaL_checklstring(L1, getnum, &slen); |
1522 | const char *name = getstring; | ||
1523 | const char *mode = getstring; | ||
1524 | luaL_loadbufferx(L1, s, slen, name, mode); | ||
1529 | } | 1525 | } |
1530 | else if EQ("newmetatable") { | 1526 | else if EQ("newmetatable") { |
1531 | lua_pushboolean(L1, luaL_newmetatable(L1, getstring)); | 1527 | lua_pushboolean(L1, luaL_newmetatable(L1, getstring)); |
@@ -1938,6 +1934,7 @@ static const struct luaL_Reg tests_funcs[] = { | |||
1938 | {"pushuserdata", pushuserdata}, | 1934 | {"pushuserdata", pushuserdata}, |
1939 | {"querystr", string_query}, | 1935 | {"querystr", string_query}, |
1940 | {"querytab", table_query}, | 1936 | {"querytab", table_query}, |
1937 | {"queryinc", query_inc}, | ||
1941 | {"ref", tref}, | 1938 | {"ref", tref}, |
1942 | {"resume", coresume}, | 1939 | {"resume", coresume}, |
1943 | {"s2d", s2d}, | 1940 | {"s2d", s2d}, |
@@ -102,9 +102,10 @@ LUA_API void *debug_realloc (void *ud, void *block, | |||
102 | size_t osize, size_t nsize); | 102 | size_t osize, size_t nsize); |
103 | 103 | ||
104 | #if defined(lua_c) | 104 | #if defined(lua_c) |
105 | #define luaL_newstate() lua_newstate(debug_realloc, &l_memcontrol) | 105 | #define luaL_newstate() \ |
106 | #define luaL_openlibs(L) \ | 106 | lua_newstate(debug_realloc, &l_memcontrol, luaL_makeseed(NULL)) |
107 | { (luaL_openlibs)(L); \ | 107 | #define luai_openlibs(L) \ |
108 | { luaL_openlibs(L); \ | ||
108 | luaL_requiref(L, "T", luaB_opentests, 1); \ | 109 | luaL_requiref(L, "T", luaB_opentests, 1); \ |
109 | lua_pop(L, 1); } | 110 | lua_pop(L, 1); } |
110 | #endif | 111 | #endif |
@@ -261,7 +261,7 @@ void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) { | |||
261 | int nextra = ci->u.l.nextraargs; | 261 | int nextra = ci->u.l.nextraargs; |
262 | if (wanted < 0) { | 262 | if (wanted < 0) { |
263 | wanted = nextra; /* get all extra arguments available */ | 263 | wanted = nextra; /* get all extra arguments available */ |
264 | checkstackGCp(L, nextra, where); /* ensure stack space */ | 264 | checkstackp(L, nextra, where); /* ensure stack space */ |
265 | L->top.p = where + nextra; /* next instruction will need top */ | 265 | L->top.p = where + nextra; /* next instruction will need top */ |
266 | } | 266 | } |
267 | for (i = 0; i < wanted && i < nextra; i++) | 267 | for (i = 0; i < wanted && i < nextra; i++) |
@@ -48,8 +48,8 @@ typedef enum { | |||
48 | /* | 48 | /* |
49 | ** Mask with 1 in all fast-access methods. A 1 in any of these bits | 49 | ** Mask with 1 in all fast-access methods. A 1 in any of these bits |
50 | ** in the flag of a (meta)table means the metatable does not have the | 50 | ** in the flag of a (meta)table means the metatable does not have the |
51 | ** corresponding metamethod field. (Bit 7 of the flag is used for | 51 | ** corresponding metamethod field. (Bit 6 of the flag indicates that |
52 | ** 'isrealasize'.) | 52 | ** the table is using the dummy node; bit 7 is used for 'isrealasize'.) |
53 | */ | 53 | */ |
54 | #define maskflags (~(~0u << (TM_EQ + 1))) | 54 | #define maskflags (~(~0u << (TM_EQ + 1))) |
55 | 55 | ||
@@ -617,6 +617,10 @@ static void doREPL (lua_State *L) { | |||
617 | 617 | ||
618 | /* }================================================================== */ | 618 | /* }================================================================== */ |
619 | 619 | ||
620 | #if !defined(luai_openlibs) | ||
621 | #define luai_openlibs(L) luaL_openlibs(L) | ||
622 | #endif | ||
623 | |||
620 | 624 | ||
621 | /* | 625 | /* |
622 | ** Main body of stand-alone interpreter (to be called in protected mode). | 626 | ** Main body of stand-alone interpreter (to be called in protected mode). |
@@ -639,7 +643,7 @@ static int pmain (lua_State *L) { | |||
639 | lua_pushboolean(L, 1); /* signal for libraries to ignore env. vars. */ | 643 | lua_pushboolean(L, 1); /* signal for libraries to ignore env. vars. */ |
640 | lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); | 644 | lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); |
641 | } | 645 | } |
642 | luaL_openlibs(L); /* open standard libraries */ | 646 | luai_openlibs(L); /* open standard libraries */ |
643 | createargtable(L, argv, argc, script); /* create table 'arg' */ | 647 | createargtable(L, argv, argc, script); /* create table 'arg' */ |
644 | lua_gc(L, LUA_GCRESTART); /* start GC... */ | 648 | lua_gc(L, LUA_GCRESTART); /* start GC... */ |
645 | lua_gc(L, LUA_GCGEN, 0, 0); /* ...in generational mode */ | 649 | lua_gc(L, LUA_GCGEN, 0, 0); /* ...in generational mode */ |
@@ -18,8 +18,8 @@ | |||
18 | 18 | ||
19 | 19 | ||
20 | #define LUA_VERSION_MAJOR_N 5 | 20 | #define LUA_VERSION_MAJOR_N 5 |
21 | #define LUA_VERSION_MINOR_N 4 | 21 | #define LUA_VERSION_MINOR_N 5 |
22 | #define LUA_VERSION_RELEASE_N 6 | 22 | #define LUA_VERSION_RELEASE_N 0 |
23 | 23 | ||
24 | #define LUA_VERSION_NUM (LUA_VERSION_MAJOR_N * 100 + LUA_VERSION_MINOR_N) | 24 | #define LUA_VERSION_NUM (LUA_VERSION_MAJOR_N * 100 + LUA_VERSION_MINOR_N) |
25 | #define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + LUA_VERSION_RELEASE_N) | 25 | #define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + LUA_VERSION_RELEASE_N) |
@@ -159,11 +159,11 @@ extern const char lua_ident[]; | |||
159 | /* | 159 | /* |
160 | ** state manipulation | 160 | ** state manipulation |
161 | */ | 161 | */ |
162 | LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); | 162 | LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud, |
163 | unsigned int seed); | ||
163 | LUA_API void (lua_close) (lua_State *L); | 164 | LUA_API void (lua_close) (lua_State *L); |
164 | LUA_API lua_State *(lua_newthread) (lua_State *L); | 165 | LUA_API lua_State *(lua_newthread) (lua_State *L); |
165 | LUA_API int (lua_closethread) (lua_State *L, lua_State *from); | 166 | LUA_API int (lua_closethread) (lua_State *L, lua_State *from); |
166 | LUA_API int (lua_resetthread) (lua_State *L); /* Deprecated! */ | ||
167 | 167 | ||
168 | LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); | 168 | LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); |
169 | 169 | ||
@@ -425,6 +425,8 @@ LUA_API void (lua_closeslot) (lua_State *L, int idx); | |||
425 | 425 | ||
426 | #define LUA_NUMTAGS LUA_NUMTYPES | 426 | #define LUA_NUMTAGS LUA_NUMTYPES |
427 | 427 | ||
428 | #define lua_resetthread(L) lua_closethread(L,NULL) | ||
429 | |||
428 | /* }============================================================== */ | 430 | /* }============================================================== */ |
429 | 431 | ||
430 | /* | 432 | /* |
@@ -14,39 +14,52 @@ | |||
14 | /* version suffix for environment variable names */ | 14 | /* version suffix for environment variable names */ |
15 | #define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR | 15 | #define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR |
16 | 16 | ||
17 | 17 | #define LUA_GK 1 | |
18 | LUAMOD_API int (luaopen_base) (lua_State *L); | 18 | LUAMOD_API int (luaopen_base) (lua_State *L); |
19 | 19 | ||
20 | #define LUA_LOADLIBNAME "package" | ||
21 | #define LUA_LOADLIBK (LUA_GK << 1) | ||
22 | LUAMOD_API int (luaopen_package) (lua_State *L); | ||
23 | |||
24 | |||
20 | #define LUA_COLIBNAME "coroutine" | 25 | #define LUA_COLIBNAME "coroutine" |
26 | #define LUA_COLIBK (LUA_LOADLIBK << 1) | ||
21 | LUAMOD_API int (luaopen_coroutine) (lua_State *L); | 27 | LUAMOD_API int (luaopen_coroutine) (lua_State *L); |
22 | 28 | ||
23 | #define LUA_TABLIBNAME "table" | 29 | #define LUA_DBLIBNAME "debug" |
24 | LUAMOD_API int (luaopen_table) (lua_State *L); | 30 | #define LUA_DBLIBK (LUA_COLIBK << 1) |
31 | LUAMOD_API int (luaopen_debug) (lua_State *L); | ||
25 | 32 | ||
26 | #define LUA_IOLIBNAME "io" | 33 | #define LUA_IOLIBNAME "io" |
34 | #define LUA_IOLIBK (LUA_DBLIBK << 1) | ||
27 | LUAMOD_API int (luaopen_io) (lua_State *L); | 35 | LUAMOD_API int (luaopen_io) (lua_State *L); |
28 | 36 | ||
37 | #define LUA_MATHLIBNAME "math" | ||
38 | #define LUA_MATHLIBK (LUA_IOLIBK << 1) | ||
39 | LUAMOD_API int (luaopen_math) (lua_State *L); | ||
40 | |||
29 | #define LUA_OSLIBNAME "os" | 41 | #define LUA_OSLIBNAME "os" |
42 | #define LUA_OSLIBK (LUA_MATHLIBK << 1) | ||
30 | LUAMOD_API int (luaopen_os) (lua_State *L); | 43 | LUAMOD_API int (luaopen_os) (lua_State *L); |
31 | 44 | ||
32 | #define LUA_STRLIBNAME "string" | 45 | #define LUA_STRLIBNAME "string" |
46 | #define LUA_STRLIBK (LUA_OSLIBK << 1) | ||
33 | LUAMOD_API int (luaopen_string) (lua_State *L); | 47 | LUAMOD_API int (luaopen_string) (lua_State *L); |
34 | 48 | ||
49 | #define LUA_TABLIBNAME "table" | ||
50 | #define LUA_TABLIBK (LUA_STRLIBK << 1) | ||
51 | LUAMOD_API int (luaopen_table) (lua_State *L); | ||
52 | |||
35 | #define LUA_UTF8LIBNAME "utf8" | 53 | #define LUA_UTF8LIBNAME "utf8" |
54 | #define LUA_UTF8LIBK (LUA_TABLIBK << 1) | ||
36 | LUAMOD_API int (luaopen_utf8) (lua_State *L); | 55 | LUAMOD_API int (luaopen_utf8) (lua_State *L); |
37 | 56 | ||
38 | #define LUA_MATHLIBNAME "math" | ||
39 | LUAMOD_API int (luaopen_math) (lua_State *L); | ||
40 | |||
41 | #define LUA_DBLIBNAME "debug" | ||
42 | LUAMOD_API int (luaopen_debug) (lua_State *L); | ||
43 | |||
44 | #define LUA_LOADLIBNAME "package" | ||
45 | LUAMOD_API int (luaopen_package) (lua_State *L); | ||
46 | 57 | ||
58 | /* open selected libraries */ | ||
59 | LUALIB_API void (luaL_openselectedlibs) (lua_State *L, int what); | ||
47 | 60 | ||
48 | /* open all previous libraries */ | 61 | /* open all libraries */ |
49 | LUALIB_API void (luaL_openlibs) (lua_State *L); | 62 | #define luaL_openlibs(L) luaL_openselectedlibs(L, ~0) |
50 | 63 | ||
51 | 64 | ||
52 | #endif | 65 | #endif |
@@ -21,6 +21,7 @@ | |||
21 | #include "lmem.h" | 21 | #include "lmem.h" |
22 | #include "lobject.h" | 22 | #include "lobject.h" |
23 | #include "lstring.h" | 23 | #include "lstring.h" |
24 | #include "ltable.h" | ||
24 | #include "lundump.h" | 25 | #include "lundump.h" |
25 | #include "lzio.h" | 26 | #include "lzio.h" |
26 | 27 | ||
@@ -34,6 +35,10 @@ typedef struct { | |||
34 | lua_State *L; | 35 | lua_State *L; |
35 | ZIO *Z; | 36 | ZIO *Z; |
36 | const char *name; | 37 | const char *name; |
38 | Table *h; /* list for string reuse */ | ||
39 | lu_mem offset; /* current position relative to beginning of dump */ | ||
40 | lua_Integer nstr; /* number of strings in the list */ | ||
41 | lu_byte fixed; /* dump is fixed in memory */ | ||
37 | } LoadState; | 42 | } LoadState; |
38 | 43 | ||
39 | 44 | ||
@@ -52,6 +57,27 @@ static l_noret error (LoadState *S, const char *why) { | |||
52 | static void loadBlock (LoadState *S, void *b, size_t size) { | 57 | static void loadBlock (LoadState *S, void *b, size_t size) { |
53 | if (luaZ_read(S->Z, b, size) != 0) | 58 | if (luaZ_read(S->Z, b, size) != 0) |
54 | error(S, "truncated chunk"); | 59 | error(S, "truncated chunk"); |
60 | S->offset += size; | ||
61 | } | ||
62 | |||
63 | |||
64 | static void loadAlign (LoadState *S, int align) { | ||
65 | int padding = align - (S->offset % align); | ||
66 | if (padding < align) { /* apd == align means no padding */ | ||
67 | lua_Integer paddingContent; | ||
68 | loadBlock(S, &paddingContent, padding); | ||
69 | lua_assert(S->offset % align == 0); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | |||
74 | #define getaddr(S,n,t) cast(t *, getaddr_(S,n,sizeof(t))) | ||
75 | |||
76 | static const void *getaddr_ (LoadState *S, int n, int sz) { | ||
77 | const void *block = luaZ_getaddr(S->Z, n * sz); | ||
78 | if (block == NULL) | ||
79 | error(S, "truncated fixed buffer"); | ||
80 | return block; | ||
55 | } | 81 | } |
56 | 82 | ||
57 | 83 | ||
@@ -62,6 +88,7 @@ static lu_byte loadByte (LoadState *S) { | |||
62 | int b = zgetc(S->Z); | 88 | int b = zgetc(S->Z); |
63 | if (b == EOZ) | 89 | if (b == EOZ) |
64 | error(S, "truncated chunk"); | 90 | error(S, "truncated chunk"); |
91 | S->offset++; | ||
65 | return cast_byte(b); | 92 | return cast_byte(b); |
66 | } | 93 | } |
67 | 94 | ||
@@ -110,10 +137,16 @@ static lua_Integer loadInteger (LoadState *S) { | |||
110 | static TString *loadStringN (LoadState *S, Proto *p) { | 137 | static TString *loadStringN (LoadState *S, Proto *p) { |
111 | lua_State *L = S->L; | 138 | lua_State *L = S->L; |
112 | TString *ts; | 139 | TString *ts; |
140 | TValue sv; | ||
113 | size_t size = loadSize(S); | 141 | size_t size = loadSize(S); |
114 | if (size == 0) /* no string? */ | 142 | if (size == 0) /* no string? */ |
115 | return NULL; | 143 | return NULL; |
116 | else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */ | 144 | else if (size == 1) { /* previously saved string? */ |
145 | int idx = loadInt(S); /* get its index */ | ||
146 | const TValue *stv = luaH_getint(S->h, idx); | ||
147 | return tsvalue(stv); | ||
148 | } | ||
149 | else if (size -= 2, size <= LUAI_MAXSHORTLEN) { /* short string? */ | ||
117 | char buff[LUAI_MAXSHORTLEN]; | 150 | char buff[LUAI_MAXSHORTLEN]; |
118 | loadVector(S, buff, size); /* load string into buffer */ | 151 | loadVector(S, buff, size); /* load string into buffer */ |
119 | ts = luaS_newlstr(L, buff, size); /* create string */ | 152 | ts = luaS_newlstr(L, buff, size); /* create string */ |
@@ -126,6 +159,10 @@ static TString *loadStringN (LoadState *S, Proto *p) { | |||
126 | L->top.p--; /* pop string */ | 159 | L->top.p--; /* pop string */ |
127 | } | 160 | } |
128 | luaC_objbarrier(L, p, ts); | 161 | luaC_objbarrier(L, p, ts); |
162 | S->nstr++; /* add string to list of saved strings */ | ||
163 | setsvalue(L, &sv, ts); | ||
164 | luaH_setint(L, S->h, S->nstr, &sv); | ||
165 | luaC_objbarrierback(L, obj2gco(S->h), ts); | ||
129 | return ts; | 166 | return ts; |
130 | } | 167 | } |
131 | 168 | ||
@@ -143,13 +180,20 @@ static TString *loadString (LoadState *S, Proto *p) { | |||
143 | 180 | ||
144 | static void loadCode (LoadState *S, Proto *f) { | 181 | static void loadCode (LoadState *S, Proto *f) { |
145 | int n = loadInt(S); | 182 | int n = loadInt(S); |
146 | f->code = luaM_newvectorchecked(S->L, n, Instruction); | 183 | loadAlign(S, sizeof(f->code[0])); |
147 | f->sizecode = n; | 184 | if (S->fixed) { |
148 | loadVector(S, f->code, n); | 185 | f->code = getaddr(S, n, Instruction); |
186 | f->sizecode = n; | ||
187 | } | ||
188 | else { | ||
189 | f->code = luaM_newvectorchecked(S->L, n, Instruction); | ||
190 | f->sizecode = n; | ||
191 | loadVector(S, f->code, n); | ||
192 | } | ||
149 | } | 193 | } |
150 | 194 | ||
151 | 195 | ||
152 | static void loadFunction(LoadState *S, Proto *f, TString *psource); | 196 | static void loadFunction(LoadState *S, Proto *f); |
153 | 197 | ||
154 | 198 | ||
155 | static void loadConstants (LoadState *S, Proto *f) { | 199 | static void loadConstants (LoadState *S, Proto *f) { |
@@ -198,7 +242,7 @@ static void loadProtos (LoadState *S, Proto *f) { | |||
198 | for (i = 0; i < n; i++) { | 242 | for (i = 0; i < n; i++) { |
199 | f->p[i] = luaF_newproto(S->L); | 243 | f->p[i] = luaF_newproto(S->L); |
200 | luaC_objbarrier(S->L, f, f->p[i]); | 244 | luaC_objbarrier(S->L, f, f->p[i]); |
201 | loadFunction(S, f->p[i], f->source); | 245 | loadFunction(S, f->p[i]); |
202 | } | 246 | } |
203 | } | 247 | } |
204 | 248 | ||
@@ -227,9 +271,15 @@ static void loadUpvalues (LoadState *S, Proto *f) { | |||
227 | static void loadDebug (LoadState *S, Proto *f) { | 271 | static void loadDebug (LoadState *S, Proto *f) { |
228 | int i, n; | 272 | int i, n; |
229 | n = loadInt(S); | 273 | n = loadInt(S); |
230 | f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte); | 274 | if (S->fixed) { |
231 | f->sizelineinfo = n; | 275 | f->lineinfo = getaddr(S, n, ls_byte); |
232 | loadVector(S, f->lineinfo, n); | 276 | f->sizelineinfo = n; |
277 | } | ||
278 | else { | ||
279 | f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte); | ||
280 | f->sizelineinfo = n; | ||
281 | loadVector(S, f->lineinfo, n); | ||
282 | } | ||
233 | n = loadInt(S); | 283 | n = loadInt(S); |
234 | f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo); | 284 | f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo); |
235 | f->sizeabslineinfo = n; | 285 | f->sizeabslineinfo = n; |
@@ -255,14 +305,14 @@ static void loadDebug (LoadState *S, Proto *f) { | |||
255 | } | 305 | } |
256 | 306 | ||
257 | 307 | ||
258 | static void loadFunction (LoadState *S, Proto *f, TString *psource) { | 308 | static void loadFunction (LoadState *S, Proto *f) { |
259 | f->source = loadStringN(S, f); | 309 | f->source = loadStringN(S, f); |
260 | if (f->source == NULL) /* no source in dump? */ | ||
261 | f->source = psource; /* reuse parent's source */ | ||
262 | f->linedefined = loadInt(S); | 310 | f->linedefined = loadInt(S); |
263 | f->lastlinedefined = loadInt(S); | 311 | f->lastlinedefined = loadInt(S); |
264 | f->numparams = loadByte(S); | 312 | f->numparams = loadByte(S); |
265 | f->is_vararg = loadByte(S); | 313 | f->flag = loadByte(S) & PF_ISVARARG; /* get only the meaningful flags */ |
314 | if (S->fixed) | ||
315 | f->flag |= PF_FIXED; /* signal that code is fixed */ | ||
266 | f->maxstacksize = loadByte(S); | 316 | f->maxstacksize = loadByte(S); |
267 | loadCode(S, f); | 317 | loadCode(S, f); |
268 | loadConstants(S, f); | 318 | loadConstants(S, f); |
@@ -310,7 +360,7 @@ static void checkHeader (LoadState *S) { | |||
310 | /* | 360 | /* |
311 | ** Load precompiled chunk. | 361 | ** Load precompiled chunk. |
312 | */ | 362 | */ |
313 | LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) { | 363 | LClosure *luaU_undump (lua_State *L, ZIO *Z, const char *name, int fixed) { |
314 | LoadState S; | 364 | LoadState S; |
315 | LClosure *cl; | 365 | LClosure *cl; |
316 | if (*name == '@' || *name == '=') | 366 | if (*name == '@' || *name == '=') |
@@ -321,15 +371,22 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) { | |||
321 | S.name = name; | 371 | S.name = name; |
322 | S.L = L; | 372 | S.L = L; |
323 | S.Z = Z; | 373 | S.Z = Z; |
374 | S.fixed = fixed; | ||
375 | S.offset = 1; /* fist byte was already read */ | ||
324 | checkHeader(&S); | 376 | checkHeader(&S); |
325 | cl = luaF_newLclosure(L, loadByte(&S)); | 377 | cl = luaF_newLclosure(L, loadByte(&S)); |
326 | setclLvalue2s(L, L->top.p, cl); | 378 | setclLvalue2s(L, L->top.p, cl); |
327 | luaD_inctop(L); | 379 | luaD_inctop(L); |
380 | S.h = luaH_new(L); /* create list of saved strings */ | ||
381 | S.nstr = 0; | ||
382 | sethvalue2s(L, L->top.p, S.h); /* anchor it */ | ||
383 | luaD_inctop(L); | ||
328 | cl->p = luaF_newproto(L); | 384 | cl->p = luaF_newproto(L); |
329 | luaC_objbarrier(L, cl, cl->p); | 385 | luaC_objbarrier(L, cl, cl->p); |
330 | loadFunction(&S, cl->p, NULL); | 386 | loadFunction(&S, cl->p); |
331 | lua_assert(cl->nupvalues == cl->p->sizeupvalues); | 387 | lua_assert(cl->nupvalues == cl->p->sizeupvalues); |
332 | luai_verifycode(L, cl->p); | 388 | luai_verifycode(L, cl->p); |
389 | L->top.p--; /* pop table */ | ||
333 | return cl; | 390 | return cl; |
334 | } | 391 | } |
335 | 392 | ||
@@ -26,10 +26,11 @@ | |||
26 | #define LUAC_FORMAT 0 /* this is the official format */ | 26 | #define LUAC_FORMAT 0 /* this is the official format */ |
27 | 27 | ||
28 | /* load one chunk; from lundump.c */ | 28 | /* load one chunk; from lundump.c */ |
29 | LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name); | 29 | LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name, |
30 | int fixed); | ||
30 | 31 | ||
31 | /* dump one chunk; from ldump.c */ | 32 | /* dump one chunk; from ldump.c */ |
32 | LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, | 33 | LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, |
33 | void* data, int strip); | 34 | void* data, int strip, Table *h); |
34 | 35 | ||
35 | #endif | 36 | #endif |
@@ -93,7 +93,9 @@ static int l_strton (const TValue *obj, TValue *result) { | |||
93 | return 0; | 93 | return 0; |
94 | else { | 94 | else { |
95 | TString *st = tsvalue(obj); | 95 | TString *st = tsvalue(obj); |
96 | return (luaO_str2num(getstr(st), result) == tsslen(st) + 1); | 96 | size_t stlen; |
97 | const char *s = getlstr(st, stlen); | ||
98 | return (luaO_str2num(s, result) == stlen + 1); | ||
97 | } | 99 | } |
98 | } | 100 | } |
99 | 101 | ||
@@ -198,12 +200,15 @@ static int forlimit (lua_State *L, lua_Integer init, const TValue *lim, | |||
198 | 200 | ||
199 | /* | 201 | /* |
200 | ** Prepare a numerical for loop (opcode OP_FORPREP). | 202 | ** Prepare a numerical for loop (opcode OP_FORPREP). |
203 | ** Before execution, stack is as follows: | ||
204 | ** ra : initial value | ||
205 | ** ra + 1 : limit | ||
206 | ** ra + 2 : step | ||
201 | ** Return true to skip the loop. Otherwise, | 207 | ** Return true to skip the loop. Otherwise, |
202 | ** after preparation, stack will be as follows: | 208 | ** after preparation, stack will be as follows: |
203 | ** ra : internal index (safe copy of the control variable) | 209 | ** ra : loop counter (integer loops) or limit (float loops) |
204 | ** ra + 1 : loop counter (integer loops) or limit (float loops) | 210 | ** ra + 1 : step |
205 | ** ra + 2 : step | 211 | ** ra + 2 : control variable |
206 | ** ra + 3 : control variable | ||
207 | */ | 212 | */ |
208 | static int forprep (lua_State *L, StkId ra) { | 213 | static int forprep (lua_State *L, StkId ra) { |
209 | TValue *pinit = s2v(ra); | 214 | TValue *pinit = s2v(ra); |
@@ -215,7 +220,6 @@ static int forprep (lua_State *L, StkId ra) { | |||
215 | lua_Integer limit; | 220 | lua_Integer limit; |
216 | if (step == 0) | 221 | if (step == 0) |
217 | luaG_runerror(L, "'for' step is zero"); | 222 | luaG_runerror(L, "'for' step is zero"); |
218 | setivalue(s2v(ra + 3), init); /* control variable */ | ||
219 | if (forlimit(L, init, plimit, &limit, step)) | 223 | if (forlimit(L, init, plimit, &limit, step)) |
220 | return 1; /* skip the loop */ | 224 | return 1; /* skip the loop */ |
221 | else { /* prepare loop counter */ | 225 | else { /* prepare loop counter */ |
@@ -230,9 +234,10 @@ static int forprep (lua_State *L, StkId ra) { | |||
230 | /* 'step+1' avoids negating 'mininteger' */ | 234 | /* 'step+1' avoids negating 'mininteger' */ |
231 | count /= l_castS2U(-(step + 1)) + 1u; | 235 | count /= l_castS2U(-(step + 1)) + 1u; |
232 | } | 236 | } |
233 | /* store the counter in place of the limit (which won't be | 237 | /* use 'chgivalue' for places that for sure had integers */ |
234 | needed anymore) */ | 238 | chgivalue(s2v(ra), l_castU2S(count)); /* change init to count */ |
235 | setivalue(plimit, l_castU2S(count)); | 239 | setivalue(s2v(ra + 1), step); /* change limit to step */ |
240 | chgivalue(s2v(ra + 2), init); /* change step to init */ | ||
236 | } | 241 | } |
237 | } | 242 | } |
238 | else { /* try making all values floats */ | 243 | else { /* try making all values floats */ |
@@ -249,11 +254,10 @@ static int forprep (lua_State *L, StkId ra) { | |||
249 | : luai_numlt(init, limit)) | 254 | : luai_numlt(init, limit)) |
250 | return 1; /* skip the loop */ | 255 | return 1; /* skip the loop */ |
251 | else { | 256 | else { |
252 | /* make sure internal values are all floats */ | 257 | /* make sure all values are floats */ |
253 | setfltvalue(plimit, limit); | 258 | setfltvalue(s2v(ra), limit); |
254 | setfltvalue(pstep, step); | 259 | setfltvalue(s2v(ra + 1), step); |
255 | setfltvalue(s2v(ra), init); /* internal index */ | 260 | setfltvalue(s2v(ra + 2), init); /* control variable */ |
256 | setfltvalue(s2v(ra + 3), init); /* control variable */ | ||
257 | } | 261 | } |
258 | } | 262 | } |
259 | return 0; | 263 | return 0; |
@@ -266,14 +270,13 @@ static int forprep (lua_State *L, StkId ra) { | |||
266 | ** written online with opcode OP_FORLOOP, for performance.) | 270 | ** written online with opcode OP_FORLOOP, for performance.) |
267 | */ | 271 | */ |
268 | static int floatforloop (StkId ra) { | 272 | static int floatforloop (StkId ra) { |
269 | lua_Number step = fltvalue(s2v(ra + 2)); | 273 | lua_Number step = fltvalue(s2v(ra + 1)); |
270 | lua_Number limit = fltvalue(s2v(ra + 1)); | 274 | lua_Number limit = fltvalue(s2v(ra)); |
271 | lua_Number idx = fltvalue(s2v(ra)); /* internal index */ | 275 | lua_Number idx = fltvalue(s2v(ra + 2)); /* control variable */ |
272 | idx = luai_numadd(L, idx, step); /* increment index */ | 276 | idx = luai_numadd(L, idx, step); /* increment index */ |
273 | if (luai_numlt(0, step) ? luai_numle(idx, limit) | 277 | if (luai_numlt(0, step) ? luai_numle(idx, limit) |
274 | : luai_numle(limit, idx)) { | 278 | : luai_numle(limit, idx)) { |
275 | chgfltvalue(s2v(ra), idx); /* update internal index */ | 279 | chgfltvalue(s2v(ra + 2), idx); /* update control variable */ |
276 | setfltvalue(s2v(ra + 3), idx); /* and control variable */ | ||
277 | return 1; /* jump back */ | 280 | return 1; /* jump back */ |
278 | } | 281 | } |
279 | else | 282 | else |
@@ -366,10 +369,10 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, | |||
366 | ** have different lengths. | 369 | ** have different lengths. |
367 | */ | 370 | */ |
368 | static int l_strcmp (const TString *ts1, const TString *ts2) { | 371 | static int l_strcmp (const TString *ts1, const TString *ts2) { |
369 | const char *s1 = getstr(ts1); | 372 | size_t rl1; /* real length */ |
370 | size_t rl1 = tsslen(ts1); /* real length */ | 373 | const char *s1 = getlstr(ts1, rl1); |
371 | const char *s2 = getstr(ts2); | 374 | size_t rl2; |
372 | size_t rl2 = tsslen(ts2); | 375 | const char *s2 = getlstr(ts2, rl2); |
373 | for (;;) { /* for each segment */ | 376 | for (;;) { /* for each segment */ |
374 | int temp = strcoll(s1, s2); | 377 | int temp = strcoll(s1, s2); |
375 | if (temp != 0) /* not equal? */ | 378 | if (temp != 0) /* not equal? */ |
@@ -619,8 +622,9 @@ static void copy2buff (StkId top, int n, char *buff) { | |||
619 | size_t tl = 0; /* size already copied */ | 622 | size_t tl = 0; /* size already copied */ |
620 | do { | 623 | do { |
621 | TString *st = tsvalue(s2v(top - n)); | 624 | TString *st = tsvalue(s2v(top - n)); |
622 | size_t l = tsslen(st); /* length of string being copied */ | 625 | size_t l; /* length of string being copied */ |
623 | memcpy(buff + tl, getstr(st), l * sizeof(char)); | 626 | const char *s = getlstr(st, l); |
627 | memcpy(buff + tl, s, l * sizeof(char)); | ||
624 | tl += l; | 628 | tl += l; |
625 | } while (--n > 0); | 629 | } while (--n > 0); |
626 | } | 630 | } |
@@ -1766,15 +1770,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1766 | } | 1770 | } |
1767 | vmcase(OP_FORLOOP) { | 1771 | vmcase(OP_FORLOOP) { |
1768 | StkId ra = RA(i); | 1772 | StkId ra = RA(i); |
1769 | if (ttisinteger(s2v(ra + 2))) { /* integer loop? */ | 1773 | if (ttisinteger(s2v(ra + 1))) { /* integer loop? */ |
1770 | lua_Unsigned count = l_castS2U(ivalue(s2v(ra + 1))); | 1774 | lua_Unsigned count = l_castS2U(ivalue(s2v(ra))); |
1771 | if (count > 0) { /* still more iterations? */ | 1775 | if (count > 0) { /* still more iterations? */ |
1772 | lua_Integer step = ivalue(s2v(ra + 2)); | 1776 | lua_Integer step = ivalue(s2v(ra + 1)); |
1773 | lua_Integer idx = ivalue(s2v(ra)); /* internal index */ | 1777 | lua_Integer idx = ivalue(s2v(ra + 2)); /* control variable */ |
1774 | chgivalue(s2v(ra + 1), count - 1); /* update counter */ | 1778 | chgivalue(s2v(ra), count - 1); /* update counter */ |
1775 | idx = intop(+, idx, step); /* add step to index */ | 1779 | idx = intop(+, idx, step); /* add step to index */ |
1776 | chgivalue(s2v(ra), idx); /* update internal index */ | 1780 | chgivalue(s2v(ra + 2), idx); /* update control variable */ |
1777 | setivalue(s2v(ra + 3), idx); /* and control variable */ | ||
1778 | pc -= GETARG_Bx(i); /* jump back */ | 1781 | pc -= GETARG_Bx(i); /* jump back */ |
1779 | } | 1782 | } |
1780 | } | 1783 | } |
@@ -1791,26 +1794,38 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1791 | vmbreak; | 1794 | vmbreak; |
1792 | } | 1795 | } |
1793 | vmcase(OP_TFORPREP) { | 1796 | vmcase(OP_TFORPREP) { |
1797 | /* before: 'ra' has the iterator function, 'ra + 1' has the state, | ||
1798 | 'ra + 2' has the initial value for the control variable, and | ||
1799 | 'ra + 3' has the closing variable. This opcode then swaps the | ||
1800 | control and the closing variables and marks the closing variable | ||
1801 | as to-be-closed. | ||
1802 | */ | ||
1794 | StkId ra = RA(i); | 1803 | StkId ra = RA(i); |
1795 | /* create to-be-closed upvalue (if needed) */ | 1804 | TValue temp; /* to swap control and closing variables */ |
1796 | halfProtect(luaF_newtbcupval(L, ra + 3)); | 1805 | setobj(L, &temp, s2v(ra + 3)); |
1797 | pc += GETARG_Bx(i); | 1806 | setobjs2s(L, ra + 3, ra + 2); |
1798 | i = *(pc++); /* go to next instruction */ | 1807 | setobj2s(L, ra + 2, &temp); |
1808 | /* create to-be-closed upvalue (if closing var. is not nil) */ | ||
1809 | halfProtect(luaF_newtbcupval(L, ra + 2)); | ||
1810 | pc += GETARG_Bx(i); /* go to end of the loop */ | ||
1811 | i = *(pc++); /* fetch next instruction */ | ||
1799 | lua_assert(GET_OPCODE(i) == OP_TFORCALL && ra == RA(i)); | 1812 | lua_assert(GET_OPCODE(i) == OP_TFORCALL && ra == RA(i)); |
1800 | goto l_tforcall; | 1813 | goto l_tforcall; |
1801 | } | 1814 | } |
1802 | vmcase(OP_TFORCALL) { | 1815 | vmcase(OP_TFORCALL) { |
1803 | l_tforcall: { | 1816 | l_tforcall: { |
1804 | StkId ra = RA(i); | ||
1805 | /* 'ra' has the iterator function, 'ra + 1' has the state, | 1817 | /* 'ra' has the iterator function, 'ra + 1' has the state, |
1806 | 'ra + 2' has the control variable, and 'ra + 3' has the | 1818 | 'ra + 2' has the closing variable, and 'ra + 3' has the control |
1807 | to-be-closed variable. The call will use the stack after | 1819 | variable. The call will use the stack starting at 'ra + 3', |
1808 | these values (starting at 'ra + 4') | 1820 | so that it preserves the first three values, and the first |
1821 | return will be the new value for the control variable. | ||
1809 | */ | 1822 | */ |
1810 | /* push function, state, and control variable */ | 1823 | StkId ra = RA(i); |
1811 | memcpy(ra + 4, ra, 3 * sizeof(*ra)); | 1824 | setobjs2s(L, ra + 5, ra + 3); /* copy the control variable */ |
1812 | L->top.p = ra + 4 + 3; | 1825 | setobjs2s(L, ra + 4, ra + 1); /* copy state */ |
1813 | ProtectNT(luaD_call(L, ra + 4, GETARG_C(i))); /* do the call */ | 1826 | setobjs2s(L, ra + 3, ra); /* copy function */ |
1827 | L->top.p = ra + 3 + 3; | ||
1828 | ProtectNT(luaD_call(L, ra + 3, GETARG_C(i))); /* do the call */ | ||
1814 | updatestack(ci); /* stack may have changed */ | 1829 | updatestack(ci); /* stack may have changed */ |
1815 | i = *(pc++); /* go to next instruction */ | 1830 | i = *(pc++); /* go to next instruction */ |
1816 | lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i)); | 1831 | lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i)); |
@@ -1819,10 +1834,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1819 | vmcase(OP_TFORLOOP) { | 1834 | vmcase(OP_TFORLOOP) { |
1820 | l_tforloop: { | 1835 | l_tforloop: { |
1821 | StkId ra = RA(i); | 1836 | StkId ra = RA(i); |
1822 | if (!ttisnil(s2v(ra + 4))) { /* continue loop? */ | 1837 | if (!ttisnil(s2v(ra + 3))) /* continue loop? */ |
1823 | setobjs2s(L, ra + 2, ra + 4); /* save control variable */ | ||
1824 | pc -= GETARG_Bx(i); /* jump back */ | 1838 | pc -= GETARG_Bx(i); /* jump back */ |
1825 | } | ||
1826 | vmbreak; | 1839 | vmbreak; |
1827 | }} | 1840 | }} |
1828 | vmcase(OP_SETLIST) { | 1841 | vmcase(OP_SETLIST) { |
@@ -45,17 +45,25 @@ void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { | |||
45 | 45 | ||
46 | 46 | ||
47 | /* --------------------------------------------------------------- read --- */ | 47 | /* --------------------------------------------------------------- read --- */ |
48 | |||
49 | static int checkbuffer (ZIO *z) { | ||
50 | if (z->n == 0) { /* no bytes in buffer? */ | ||
51 | if (luaZ_fill(z) == EOZ) /* try to read more */ | ||
52 | return 0; /* no more input */ | ||
53 | else { | ||
54 | z->n++; /* luaZ_fill consumed first byte; put it back */ | ||
55 | z->p--; | ||
56 | } | ||
57 | } | ||
58 | return 1; /* now buffer has something */ | ||
59 | } | ||
60 | |||
61 | |||
48 | size_t luaZ_read (ZIO *z, void *b, size_t n) { | 62 | size_t luaZ_read (ZIO *z, void *b, size_t n) { |
49 | while (n) { | 63 | while (n) { |
50 | size_t m; | 64 | size_t m; |
51 | if (z->n == 0) { /* no bytes in buffer? */ | 65 | if (!checkbuffer(z)) |
52 | if (luaZ_fill(z) == EOZ) /* try to read more */ | 66 | return n; /* no more input; return number of missing bytes */ |
53 | return n; /* no more input; return number of missing bytes */ | ||
54 | else { | ||
55 | z->n++; /* luaZ_fill consumed first byte; put it back */ | ||
56 | z->p--; | ||
57 | } | ||
58 | } | ||
59 | m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ | 67 | m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ |
60 | memcpy(b, z->p, m); | 68 | memcpy(b, z->p, m); |
61 | z->n -= m; | 69 | z->n -= m; |
@@ -66,3 +74,15 @@ size_t luaZ_read (ZIO *z, void *b, size_t n) { | |||
66 | return 0; | 74 | return 0; |
67 | } | 75 | } |
68 | 76 | ||
77 | |||
78 | const void *luaZ_getaddr (ZIO* z, size_t n) { | ||
79 | const void *res; | ||
80 | if (!checkbuffer(z)) | ||
81 | return NULL; /* no more input */ | ||
82 | if (z->n < n) /* not enough bytes? */ | ||
83 | return NULL; /* block not whole; cannot give an address */ | ||
84 | res = z->p; /* get block address */ | ||
85 | z->n -= n; /* consume these bytes */ | ||
86 | z->p += n; | ||
87 | return res; | ||
88 | } | ||
@@ -48,6 +48,7 @@ LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, | |||
48 | void *data); | 48 | void *data); |
49 | LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */ | 49 | LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */ |
50 | 50 | ||
51 | LUAI_FUNC const void *luaZ_getaddr (ZIO* z, size_t n); | ||
51 | 52 | ||
52 | 53 | ||
53 | /* --------- Private Part ------------------ */ | 54 | /* --------- Private Part ------------------ */ |
diff --git a/manual/manual.of b/manual/manual.of index ad120f5e..3eab69fa 100644 --- a/manual/manual.of +++ b/manual/manual.of | |||
@@ -1467,7 +1467,7 @@ It has the following syntax: | |||
1467 | exp @bnfter{,} exp @bnfopt{@bnfter{,} exp} @Rw{do} block @Rw{end}} | 1467 | exp @bnfter{,} exp @bnfopt{@bnfter{,} exp} @Rw{do} block @Rw{end}} |
1468 | } | 1468 | } |
1469 | The given identifier (@bnfNter{Name}) defines the control variable, | 1469 | The given identifier (@bnfNter{Name}) defines the control variable, |
1470 | which is a new variable local to the loop body (@emph{block}). | 1470 | which is a new read-only variable local to the loop body (@emph{block}). |
1471 | 1471 | ||
1472 | The loop starts by evaluating once the three control expressions. | 1472 | The loop starts by evaluating once the three control expressions. |
1473 | Their values are called respectively | 1473 | Their values are called respectively |
@@ -1499,11 +1499,6 @@ For integer loops, | |||
1499 | the control variable never wraps around; | 1499 | the control variable never wraps around; |
1500 | instead, the loop ends in case of an overflow. | 1500 | instead, the loop ends in case of an overflow. |
1501 | 1501 | ||
1502 | You should not change the value of the control variable | ||
1503 | during the loop. | ||
1504 | If you need its value after the loop, | ||
1505 | assign it to another variable before exiting the loop. | ||
1506 | |||
1507 | } | 1502 | } |
1508 | 1503 | ||
1509 | @sect4{@title{The generic @Rw{for} loop} | 1504 | @sect4{@title{The generic @Rw{for} loop} |
@@ -1526,7 +1521,8 @@ for @rep{var_1}, @Cdots, @rep{var_n} in @rep{explist} do @rep{body} end | |||
1526 | works as follows. | 1521 | works as follows. |
1527 | 1522 | ||
1528 | The names @rep{var_i} declare loop variables local to the loop body. | 1523 | The names @rep{var_i} declare loop variables local to the loop body. |
1529 | The first of these variables is the @emph{control variable}. | 1524 | The first of these variables is the @emph{control variable}, |
1525 | which is a read-only variable. | ||
1530 | 1526 | ||
1531 | The loop starts by evaluating @rep{explist} | 1527 | The loop starts by evaluating @rep{explist} |
1532 | to produce four values: | 1528 | to produce four values: |
@@ -1550,9 +1546,6 @@ to-be-closed variable @see{to-be-closed}, | |||
1550 | which can be used to release resources when the loop ends. | 1546 | which can be used to release resources when the loop ends. |
1551 | Otherwise, it does not interfere with the loop. | 1547 | Otherwise, it does not interfere with the loop. |
1552 | 1548 | ||
1553 | You should not change the value of the control variable | ||
1554 | during the loop. | ||
1555 | |||
1556 | } | 1549 | } |
1557 | 1550 | ||
1558 | } | 1551 | } |
@@ -1586,7 +1579,8 @@ Each variable name may be postfixed by an attribute | |||
1586 | @producname{attrib}@producbody{@bnfopt{@bnfter{<} @bnfNter{Name} @bnfter{>}}} | 1579 | @producname{attrib}@producbody{@bnfopt{@bnfter{<} @bnfNter{Name} @bnfter{>}}} |
1587 | } | 1580 | } |
1588 | There are two possible attributes: | 1581 | There are two possible attributes: |
1589 | @id{const}, which declares a @x{constant variable}, | 1582 | @id{const}, which declares a @emph{constant} or @emph{read-only} variable, |
1583 | @index{constant variable} | ||
1590 | that is, a variable that cannot be assigned to | 1584 | that is, a variable that cannot be assigned to |
1591 | after its initialization; | 1585 | after its initialization; |
1592 | and @id{close}, which declares a to-be-closed variable @see{to-be-closed}. | 1586 | and @id{close}, which declares a to-be-closed variable @see{to-be-closed}. |
@@ -2736,7 +2730,8 @@ For such errors, Lua does not call the @x{message handler}. | |||
2736 | 2730 | ||
2737 | @item{@defid{LUA_ERRERR}| error while running the @x{message handler}.} | 2731 | @item{@defid{LUA_ERRERR}| error while running the @x{message handler}.} |
2738 | 2732 | ||
2739 | @item{@defid{LUA_ERRSYNTAX}| syntax error during precompilation.} | 2733 | @item{@defid{LUA_ERRSYNTAX}| syntax error during precompilation |
2734 | or format error in a binary chunk.} | ||
2740 | 2735 | ||
2741 | @item{@defid{LUA_YIELD}| the thread (coroutine) yields.} | 2736 | @item{@defid{LUA_YIELD}| the thread (coroutine) yields.} |
2742 | 2737 | ||
@@ -3652,6 +3647,18 @@ and loads it accordingly (see program @idx{luac}). | |||
3652 | The string @id{mode} works as in function @Lid{load}, | 3647 | The string @id{mode} works as in function @Lid{load}, |
3653 | with the addition that | 3648 | with the addition that |
3654 | a @id{NULL} value is equivalent to the string @St{bt}. | 3649 | a @id{NULL} value is equivalent to the string @St{bt}. |
3650 | Moreover, it may have a @Char{B} instead of a @Char{b}, | ||
3651 | meaning a @emphx{fixed buffer} with the binary dump. | ||
3652 | |||
3653 | A fixed buffer means that the address returned by the reader function | ||
3654 | should contain the chunk until everything created by the chunk has | ||
3655 | been collected. | ||
3656 | (In general, a fixed buffer would keep the chunk | ||
3657 | as its contents until the end of the program, | ||
3658 | for instance with the chunk in ROM.) | ||
3659 | Moreover, for a fixed buffer, | ||
3660 | the reader function should return the entire chunk in the first read. | ||
3661 | (As an example, @Lid{luaL_loadbufferx} does that.) | ||
3655 | 3662 | ||
3656 | @id{lua_load} uses the stack internally, | 3663 | @id{lua_load} uses the stack internally, |
3657 | so the reader function must always leave the stack | 3664 | so the reader function must always leave the stack |
@@ -3671,7 +3678,8 @@ Other upvalues are initialized with @nil. | |||
3671 | 3678 | ||
3672 | } | 3679 | } |
3673 | 3680 | ||
3674 | @APIEntry{lua_State *lua_newstate (lua_Alloc f, void *ud);| | 3681 | @APIEntry{lua_State *lua_newstate (lua_Alloc f, void *ud, |
3682 | unsigned int seed);| | ||
3675 | @apii{0,0,-} | 3683 | @apii{0,0,-} |
3676 | 3684 | ||
3677 | Creates a new independent state and returns its main thread. | 3685 | Creates a new independent state and returns its main thread. |
@@ -3682,6 +3690,8 @@ Lua will do all memory allocation for this state | |||
3682 | through this function @seeF{lua_Alloc}. | 3690 | through this function @seeF{lua_Alloc}. |
3683 | The second argument, @id{ud}, is an opaque pointer that Lua | 3691 | The second argument, @id{ud}, is an opaque pointer that Lua |
3684 | passes to the allocator in every call. | 3692 | passes to the allocator in every call. |
3693 | The third argument, @id{seed}, is a seed for the hashing of | ||
3694 | strings when they are used as table keys. | ||
3685 | 3695 | ||
3686 | } | 3696 | } |
3687 | 3697 | ||
@@ -5691,6 +5701,8 @@ This function returns the same results as @Lid{lua_load}. | |||
5691 | @id{name} is the chunk name, | 5701 | @id{name} is the chunk name, |
5692 | used for debug information and error messages. | 5702 | used for debug information and error messages. |
5693 | The string @id{mode} works as in the function @Lid{lua_load}. | 5703 | The string @id{mode} works as in the function @Lid{lua_load}. |
5704 | In particular, this function supports mode @Char{B} for | ||
5705 | fixed buffers. | ||
5694 | 5706 | ||
5695 | } | 5707 | } |
5696 | 5708 | ||
@@ -5737,6 +5749,16 @@ it does not run it. | |||
5737 | 5749 | ||
5738 | } | 5750 | } |
5739 | 5751 | ||
5752 | @APIEntry{unsigned int luaL_makeseed (lua_State *L);| | ||
5753 | @apii{0,0,-} | ||
5754 | |||
5755 | Returns a value with a weak attempt for randomness. | ||
5756 | (It produces that value based on the current date and time | ||
5757 | and the address of an internal variable, | ||
5758 | in case the machine has Address Space Layout Randomization.) | ||
5759 | |||
5760 | } | ||
5761 | |||
5740 | 5762 | ||
5741 | @APIEntry{void luaL_newlib (lua_State *L, const luaL_Reg l[]);| | 5763 | @APIEntry{void luaL_newlib (lua_State *L, const luaL_Reg l[]);| |
5742 | @apii{0,1,m} | 5764 | @apii{0,1,m} |
@@ -6909,9 +6931,9 @@ including if necessary a path and an extension. | |||
6909 | (which may depend on the @N{C compiler} and linker used). | 6931 | (which may depend on the @N{C compiler} and linker used). |
6910 | 6932 | ||
6911 | This functionality is not supported by @N{ISO C}. | 6933 | This functionality is not supported by @N{ISO C}. |
6912 | As such, it is only available on some platforms | 6934 | As such, @id{loadlib} is only available on some platforms: |
6913 | (Windows, Linux, Mac OS X, Solaris, BSD, | 6935 | Linux, Windows, Mac OS X, Solaris, BSD, |
6914 | plus other Unix systems that support the @id{dlfcn} standard). | 6936 | plus other Unix systems that support the @id{dlfcn} standard. |
6915 | 6937 | ||
6916 | This function is inherently insecure, | 6938 | This function is inherently insecure, |
6917 | as it allows Lua to call any function in any readable dynamic | 6939 | as it allows Lua to call any function in any readable dynamic |
@@ -8109,7 +8131,7 @@ different sequences of results each time the program runs. | |||
8109 | 8131 | ||
8110 | When called with at least one argument, | 8132 | When called with at least one argument, |
8111 | the integer parameters @id{x} and @id{y} are | 8133 | the integer parameters @id{x} and @id{y} are |
8112 | joined into a 128-bit @emphx{seed} that | 8134 | joined into a @emphx{seed} that |
8113 | is used to reinitialize the pseudo-random generator; | 8135 | is used to reinitialize the pseudo-random generator; |
8114 | equal seeds produce equal sequences of numbers. | 8136 | equal seeds produce equal sequences of numbers. |
8115 | The default for @id{y} is zero. | 8137 | The default for @id{y} is zero. |
@@ -9132,7 +9154,7 @@ is a more portable solution. | |||
9132 | @simplesect{ | 9154 | @simplesect{ |
9133 | 9155 | ||
9134 | Here we list the incompatibilities that you may find when moving a program | 9156 | Here we list the incompatibilities that you may find when moving a program |
9135 | from @N{Lua 5.3} to @N{Lua 5.4}. | 9157 | from @N{Lua 5.4} to @N{Lua 5.5}. |
9136 | 9158 | ||
9137 | You can avoid some incompatibilities by compiling Lua with | 9159 | You can avoid some incompatibilities by compiling Lua with |
9138 | appropriate options (see file @id{luaconf.h}). | 9160 | appropriate options (see file @id{luaconf.h}). |
@@ -9169,51 +9191,9 @@ change between versions. | |||
9169 | @itemize{ | 9191 | @itemize{ |
9170 | 9192 | ||
9171 | @item{ | 9193 | @item{ |
9172 | The coercion of strings to numbers in | 9194 | The control variable in @Rw{for} loops are read only. |
9173 | arithmetic and bitwise operations | 9195 | If you need to change it, |
9174 | has been removed from the core language. | 9196 | declare a local variable with the same name in the loop body. |
9175 | The string library does a similar job | ||
9176 | for arithmetic (but not for bitwise) operations | ||
9177 | using the string metamethods. | ||
9178 | However, unlike in previous versions, | ||
9179 | the new implementation preserves the implicit type of the numeral | ||
9180 | in the string. | ||
9181 | For instance, the result of @T{"1" + "2"} now is an integer, | ||
9182 | not a float. | ||
9183 | } | ||
9184 | |||
9185 | @item{ | ||
9186 | Literal decimal integer constants that overflow are read as floats, | ||
9187 | instead of wrapping around. | ||
9188 | You can use hexadecimal notation for such constants if you | ||
9189 | want the old behavior | ||
9190 | (reading them as integers with wrap around). | ||
9191 | } | ||
9192 | |||
9193 | @item{ | ||
9194 | The use of the @idx{__lt} metamethod to emulate @idx{__le} | ||
9195 | has been removed. | ||
9196 | When needed, this metamethod must be explicitly defined. | ||
9197 | } | ||
9198 | |||
9199 | @item{ | ||
9200 | The semantics of the numerical @Rw{for} loop | ||
9201 | over integers changed in some details. | ||
9202 | In particular, the control variable never wraps around. | ||
9203 | } | ||
9204 | |||
9205 | @item{ | ||
9206 | A label for a @Rw{goto} cannot be declared where a label with the same | ||
9207 | name is visible, even if this other label is declared in an enclosing | ||
9208 | block. | ||
9209 | } | ||
9210 | |||
9211 | @item{ | ||
9212 | When finalizing an object, | ||
9213 | Lua does not ignore @idx{__gc} metamethods that are not functions. | ||
9214 | Any value will be called, if present. | ||
9215 | (Non-callable values will generate a warning, | ||
9216 | like any other error when calling a finalizer.) | ||
9217 | } | 9197 | } |
9218 | 9198 | ||
9219 | } | 9199 | } |
@@ -9224,39 +9204,6 @@ like any other error when calling a finalizer.) | |||
9224 | @itemize{ | 9204 | @itemize{ |
9225 | 9205 | ||
9226 | @item{ | 9206 | @item{ |
9227 | The function @Lid{print} does not call @Lid{tostring} | ||
9228 | to format its arguments; | ||
9229 | instead, it has this functionality hardwired. | ||
9230 | You should use @idx{__tostring} to modify how values are printed. | ||
9231 | } | ||
9232 | |||
9233 | @item{ | ||
9234 | The pseudo-random number generator used by the function @Lid{math.random} | ||
9235 | now starts with a somewhat random seed. | ||
9236 | Moreover, it uses a different algorithm. | ||
9237 | } | ||
9238 | |||
9239 | @item{ | ||
9240 | By default, the decoding functions in the @Lid{utf8} library | ||
9241 | do not accept surrogates as valid code points. | ||
9242 | An extra parameter in these functions makes them more permissive. | ||
9243 | } | ||
9244 | |||
9245 | @item{ | ||
9246 | The options @St{setpause} and @St{setstepmul} | ||
9247 | of the function @Lid{collectgarbage} are deprecated. | ||
9248 | You should use the new option @St{incremental} to set them. | ||
9249 | } | ||
9250 | |||
9251 | @item{ | ||
9252 | The function @Lid{io.lines} now returns four values, | ||
9253 | instead of just one. | ||
9254 | That can be a problem when it is used as the sole | ||
9255 | argument to another function that has optional parameters, | ||
9256 | such as in @T{load(io.lines(filename, "L"))}. | ||
9257 | To fix that issue, | ||
9258 | you can wrap the call into parentheses, | ||
9259 | to adjust its number of results to one. | ||
9260 | } | 9207 | } |
9261 | 9208 | ||
9262 | } | 9209 | } |
@@ -9268,46 +9215,6 @@ to adjust its number of results to one. | |||
9268 | @itemize{ | 9215 | @itemize{ |
9269 | 9216 | ||
9270 | @item{ | 9217 | @item{ |
9271 | Full userdata now has an arbitrary number of associated user values. | ||
9272 | Therefore, the functions @id{lua_newuserdata}, | ||
9273 | @id{lua_setuservalue}, and @id{lua_getuservalue} were | ||
9274 | replaced by @Lid{lua_newuserdatauv}, | ||
9275 | @Lid{lua_setiuservalue}, and @Lid{lua_getiuservalue}, | ||
9276 | which have an extra argument. | ||
9277 | |||
9278 | For compatibility, the old names still work as macros assuming | ||
9279 | one single user value. | ||
9280 | Note, however, that userdata with zero user values | ||
9281 | are more efficient memory-wise. | ||
9282 | } | ||
9283 | |||
9284 | @item{ | ||
9285 | The function @Lid{lua_resume} has an extra parameter. | ||
9286 | This out parameter returns the number of values on | ||
9287 | the top of the stack that were yielded or returned by the coroutine. | ||
9288 | (In previous versions, | ||
9289 | those values were the entire stack.) | ||
9290 | } | ||
9291 | |||
9292 | @item{ | ||
9293 | The function @Lid{lua_version} returns the version number, | ||
9294 | instead of an address of the version number. | ||
9295 | The Lua core should work correctly with libraries using their | ||
9296 | own static copies of the same core, | ||
9297 | so there is no need to check whether they are using the same | ||
9298 | address space. | ||
9299 | } | ||
9300 | |||
9301 | @item{ | ||
9302 | The constant @id{LUA_ERRGCMM} was removed. | ||
9303 | Errors in finalizers are never propagated; | ||
9304 | instead, they generate a warning. | ||
9305 | } | ||
9306 | |||
9307 | @item{ | ||
9308 | The options @idx{LUA_GCSETPAUSE} and @idx{LUA_GCSETSTEPMUL} | ||
9309 | of the function @Lid{lua_gc} are deprecated. | ||
9310 | You should use the new option @id{LUA_GCINC} to set them. | ||
9311 | } | 9218 | } |
9312 | 9219 | ||
9313 | } | 9220 | } |
diff --git a/testes/all.lua b/testes/all.lua index 5df0ff9b..3c1ff5c7 100644 --- a/testes/all.lua +++ b/testes/all.lua | |||
@@ -3,7 +3,7 @@ | |||
3 | -- See Copyright Notice at the end of this file | 3 | -- See Copyright Notice at the end of this file |
4 | 4 | ||
5 | 5 | ||
6 | local version = "Lua 5.4" | 6 | local version = "Lua 5.5" |
7 | if _VERSION ~= version then | 7 | if _VERSION ~= version then |
8 | io.stderr:write("This test suite is for ", version, | 8 | io.stderr:write("This test suite is for ", version, |
9 | ", not for ", _VERSION, "\nExiting tests") | 9 | ", not for ", _VERSION, "\nExiting tests") |
diff --git a/testes/api.lua b/testes/api.lua index 752ff18f..181c1d53 100644 --- a/testes/api.lua +++ b/testes/api.lua | |||
@@ -407,7 +407,7 @@ do | |||
407 | concat 3]]) == "hi alo mundo") | 407 | concat 3]]) == "hi alo mundo") |
408 | 408 | ||
409 | -- "argerror" without frames | 409 | -- "argerror" without frames |
410 | assert(T.checkpanic("loadstring 4") == | 410 | assert(T.checkpanic("loadstring 4 name bt") == |
411 | "bad argument #4 (string expected, got no value)") | 411 | "bad argument #4 (string expected, got no value)") |
412 | 412 | ||
413 | 413 | ||
@@ -420,7 +420,7 @@ do | |||
420 | if not _soft then | 420 | if not _soft then |
421 | local msg = T.checkpanic[[ | 421 | local msg = T.checkpanic[[ |
422 | pushstring "function f() f() end" | 422 | pushstring "function f() f() end" |
423 | loadstring -1; call 0 0 | 423 | loadstring -1 name t; call 0 0 |
424 | getglobal f; call 0 0 | 424 | getglobal f; call 0 0 |
425 | ]] | 425 | ]] |
426 | assert(string.find(msg, "stack overflow")) | 426 | assert(string.find(msg, "stack overflow")) |
@@ -430,7 +430,7 @@ do | |||
430 | assert(T.checkpanic([[ | 430 | assert(T.checkpanic([[ |
431 | pushstring "return {__close = function () Y = 'ho'; end}" | 431 | pushstring "return {__close = function () Y = 'ho'; end}" |
432 | newtable | 432 | newtable |
433 | loadstring -2 | 433 | loadstring -2 name t |
434 | call 0 1 | 434 | call 0 1 |
435 | setmetatable -2 | 435 | setmetatable -2 |
436 | toclose -1 | 436 | toclose -1 |
@@ -458,6 +458,8 @@ if not _soft then | |||
458 | print'+' | 458 | print'+' |
459 | end | 459 | end |
460 | 460 | ||
461 | |||
462 | |||
461 | local lim = _soft and 500 or 12000 | 463 | local lim = _soft and 500 or 12000 |
462 | local prog = {"checkstack " .. (lim * 2 + 100) .. "msg", "newtable"} | 464 | local prog = {"checkstack " .. (lim * 2 + 100) .. "msg", "newtable"} |
463 | for i = 1,lim do | 465 | for i = 1,lim do |
@@ -481,10 +483,20 @@ for i = 1,lim do assert(t[i] == i*10); t[i] = undef end | |||
481 | assert(next(t) == nil) | 483 | assert(next(t) == nil) |
482 | prog, g, t = nil | 484 | prog, g, t = nil |
483 | 485 | ||
486 | do -- shrink stack | ||
487 | local m1, m2 = 0, collectgarbage"count" * 1024 | ||
488 | while m1 ~= m2 do -- repeat until stable | ||
489 | collectgarbage() | ||
490 | m1 = m2 | ||
491 | m2 = collectgarbage"count" * 1024 | ||
492 | end | ||
493 | end | ||
494 | |||
495 | |||
484 | -- testing errors | 496 | -- testing errors |
485 | 497 | ||
486 | a = T.testC([[ | 498 | a = T.testC([[ |
487 | loadstring 2; pcall 0 1 0; | 499 | loadstring 2 name t; pcall 0 1 0; |
488 | pushvalue 3; insert -2; pcall 1 1 0; | 500 | pushvalue 3; insert -2; pcall 1 1 0; |
489 | pcall 0 0 0; | 501 | pcall 0 0 0; |
490 | return 1 | 502 | return 1 |
@@ -498,7 +510,7 @@ local function check3(p, ...) | |||
498 | assert(#arg == 3) | 510 | assert(#arg == 3) |
499 | assert(string.find(arg[3], p)) | 511 | assert(string.find(arg[3], p)) |
500 | end | 512 | end |
501 | check3(":1:", T.testC("loadstring 2; return *", "x=")) | 513 | check3(":1:", T.testC("loadstring 2 name t; return *", "x=")) |
502 | check3("%.", T.testC("loadfile 2; return *", ".")) | 514 | check3("%.", T.testC("loadfile 2; return *", ".")) |
503 | check3("xxxx", T.testC("loadfile 2; return *", "xxxx")) | 515 | check3("xxxx", T.testC("loadfile 2; return *", "xxxx")) |
504 | 516 | ||
@@ -509,6 +521,35 @@ local function checkerrnopro (code, msg) | |||
509 | assert(not stt and string.find(err, msg)) | 521 | assert(not stt and string.find(err, msg)) |
510 | end | 522 | end |
511 | 523 | ||
524 | |||
525 | do | ||
526 | print("testing load of binaries in fixed buffers") | ||
527 | local source = {} | ||
528 | local N = 1000 | ||
529 | -- create a somewhat "large" source | ||
530 | for i = 1, N do source[i] = "X = X + 1; " end | ||
531 | source = table.concat(source) | ||
532 | -- give chunk an explicit name to avoid using source as name | ||
533 | source = load(source, "name1") | ||
534 | -- dump without debug information | ||
535 | source = string.dump(source, true) | ||
536 | -- each "X=X+1" generates 4 opcodes with 4 bytes each | ||
537 | assert(#source > N * 4 * 4) | ||
538 | collectgarbage(); collectgarbage() | ||
539 | local m1 = collectgarbage"count" * 1024 | ||
540 | -- load dump using fixed buffer | ||
541 | local code = T.testC([[ | ||
542 | loadstring 2 name B; | ||
543 | return 1 | ||
544 | ]], source) | ||
545 | collectgarbage() | ||
546 | local m2 = collectgarbage"count" * 1024 | ||
547 | -- load used fewer than 300 bytes | ||
548 | assert(m2 > m1 and m2 - m1 < 300) | ||
549 | X = 0; code(); assert(X == N); X = nil | ||
550 | end | ||
551 | |||
552 | |||
512 | if not _soft then | 553 | if not _soft then |
513 | collectgarbage("stop") -- avoid __gc with full stack | 554 | collectgarbage("stop") -- avoid __gc with full stack |
514 | checkerrnopro("pushnum 3; call 0 0", "attempt to call") | 555 | checkerrnopro("pushnum 3; call 0 0", "attempt to call") |
@@ -1046,10 +1087,12 @@ assert(a == nil and c == 2) -- 2 == run-time error | |||
1046 | a, b, c = T.doremote(L1, "return a+") | 1087 | a, b, c = T.doremote(L1, "return a+") |
1047 | assert(a == nil and c == 3 and type(b) == "string") -- 3 == syntax error | 1088 | assert(a == nil and c == 3 and type(b) == "string") -- 3 == syntax error |
1048 | 1089 | ||
1049 | T.loadlib(L1) | 1090 | T.loadlib(L1, 2) -- load only 'package' |
1050 | a, b, c = T.doremote(L1, [[ | 1091 | a, b, c = T.doremote(L1, [[ |
1051 | string = require'string' | 1092 | string = require'string' |
1052 | a = require'_G'; assert(a == _G and require("_G") == a) | 1093 | local initialG = _G -- not loaded yet |
1094 | local a = require'_G'; assert(a == _G and require("_G") == a) | ||
1095 | assert(initialG == nil and io == nil) -- now we have 'assert' | ||
1053 | io = require'io'; assert(type(io.read) == "function") | 1096 | io = require'io'; assert(type(io.read) == "function") |
1054 | assert(require("io") == io) | 1097 | assert(require("io") == io) |
1055 | a = require'table'; assert(type(a.insert) == "function") | 1098 | a = require'table'; assert(type(a.insert) == "function") |
@@ -1063,7 +1106,7 @@ T.closestate(L1); | |||
1063 | 1106 | ||
1064 | 1107 | ||
1065 | L1 = T.newstate() | 1108 | L1 = T.newstate() |
1066 | T.loadlib(L1) | 1109 | T.loadlib(L1, 0) |
1067 | T.doremote(L1, "a = {}") | 1110 | T.doremote(L1, "a = {}") |
1068 | T.testC(L1, [[getglobal "a"; pushstring "x"; pushint 1; | 1111 | T.testC(L1, [[getglobal "a"; pushstring "x"; pushint 1; |
1069 | settable -3]]) | 1112 | settable -3]]) |
@@ -1446,10 +1489,10 @@ end | |||
1446 | 1489 | ||
1447 | do -- garbage collection with no extra memory | 1490 | do -- garbage collection with no extra memory |
1448 | local L = T.newstate() | 1491 | local L = T.newstate() |
1449 | T.loadlib(L) | 1492 | T.loadlib(L, 1 | 2) -- load _G and 'package' |
1450 | local res = (T.doremote(L, [[ | 1493 | local res = (T.doremote(L, [[ |
1451 | _ENV = require"_G" | 1494 | _ENV = _G |
1452 | local T = require"T" | 1495 | assert(string == nil) |
1453 | local a = {} | 1496 | local a = {} |
1454 | for i = 1, 1000 do a[i] = 'i' .. i end -- grow string table | 1497 | for i = 1, 1000 do a[i] = 'i' .. i end -- grow string table |
1455 | local stsize, stuse = T.querystr() | 1498 | local stsize, stuse = T.querystr() |
diff --git a/testes/attrib.lua b/testes/attrib.lua index 458488a8..9054e0b6 100644 --- a/testes/attrib.lua +++ b/testes/attrib.lua | |||
@@ -236,7 +236,7 @@ package.path = oldpath | |||
236 | local fname = "file_does_not_exist2" | 236 | local fname = "file_does_not_exist2" |
237 | local m, err = pcall(require, fname) | 237 | local m, err = pcall(require, fname) |
238 | for t in string.gmatch(package.path..";"..package.cpath, "[^;]+") do | 238 | for t in string.gmatch(package.path..";"..package.cpath, "[^;]+") do |
239 | t = string.gsub(t, "?", fname) | 239 | local t = string.gsub(t, "?", fname) |
240 | assert(string.find(err, t, 1, true)) | 240 | assert(string.find(err, t, 1, true)) |
241 | end | 241 | end |
242 | 242 | ||
diff --git a/testes/calls.lua b/testes/calls.lua index a1938584..9a5eed0b 100644 --- a/testes/calls.lua +++ b/testes/calls.lua | |||
@@ -454,7 +454,7 @@ print("testing binary chunks") | |||
454 | do | 454 | do |
455 | local header = string.pack("c4BBc6BBB", | 455 | local header = string.pack("c4BBc6BBB", |
456 | "\27Lua", -- signature | 456 | "\27Lua", -- signature |
457 | 0x54, -- version 5.4 (0x54) | 457 | 0x55, -- version 5.5 (0x55) |
458 | 0, -- format | 458 | 0, -- format |
459 | "\x19\x93\r\n\x1a\n", -- data | 459 | "\x19\x93\r\n\x1a\n", -- data |
460 | 4, -- size of instruction | 460 | 4, -- size of instruction |
@@ -493,5 +493,30 @@ do | |||
493 | end | 493 | end |
494 | end | 494 | end |
495 | 495 | ||
496 | |||
497 | do -- check reuse of strings in dumps | ||
498 | local str = "|" .. string.rep("X", 50) .. "|" | ||
499 | local foo = load(string.format([[ | ||
500 | local str <const> = "%s" | ||
501 | return { | ||
502 | function () return str end, | ||
503 | function () return str end, | ||
504 | function () return str end | ||
505 | } | ||
506 | ]], str)) | ||
507 | -- count occurrences of 'str' inside the dump | ||
508 | local dump = string.dump(foo) | ||
509 | local _, count = string.gsub(dump, str, {}) | ||
510 | -- there should be only two occurrences: | ||
511 | -- one inside the source, other the string itself. | ||
512 | assert(count == 2) | ||
513 | |||
514 | if T then -- check reuse of strings in undump | ||
515 | local funcs = load(dump)() | ||
516 | assert(string.format("%p", T.listk(funcs[1])[1]) == | ||
517 | string.format("%p", T.listk(funcs[3])[1])) | ||
518 | end | ||
519 | end | ||
520 | |||
496 | print('OK') | 521 | print('OK') |
497 | return deep | 522 | return deep |
diff --git a/testes/closure.lua b/testes/closure.lua index ea038e82..de1b54ec 100644 --- a/testes/closure.lua +++ b/testes/closure.lua | |||
@@ -60,32 +60,29 @@ end | |||
60 | -- testing closures with 'for' control variable | 60 | -- testing closures with 'for' control variable |
61 | a = {} | 61 | a = {} |
62 | for i=1,10 do | 62 | for i=1,10 do |
63 | a[i] = {set = function(x) i=x end, get = function () return i end} | 63 | a[i] = function () return i end |
64 | if i == 3 then break end | 64 | if i == 3 then break end |
65 | end | 65 | end |
66 | assert(a[4] == undef) | 66 | assert(a[4] == undef) |
67 | a[1].set(10) | 67 | assert(a[2]() == 2) |
68 | assert(a[2].get() == 2) | 68 | assert(a[3]() == 3) |
69 | a[2].set('a') | ||
70 | assert(a[3].get() == 3) | ||
71 | assert(a[2].get() == 'a') | ||
72 | 69 | ||
73 | a = {} | 70 | a = {} |
74 | local t = {"a", "b"} | 71 | local t = {"a", "b"} |
75 | for i = 1, #t do | 72 | for i = 1, #t do |
76 | local k = t[i] | 73 | local k = t[i] |
77 | a[i] = {set = function(x, y) i=x; k=y end, | 74 | a[i] = {set = function(x) k=x end, |
78 | get = function () return i, k end} | 75 | get = function () return i, k end} |
79 | if i == 2 then break end | 76 | if i == 2 then break end |
80 | end | 77 | end |
81 | a[1].set(10, 20) | 78 | a[1].set(10) |
82 | local r,s = a[2].get() | 79 | local r,s = a[2].get() |
83 | assert(r == 2 and s == 'b') | 80 | assert(r == 2 and s == 'b') |
84 | r,s = a[1].get() | 81 | r,s = a[1].get() |
85 | assert(r == 10 and s == 20) | 82 | assert(r == 1 and s == 10) |
86 | a[2].set('a', 'b') | 83 | a[2].set('a') |
87 | r,s = a[2].get() | 84 | r,s = a[2].get() |
88 | assert(r == "a" and s == "b") | 85 | assert(r == 2 and s == "a") |
89 | 86 | ||
90 | 87 | ||
91 | -- testing closures with 'for' control variable x break | 88 | -- testing closures with 'for' control variable x break |
diff --git a/testes/coroutine.lua b/testes/coroutine.lua index de7e46fb..990da8c4 100644 --- a/testes/coroutine.lua +++ b/testes/coroutine.lua | |||
@@ -703,7 +703,7 @@ else | |||
703 | 703 | ||
704 | T.testC(state, "settop 0") | 704 | T.testC(state, "settop 0") |
705 | 705 | ||
706 | T.loadlib(state) | 706 | T.loadlib(state, 1 | 2) -- load _G and 'package' |
707 | 707 | ||
708 | assert(T.doremote(state, [[ | 708 | assert(T.doremote(state, [[ |
709 | coroutine = require'coroutine'; | 709 | coroutine = require'coroutine'; |
diff --git a/testes/files.lua b/testes/files.lua index 1476006e..2582406f 100644 --- a/testes/files.lua +++ b/testes/files.lua | |||
@@ -427,12 +427,12 @@ do -- testing closing file in line iteration | |||
427 | -- get the to-be-closed variable from a loop | 427 | -- get the to-be-closed variable from a loop |
428 | local function gettoclose (lv) | 428 | local function gettoclose (lv) |
429 | lv = lv + 1 | 429 | lv = lv + 1 |
430 | local stvar = 0 -- to-be-closed is 4th state variable in the loop | 430 | local stvar = 0 -- to-be-closed is 3th state variable in the loop |
431 | for i = 1, 1000 do | 431 | for i = 1, 1000 do |
432 | local n, v = debug.getlocal(lv, i) | 432 | local n, v = debug.getlocal(lv, i) |
433 | if n == "(for state)" then | 433 | if n == "(for state)" then |
434 | stvar = stvar + 1 | 434 | stvar = stvar + 1 |
435 | if stvar == 4 then return v end | 435 | if stvar == 3 then return v end |
436 | end | 436 | end |
437 | end | 437 | end |
438 | end | 438 | end |
diff --git a/testes/main.lua b/testes/main.lua index 11b14b44..dde72a74 100644 --- a/testes/main.lua +++ b/testes/main.lua | |||
@@ -137,7 +137,7 @@ RUN('env LUA_INIT= LUA_PATH=x lua %s > %s', prog, out) | |||
137 | checkout("x\n") | 137 | checkout("x\n") |
138 | 138 | ||
139 | -- test LUA_PATH_version | 139 | -- test LUA_PATH_version |
140 | RUN('env LUA_INIT= LUA_PATH_5_4=y LUA_PATH=x lua %s > %s', prog, out) | 140 | RUN('env LUA_INIT= LUA_PATH_5_5=y LUA_PATH=x lua %s > %s', prog, out) |
141 | checkout("y\n") | 141 | checkout("y\n") |
142 | 142 | ||
143 | -- test LUA_CPATH | 143 | -- test LUA_CPATH |
@@ -146,7 +146,7 @@ RUN('env LUA_INIT= LUA_CPATH=xuxu lua %s > %s', prog, out) | |||
146 | checkout("xuxu\n") | 146 | checkout("xuxu\n") |
147 | 147 | ||
148 | -- test LUA_CPATH_version | 148 | -- test LUA_CPATH_version |
149 | RUN('env LUA_INIT= LUA_CPATH_5_4=yacc LUA_CPATH=x lua %s > %s', prog, out) | 149 | RUN('env LUA_INIT= LUA_CPATH_5_5=yacc LUA_CPATH=x lua %s > %s', prog, out) |
150 | checkout("yacc\n") | 150 | checkout("yacc\n") |
151 | 151 | ||
152 | -- test LUA_INIT (and its access to 'arg' table) | 152 | -- test LUA_INIT (and its access to 'arg' table) |
@@ -156,7 +156,7 @@ checkout("3.2\n") | |||
156 | 156 | ||
157 | -- test LUA_INIT_version | 157 | -- test LUA_INIT_version |
158 | prepfile("print(X)") | 158 | prepfile("print(X)") |
159 | RUN('env LUA_INIT_5_4="X=10" LUA_INIT="X=3" lua %s > %s', prog, out) | 159 | RUN('env LUA_INIT_5_5="X=10" LUA_INIT="X=3" lua %s > %s', prog, out) |
160 | checkout("10\n") | 160 | checkout("10\n") |
161 | 161 | ||
162 | -- test LUA_INIT for files | 162 | -- test LUA_INIT for files |
diff --git a/testes/nextvar.lua b/testes/nextvar.lua index 02b7dea2..5d8796f7 100644 --- a/testes/nextvar.lua +++ b/testes/nextvar.lua | |||
@@ -210,9 +210,9 @@ assert(T.querytab(a) == 64) -- array part has 64 elements | |||
210 | a[32] = true; a[48] = true; -- binary search will find these ones | 210 | a[32] = true; a[48] = true; -- binary search will find these ones |
211 | a[51] = true -- binary search will miss this one | 211 | a[51] = true -- binary search will miss this one |
212 | assert(#a == 48) -- this will set the limit | 212 | assert(#a == 48) -- this will set the limit |
213 | assert(select(4, T.querytab(a)) == 48) -- this is the limit now | 213 | assert(select(3, T.querytab(a)) == 48) -- this is the limit now |
214 | a[50] = true -- this will set a new limit | 214 | a[50] = true -- this will set a new limit |
215 | assert(select(4, T.querytab(a)) == 50) -- this is the limit now | 215 | assert(select(3, T.querytab(a)) == 50) -- this is the limit now |
216 | -- but the size is larger (and still inside the array part) | 216 | -- but the size is larger (and still inside the array part) |
217 | assert(#a == 51) | 217 | assert(#a == 51) |
218 | 218 | ||
@@ -609,10 +609,12 @@ do | |||
609 | a = 0; for i=1.0, 0.99999, -1 do a=a+1 end; assert(a==1) | 609 | a = 0; for i=1.0, 0.99999, -1 do a=a+1 end; assert(a==1) |
610 | end | 610 | end |
611 | 611 | ||
612 | do -- changing the control variable | 612 | do -- attempt to change the control variable |
613 | local a | 613 | local st, msg = load "for i = 1, 10 do i = 10 end" |
614 | a = 0; for i = 1, 10 do a = a + 1; i = "x" end; assert(a == 10) | 614 | assert(not st and string.find(msg, "assign to const variable 'i'")) |
615 | a = 0; for i = 10.0, 1, -1 do a = a + 1; i = "x" end; assert(a == 10) | 615 | |
616 | local st, msg = load "for v, k in pairs{} do v = 10 end" | ||
617 | assert(not st and string.find(msg, "assign to const variable 'v'")) | ||
616 | end | 618 | end |
617 | 619 | ||
618 | -- conversion | 620 | -- conversion |