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
@@ -1107,16 +1107,37 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, | |||
1107 | } | 1107 | } |
1108 | 1108 | ||
1109 | 1109 | ||
1110 | /* | ||
1111 | ** Dump a function, calling 'writer' to write its parts. Because the | ||
1112 | ** writer can use the stack in unkown ways, this function should not | ||
1113 | ** push things on the stack, but it must anchor an auxiliary table | ||
1114 | ** used by 'luaU_dump'. To do so, it creates the table, anchors the | ||
1115 | ** function that is on the stack in the table, and substitutes the | ||
1116 | ** table for the function in the stack. | ||
1117 | */ | ||
1118 | |||
1110 | LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) { | 1119 | LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) { |
1111 | int status; | 1120 | int status; |
1121 | StkId fstk; /* pointer to function */ | ||
1112 | TValue *o; | 1122 | TValue *o; |
1113 | lua_lock(L); | 1123 | lua_lock(L); |
1114 | api_checknelems(L, 1); | 1124 | api_checknelems(L, 1); |
1115 | o = s2v(L->top.p - 1); | 1125 | fstk = L->top.p - 1; |
1116 | if (isLfunction(o)) | 1126 | o = s2v(fstk); |
1117 | status = luaU_dump(L, getproto(o), writer, data, strip); | 1127 | if (!isLfunction(o)) |
1118 | else | ||
1119 | status = 1; | 1128 | status = 1; |
1129 | else { | ||
1130 | LClosure *f = clLvalue(o); | ||
1131 | ptrdiff_t fidx = savestack(L, fstk); /* function index */ | ||
1132 | Table *h = luaH_new(L); /* auxiliary table used by 'luaU_dump' */ | ||
1133 | sethvalue2s(L, L->top.p, h); /* anchor it (luaH_set may call GC) */ | ||
1134 | L->top.p++; /* (assume extra slot) */ | ||
1135 | luaH_set(L, h, o, o); /* anchor function into table */ | ||
1136 | setobjs2s(L, fstk, L->top.p - 1); /* move table over function */ | ||
1137 | L->top.p--; /* stack back to initial size */ | ||
1138 | status = luaU_dump(L, f->p, writer, data, strip, h); | ||
1139 | setclLvalue2s(L, restorestack(L, fidx), f); /* put function back */ | ||
1140 | } | ||
1120 | lua_unlock(L); | 1141 | lua_unlock(L); |
1121 | return status; | 1142 | return status; |
1122 | } | 1143 | } |
@@ -1145,7 +1166,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { | |||
1145 | } | 1166 | } |
1146 | case LUA_GCRESTART: { | 1167 | case LUA_GCRESTART: { |
1147 | luaE_setdebt(g, 0); | 1168 | luaE_setdebt(g, 0); |
1148 | g->gcstp = 0; /* (GCSTPGC must be already zero here) */ | 1169 | g->gcstp = 0; /* (bit GCSTPGC must be zero here) */ |
1149 | break; | 1170 | break; |
1150 | } | 1171 | } |
1151 | case LUA_GCCOLLECT: { | 1172 | case LUA_GCCOLLECT: { |
@@ -1154,42 +1175,46 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { | |||
1154 | } | 1175 | } |
1155 | case LUA_GCCOUNT: { | 1176 | case LUA_GCCOUNT: { |
1156 | /* GC values are expressed in Kbytes: #bytes/2^10 */ | 1177 | /* GC values are expressed in Kbytes: #bytes/2^10 */ |
1157 | res = cast_int(gettotalbytes(g) >> 10); | 1178 | res = cast_int(g->totalbytes >> 10); |
1158 | break; | 1179 | break; |
1159 | } | 1180 | } |
1160 | case LUA_GCCOUNTB: { | 1181 | case LUA_GCCOUNTB: { |
1161 | res = cast_int(gettotalbytes(g) & 0x3ff); | 1182 | res = cast_int(g->totalbytes & 0x3ff); |
1162 | break; | 1183 | break; |
1163 | } | 1184 | } |
1164 | case LUA_GCSTEP: { | 1185 | case LUA_GCSTEP: { |
1165 | int data = va_arg(argp, int); | 1186 | int todo = va_arg(argp, int); /* work to be done */ |
1166 | l_mem debt = 1; /* =1 to signal that it did an actual step */ | 1187 | int didsomething = 0; |
1167 | lu_byte oldstp = g->gcstp; | 1188 | lu_byte oldstp = g->gcstp; |
1168 | g->gcstp = 0; /* allow GC to run (GCSTPGC must be zero here) */ | 1189 | g->gcstp = 0; /* allow GC to run (bit GCSTPGC must be zero here) */ |
1169 | if (data == 0) { | 1190 | if (todo == 0) |
1170 | luaE_setdebt(g, 0); /* do a basic step */ | 1191 | todo = 1 << g->gcstepsize; /* standard step size */ |
1171 | luaC_step(L); | 1192 | while (todo >= g->GCdebt) { /* enough to run a step? */ |
1172 | } | 1193 | todo -= g->GCdebt; /* decrement 'todo' */ |
1173 | else { /* add 'data' to total debt */ | 1194 | luaC_step(L); /* run one basic step */ |
1174 | debt = cast(l_mem, data) * 1024 + g->GCdebt; | 1195 | didsomething = 1; |
1175 | luaE_setdebt(g, debt); | 1196 | if (g->gckind == KGC_GEN) /* minor collections? */ |
1176 | luaC_checkGC(L); | 1197 | todo = 0; /* doesn't make sense to repeat in this case */ |
1198 | else if (g->gcstate == GCSpause) | ||
1199 | break; /* don't run more than one cycle */ | ||
1177 | } | 1200 | } |
1201 | /* remove remaining 'todo' from total debt */ | ||
1202 | luaE_setdebt(g, g->GCdebt - todo); | ||
1178 | g->gcstp = oldstp; /* restore previous state */ | 1203 | g->gcstp = oldstp; /* restore previous state */ |
1179 | if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */ | 1204 | if (didsomething && g->gcstate == GCSpause) /* end of cycle? */ |
1180 | res = 1; /* signal it */ | 1205 | res = 1; /* signal it */ |
1181 | break; | 1206 | break; |
1182 | } | 1207 | } |
1183 | case LUA_GCSETPAUSE: { | 1208 | case LUA_GCSETPAUSE: { |
1184 | int data = va_arg(argp, int); | 1209 | unsigned int data = va_arg(argp, unsigned int); |
1185 | res = getgcparam(g->gcpause); | 1210 | res = applygcparam(g, gcpause, 100); |
1186 | setgcparam(g->gcpause, data); | 1211 | setgcparam(g, gcpause, data); |
1187 | break; | 1212 | break; |
1188 | } | 1213 | } |
1189 | case LUA_GCSETSTEPMUL: { | 1214 | case LUA_GCSETSTEPMUL: { |
1190 | int data = va_arg(argp, int); | 1215 | unsigned int data = va_arg(argp, unsigned int); |
1191 | res = getgcparam(g->gcstepmul); | 1216 | res = applygcparam(g, gcstepmul, 100); |
1192 | setgcparam(g->gcstepmul, data); | 1217 | setgcparam(g, gcstepmul, data); |
1193 | break; | 1218 | break; |
1194 | } | 1219 | } |
1195 | case LUA_GCISRUNNING: { | 1220 | case LUA_GCISRUNNING: { |
@@ -1197,27 +1222,28 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { | |||
1197 | break; | 1222 | break; |
1198 | } | 1223 | } |
1199 | case LUA_GCGEN: { | 1224 | case LUA_GCGEN: { |
1200 | int minormul = va_arg(argp, int); | 1225 | unsigned int minormul = va_arg(argp, unsigned int); |
1201 | int majormul = va_arg(argp, int); | 1226 | unsigned int majormul = va_arg(argp, unsigned int); |
1202 | res = isdecGCmodegen(g) ? LUA_GCGEN : LUA_GCINC; | 1227 | res = (g->gckind == KGC_INC) ? LUA_GCINC : LUA_GCGEN; |
1203 | if (minormul != 0) | 1228 | if (minormul != 0) |
1204 | g->genminormul = minormul; | 1229 | setgcparam(g, genminormul, minormul); |
1205 | if (majormul != 0) | 1230 | if (majormul != 0) |
1206 | setgcparam(g->genmajormul, majormul); | 1231 | setgcparam(g, genmajormul, majormul); |
1207 | luaC_changemode(L, KGC_GEN); | 1232 | luaC_changemode(L, KGC_GEN); |
1208 | break; | 1233 | break; |
1209 | } | 1234 | } |
1210 | case LUA_GCINC: { | 1235 | case LUA_GCINC: { |
1211 | int pause = va_arg(argp, int); | 1236 | unsigned int pause = va_arg(argp, unsigned int); |
1212 | int stepmul = va_arg(argp, int); | 1237 | unsigned int stepmul = va_arg(argp, unsigned int); |
1213 | int stepsize = va_arg(argp, int); | 1238 | unsigned int stepsize = va_arg(argp, unsigned int); |
1214 | res = isdecGCmodegen(g) ? LUA_GCGEN : LUA_GCINC; | 1239 | res = (g->gckind == KGC_INC) ? LUA_GCINC : LUA_GCGEN; |
1215 | if (pause != 0) | 1240 | if (pause != 0) |
1216 | setgcparam(g->gcpause, pause); | 1241 | setgcparam(g, gcpause, pause); |
1217 | if (stepmul != 0) | 1242 | if (stepmul != 0) |
1218 | setgcparam(g->gcstepmul, stepmul); | 1243 | setgcparam(g, gcstepmul, stepmul); |
1219 | if (stepsize != 0) | 1244 | if (stepsize != 0) |
1220 | g->gcstepsize = stepsize; | 1245 | g->gcstepsize = (stepsize <= log2maxs(l_obj)) ? stepsize |
1246 | : log2maxs(l_obj); | ||
1221 | luaC_changemode(L, KGC_INC); | 1247 | luaC_changemode(L, KGC_INC); |
1222 | break; | 1248 | break; |
1223 | } | 1249 | } |
@@ -1285,13 +1311,14 @@ LUA_API void lua_toclose (lua_State *L, int idx) { | |||
1285 | LUA_API void lua_concat (lua_State *L, int n) { | 1311 | LUA_API void lua_concat (lua_State *L, int n) { |
1286 | lua_lock(L); | 1312 | lua_lock(L); |
1287 | api_checknelems(L, n); | 1313 | api_checknelems(L, n); |
1288 | if (n > 0) | 1314 | if (n > 0) { |
1289 | luaV_concat(L, n); | 1315 | luaV_concat(L, n); |
1316 | luaC_checkGC(L); | ||
1317 | } | ||
1290 | else { /* nothing to concatenate */ | 1318 | else { /* nothing to concatenate */ |
1291 | setsvalue2s(L, L->top.p, luaS_newlstr(L, "", 0)); /* push empty string */ | 1319 | setsvalue2s(L, L->top.p, luaS_newlstr(L, "", 0)); /* push empty string */ |
1292 | api_incr_top(L); | 1320 | api_incr_top(L); |
1293 | } | 1321 | } |
1294 | luaC_checkGC(L); | ||
1295 | lua_unlock(L); | 1322 | lua_unlock(L); |
1296 | } | 1323 | } |
1297 | 1324 | ||
@@ -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 */ |
@@ -105,7 +87,7 @@ | |||
105 | #define markobjectN(g,t) { if (t) markobject(g,t); } | 87 | #define markobjectN(g,t) { if (t) markobject(g,t); } |
106 | 88 | ||
107 | static void reallymarkobject (global_State *g, GCObject *o); | 89 | static void reallymarkobject (global_State *g, GCObject *o); |
108 | static lu_mem atomic (lua_State *L); | 90 | static l_obj atomic (lua_State *L); |
109 | static void entersweep (lua_State *L); | 91 | static void entersweep (lua_State *L); |
110 | 92 | ||
111 | 93 | ||
@@ -217,7 +199,7 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { | |||
217 | } | 199 | } |
218 | else { /* sweep phase */ | 200 | else { /* sweep phase */ |
219 | lua_assert(issweepphase(g)); | 201 | lua_assert(issweepphase(g)); |
220 | if (g->gckind == KGC_INC) /* incremental mode? */ | 202 | if (g->gckind != KGC_GEN) /* incremental mode? */ |
221 | makewhite(g, o); /* mark 'o' as white to avoid other barriers */ | 203 | makewhite(g, o); /* mark 'o' as white to avoid other barriers */ |
222 | } | 204 | } |
223 | } | 205 | } |
@@ -259,6 +241,7 @@ GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, size_t offset) { | |||
259 | global_State *g = G(L); | 241 | global_State *g = G(L); |
260 | char *p = cast_charp(luaM_newobject(L, novariant(tt), sz)); | 242 | char *p = cast_charp(luaM_newobject(L, novariant(tt), sz)); |
261 | GCObject *o = cast(GCObject *, p + offset); | 243 | GCObject *o = cast(GCObject *, p + offset); |
244 | g->GCdebt--; | ||
262 | o->marked = luaC_white(g); | 245 | o->marked = luaC_white(g); |
263 | o->tt = tt; | 246 | o->tt = tt; |
264 | o->next = g->allgc; | 247 | o->next = g->allgc; |
@@ -267,6 +250,9 @@ GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, size_t offset) { | |||
267 | } | 250 | } |
268 | 251 | ||
269 | 252 | ||
253 | /* | ||
254 | ** create a new collectable object with no offset. | ||
255 | */ | ||
270 | GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { | 256 | GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { |
271 | return luaC_newobjdt(L, tt, sz, 0); | 257 | return luaC_newobjdt(L, tt, sz, 0); |
272 | } | 258 | } |
@@ -295,6 +281,7 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { | |||
295 | ** (only closures can), and a userdata's metatable must be a table. | 281 | ** (only closures can), and a userdata's metatable must be a table. |
296 | */ | 282 | */ |
297 | static void reallymarkobject (global_State *g, GCObject *o) { | 283 | static void reallymarkobject (global_State *g, GCObject *o) { |
284 | g->marked++; | ||
298 | switch (o->tt) { | 285 | switch (o->tt) { |
299 | case LUA_VSHRSTR: | 286 | case LUA_VSHRSTR: |
300 | case LUA_VLNGSTR: { | 287 | case LUA_VLNGSTR: { |
@@ -342,9 +329,9 @@ static void markmt (global_State *g) { | |||
342 | /* | 329 | /* |
343 | ** mark all objects in list of being-finalized | 330 | ** mark all objects in list of being-finalized |
344 | */ | 331 | */ |
345 | static lu_mem markbeingfnz (global_State *g) { | 332 | static l_obj markbeingfnz (global_State *g) { |
346 | GCObject *o; | 333 | GCObject *o; |
347 | lu_mem count = 0; | 334 | l_obj count = 0; |
348 | for (o = g->tobefnz; o != NULL; o = o->next) { | 335 | for (o = g->tobefnz; o != NULL; o = o->next) { |
349 | count++; | 336 | count++; |
350 | markobject(g, o); | 337 | markobject(g, o); |
@@ -364,12 +351,11 @@ static lu_mem markbeingfnz (global_State *g) { | |||
364 | ** upvalues, as they have nothing to be checked. (If the thread gets an | 351 | ** upvalues, as they have nothing to be checked. (If the thread gets an |
365 | ** upvalue later, it will be linked in the list again.) | 352 | ** upvalue later, it will be linked in the list again.) |
366 | */ | 353 | */ |
367 | static int remarkupvals (global_State *g) { | 354 | static l_obj remarkupvals (global_State *g) { |
355 | l_obj work = 0; | ||
368 | lua_State *thread; | 356 | lua_State *thread; |
369 | lua_State **p = &g->twups; | 357 | lua_State **p = &g->twups; |
370 | int work = 0; /* estimate of how much work was done here */ | ||
371 | while ((thread = *p) != NULL) { | 358 | while ((thread = *p) != NULL) { |
372 | work++; | ||
373 | if (!iswhite(thread) && thread->openupval != NULL) | 359 | if (!iswhite(thread) && thread->openupval != NULL) |
374 | p = &thread->twups; /* keep marked thread with upvalues in the list */ | 360 | p = &thread->twups; /* keep marked thread with upvalues in the list */ |
375 | else { /* thread is not marked or without upvalues */ | 361 | else { /* thread is not marked or without upvalues */ |
@@ -379,13 +365,13 @@ static int remarkupvals (global_State *g) { | |||
379 | thread->twups = thread; /* mark that it is out of list */ | 365 | thread->twups = thread; /* mark that it is out of list */ |
380 | for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { | 366 | for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { |
381 | lua_assert(getage(uv) <= getage(thread)); | 367 | lua_assert(getage(uv) <= getage(thread)); |
382 | work++; | ||
383 | if (!iswhite(uv)) { /* upvalue already visited? */ | 368 | if (!iswhite(uv)) { /* upvalue already visited? */ |
384 | lua_assert(upisopen(uv) && isgray(uv)); | 369 | lua_assert(upisopen(uv) && isgray(uv)); |
385 | markvalue(g, uv->v.p); /* mark its value */ | 370 | markvalue(g, uv->v.p); /* mark its value */ |
386 | } | 371 | } |
387 | } | 372 | } |
388 | } | 373 | } |
374 | work++; | ||
389 | } | 375 | } |
390 | return work; | 376 | return work; |
391 | } | 377 | } |
@@ -398,10 +384,15 @@ static void cleargraylists (global_State *g) { | |||
398 | 384 | ||
399 | 385 | ||
400 | /* | 386 | /* |
401 | ** mark root set and reset all gray lists, to start a new collection | 387 | ** mark root set and reset all gray lists, to start a new collection. |
388 | ** 'marked' is initialized with the number of fixed objects in the state, | ||
389 | ** to count the total number of live objects during a cycle. (That is | ||
390 | ** the metafield names, plus the reserved words, plus "_ENV" plus the | ||
391 | ** memory-error message.) | ||
402 | */ | 392 | */ |
403 | static void restartcollection (global_State *g) { | 393 | static void restartcollection (global_State *g) { |
404 | cleargraylists(g); | 394 | cleargraylists(g); |
395 | g->marked = NFIXED; | ||
405 | markobject(g, g->mainthread); | 396 | markobject(g, g->mainthread); |
406 | markvalue(g, &g->l_registry); | 397 | markvalue(g, &g->l_registry); |
407 | markmt(g); | 398 | markmt(g); |
@@ -539,7 +530,7 @@ static void traversestrongtable (global_State *g, Table *h) { | |||
539 | } | 530 | } |
540 | 531 | ||
541 | 532 | ||
542 | static lu_mem traversetable (global_State *g, Table *h) { | 533 | static void traversetable (global_State *g, Table *h) { |
543 | const char *weakkey, *weakvalue; | 534 | const char *weakkey, *weakvalue; |
544 | const TValue *mode = gfasttm(g, h->metatable, TM_MODE); | 535 | const TValue *mode = gfasttm(g, h->metatable, TM_MODE); |
545 | TString *smode; | 536 | TString *smode; |
@@ -558,17 +549,15 @@ static lu_mem traversetable (global_State *g, Table *h) { | |||
558 | } | 549 | } |
559 | else /* not weak */ | 550 | else /* not weak */ |
560 | traversestrongtable(g, h); | 551 | traversestrongtable(g, h); |
561 | return 1 + h->alimit + 2 * allocsizenode(h); | ||
562 | } | 552 | } |
563 | 553 | ||
564 | 554 | ||
565 | static int traverseudata (global_State *g, Udata *u) { | 555 | static void traverseudata (global_State *g, Udata *u) { |
566 | int i; | 556 | int i; |
567 | markobjectN(g, u->metatable); /* mark its metatable */ | 557 | markobjectN(g, u->metatable); /* mark its metatable */ |
568 | for (i = 0; i < u->nuvalue; i++) | 558 | for (i = 0; i < u->nuvalue; i++) |
569 | markvalue(g, &u->uv[i].uv); | 559 | markvalue(g, &u->uv[i].uv); |
570 | genlink(g, obj2gco(u)); | 560 | genlink(g, obj2gco(u)); |
571 | return 1 + u->nuvalue; | ||
572 | } | 561 | } |
573 | 562 | ||
574 | 563 | ||
@@ -577,7 +566,7 @@ static int traverseudata (global_State *g, Udata *u) { | |||
577 | ** arrays can be larger than needed; the extra slots are filled with | 566 | ** arrays can be larger than needed; the extra slots are filled with |
578 | ** NULL, so the use of 'markobjectN') | 567 | ** NULL, so the use of 'markobjectN') |
579 | */ | 568 | */ |
580 | static int traverseproto (global_State *g, Proto *f) { | 569 | static void traverseproto (global_State *g, Proto *f) { |
581 | int i; | 570 | int i; |
582 | markobjectN(g, f->source); | 571 | markobjectN(g, f->source); |
583 | for (i = 0; i < f->sizek; i++) /* mark literals */ | 572 | for (i = 0; i < f->sizek; i++) /* mark literals */ |
@@ -588,29 +577,26 @@ static int traverseproto (global_State *g, Proto *f) { | |||
588 | markobjectN(g, f->p[i]); | 577 | markobjectN(g, f->p[i]); |
589 | for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ | 578 | for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ |
590 | markobjectN(g, f->locvars[i].varname); | 579 | markobjectN(g, f->locvars[i].varname); |
591 | return 1 + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars; | ||
592 | } | 580 | } |
593 | 581 | ||
594 | 582 | ||
595 | static int traverseCclosure (global_State *g, CClosure *cl) { | 583 | static void traverseCclosure (global_State *g, CClosure *cl) { |
596 | int i; | 584 | int i; |
597 | for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ | 585 | for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ |
598 | markvalue(g, &cl->upvalue[i]); | 586 | markvalue(g, &cl->upvalue[i]); |
599 | return 1 + cl->nupvalues; | ||
600 | } | 587 | } |
601 | 588 | ||
602 | /* | 589 | /* |
603 | ** Traverse a Lua closure, marking its prototype and its upvalues. | 590 | ** Traverse a Lua closure, marking its prototype and its upvalues. |
604 | ** (Both can be NULL while closure is being created.) | 591 | ** (Both can be NULL while closure is being created.) |
605 | */ | 592 | */ |
606 | static int traverseLclosure (global_State *g, LClosure *cl) { | 593 | static void traverseLclosure (global_State *g, LClosure *cl) { |
607 | int i; | 594 | int i; |
608 | markobjectN(g, cl->p); /* mark its prototype */ | 595 | markobjectN(g, cl->p); /* mark its prototype */ |
609 | for (i = 0; i < cl->nupvalues; i++) { /* visit its upvalues */ | 596 | for (i = 0; i < cl->nupvalues; i++) { /* visit its upvalues */ |
610 | UpVal *uv = cl->upvals[i]; | 597 | UpVal *uv = cl->upvals[i]; |
611 | markobjectN(g, uv); /* mark upvalue */ | 598 | markobjectN(g, uv); /* mark upvalue */ |
612 | } | 599 | } |
613 | return 1 + cl->nupvalues; | ||
614 | } | 600 | } |
615 | 601 | ||
616 | 602 | ||
@@ -626,13 +612,13 @@ static int traverseLclosure (global_State *g, LClosure *cl) { | |||
626 | ** (which can only happen in generational mode) or if the traverse is in | 612 | ** (which can only happen in generational mode) or if the traverse is in |
627 | ** the propagate phase (which can only happen in incremental mode). | 613 | ** the propagate phase (which can only happen in incremental mode). |
628 | */ | 614 | */ |
629 | static int traversethread (global_State *g, lua_State *th) { | 615 | static void traversethread (global_State *g, lua_State *th) { |
630 | UpVal *uv; | 616 | UpVal *uv; |
631 | StkId o = th->stack.p; | 617 | StkId o = th->stack.p; |
632 | if (isold(th) || g->gcstate == GCSpropagate) | 618 | if (isold(th) || g->gcstate == GCSpropagate) |
633 | linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ | 619 | linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ |
634 | if (o == NULL) | 620 | if (o == NULL) |
635 | return 1; /* stack not completely built yet */ | 621 | return; /* stack not completely built yet */ |
636 | lua_assert(g->gcstate == GCSatomic || | 622 | lua_assert(g->gcstate == GCSatomic || |
637 | th->openupval == NULL || isintwups(th)); | 623 | th->openupval == NULL || isintwups(th)); |
638 | for (; o < th->top.p; o++) /* mark live elements in the stack */ | 624 | for (; o < th->top.p; o++) /* mark live elements in the stack */ |
@@ -650,34 +636,35 @@ static int traversethread (global_State *g, lua_State *th) { | |||
650 | g->twups = th; | 636 | g->twups = th; |
651 | } | 637 | } |
652 | } | 638 | } |
653 | return 1 + stacksize(th); | ||
654 | } | 639 | } |
655 | 640 | ||
656 | 641 | ||
657 | /* | 642 | /* |
658 | ** traverse one gray object, turning it to black. | 643 | ** traverse one gray object, turning it to black. |
659 | */ | 644 | */ |
660 | static lu_mem propagatemark (global_State *g) { | 645 | static void propagatemark (global_State *g) { |
661 | GCObject *o = g->gray; | 646 | GCObject *o = g->gray; |
662 | nw2black(o); | 647 | nw2black(o); |
663 | g->gray = *getgclist(o); /* remove from 'gray' list */ | 648 | g->gray = *getgclist(o); /* remove from 'gray' list */ |
664 | switch (o->tt) { | 649 | switch (o->tt) { |
665 | case LUA_VTABLE: return traversetable(g, gco2t(o)); | 650 | case LUA_VTABLE: traversetable(g, gco2t(o)); break; |
666 | case LUA_VUSERDATA: return traverseudata(g, gco2u(o)); | 651 | case LUA_VUSERDATA: traverseudata(g, gco2u(o)); break; |
667 | case LUA_VLCL: return traverseLclosure(g, gco2lcl(o)); | 652 | case LUA_VLCL: traverseLclosure(g, gco2lcl(o)); break; |
668 | case LUA_VCCL: return traverseCclosure(g, gco2ccl(o)); | 653 | case LUA_VCCL: traverseCclosure(g, gco2ccl(o)); break; |
669 | case LUA_VPROTO: return traverseproto(g, gco2p(o)); | 654 | case LUA_VPROTO: traverseproto(g, gco2p(o)); break; |
670 | case LUA_VTHREAD: return traversethread(g, gco2th(o)); | 655 | case LUA_VTHREAD: traversethread(g, gco2th(o)); break; |
671 | default: lua_assert(0); return 0; | 656 | default: lua_assert(0); |
672 | } | 657 | } |
673 | } | 658 | } |
674 | 659 | ||
675 | 660 | ||
676 | static lu_mem propagateall (global_State *g) { | 661 | static l_obj propagateall (global_State *g) { |
677 | lu_mem tot = 0; | 662 | l_obj work = 0; |
678 | while (g->gray) | 663 | while (g->gray) { |
679 | tot += propagatemark(g); | 664 | propagatemark(g); |
680 | return tot; | 665 | work++; |
666 | } | ||
667 | return work; | ||
681 | } | 668 | } |
682 | 669 | ||
683 | 670 | ||
@@ -686,10 +673,10 @@ static lu_mem propagateall (global_State *g) { | |||
686 | ** Repeat until it converges, that is, nothing new is marked. 'dir' | 673 | ** Repeat until it converges, that is, nothing new is marked. 'dir' |
687 | ** inverts the direction of the traversals, trying to speed up | 674 | ** inverts the direction of the traversals, trying to speed up |
688 | ** convergence on chains in the same table. | 675 | ** convergence on chains in the same table. |
689 | ** | ||
690 | */ | 676 | */ |
691 | static void convergeephemerons (global_State *g) { | 677 | static l_obj convergeephemerons (global_State *g) { |
692 | int changed; | 678 | int changed; |
679 | l_obj work = 0; | ||
693 | int dir = 0; | 680 | int dir = 0; |
694 | do { | 681 | do { |
695 | GCObject *w; | 682 | GCObject *w; |
@@ -704,9 +691,11 @@ static void convergeephemerons (global_State *g) { | |||
704 | propagateall(g); /* propagate changes */ | 691 | propagateall(g); /* propagate changes */ |
705 | changed = 1; /* will have to revisit all ephemeron tables */ | 692 | changed = 1; /* will have to revisit all ephemeron tables */ |
706 | } | 693 | } |
694 | work++; | ||
707 | } | 695 | } |
708 | dir = !dir; /* invert direction next time */ | 696 | dir = !dir; /* invert direction next time */ |
709 | } while (changed); /* repeat until no more changes */ | 697 | } while (changed); /* repeat until no more changes */ |
698 | return work; | ||
710 | } | 699 | } |
711 | 700 | ||
712 | /* }====================================================== */ | 701 | /* }====================================================== */ |
@@ -722,7 +711,8 @@ static void convergeephemerons (global_State *g) { | |||
722 | /* | 711 | /* |
723 | ** clear entries with unmarked keys from all weaktables in list 'l' | 712 | ** clear entries with unmarked keys from all weaktables in list 'l' |
724 | */ | 713 | */ |
725 | static void clearbykeys (global_State *g, GCObject *l) { | 714 | static l_obj clearbykeys (global_State *g, GCObject *l) { |
715 | l_obj work = 0; | ||
726 | for (; l; l = gco2t(l)->gclist) { | 716 | for (; l; l = gco2t(l)->gclist) { |
727 | Table *h = gco2t(l); | 717 | Table *h = gco2t(l); |
728 | Node *limit = gnodelast(h); | 718 | Node *limit = gnodelast(h); |
@@ -733,7 +723,9 @@ static void clearbykeys (global_State *g, GCObject *l) { | |||
733 | if (isempty(gval(n))) /* is entry empty? */ | 723 | if (isempty(gval(n))) /* is entry empty? */ |
734 | clearkey(n); /* clear its key */ | 724 | clearkey(n); /* clear its key */ |
735 | } | 725 | } |
726 | work++; | ||
736 | } | 727 | } |
728 | return work; | ||
737 | } | 729 | } |
738 | 730 | ||
739 | 731 | ||
@@ -741,7 +733,8 @@ static void clearbykeys (global_State *g, GCObject *l) { | |||
741 | ** clear entries with unmarked values from all weaktables in list 'l' up | 733 | ** clear entries with unmarked values from all weaktables in list 'l' up |
742 | ** to element 'f' | 734 | ** to element 'f' |
743 | */ | 735 | */ |
744 | static void clearbyvalues (global_State *g, GCObject *l, GCObject *f) { | 736 | static l_obj clearbyvalues (global_State *g, GCObject *l, GCObject *f) { |
737 | l_obj work = 0; | ||
745 | for (; l != f; l = gco2t(l)->gclist) { | 738 | for (; l != f; l = gco2t(l)->gclist) { |
746 | Table *h = gco2t(l); | 739 | Table *h = gco2t(l); |
747 | Node *n, *limit = gnodelast(h); | 740 | Node *n, *limit = gnodelast(h); |
@@ -758,7 +751,9 @@ static void clearbyvalues (global_State *g, GCObject *l, GCObject *f) { | |||
758 | if (isempty(gval(n))) /* is entry empty? */ | 751 | if (isempty(gval(n))) /* is entry empty? */ |
759 | clearkey(n); /* clear its key */ | 752 | clearkey(n); /* clear its key */ |
760 | } | 753 | } |
754 | work++; | ||
761 | } | 755 | } |
756 | return work; | ||
762 | } | 757 | } |
763 | 758 | ||
764 | 759 | ||
@@ -770,6 +765,7 @@ static void freeupval (lua_State *L, UpVal *uv) { | |||
770 | 765 | ||
771 | 766 | ||
772 | static void freeobj (lua_State *L, GCObject *o) { | 767 | static void freeobj (lua_State *L, GCObject *o) { |
768 | G(L)->totalobjs--; | ||
773 | switch (o->tt) { | 769 | switch (o->tt) { |
774 | case LUA_VPROTO: | 770 | case LUA_VPROTO: |
775 | luaF_freeproto(L, gco2p(o)); | 771 | luaF_freeproto(L, gco2p(o)); |
@@ -819,10 +815,9 @@ static void freeobj (lua_State *L, GCObject *o) { | |||
819 | ** objects, where a dead object is one marked with the old (non current) | 815 | ** objects, where a dead object is one marked with the old (non current) |
820 | ** white; change all non-dead objects back to white, preparing for next | 816 | ** white; change all non-dead objects back to white, preparing for next |
821 | ** collection cycle. Return where to continue the traversal or NULL if | 817 | ** collection cycle. Return where to continue the traversal or NULL if |
822 | ** list is finished. ('*countout' gets the number of elements traversed.) | 818 | ** list is finished. |
823 | */ | 819 | */ |
824 | static GCObject **sweeplist (lua_State *L, GCObject **p, int countin, | 820 | static GCObject **sweeplist (lua_State *L, GCObject **p, int countin) { |
825 | int *countout) { | ||
826 | global_State *g = G(L); | 821 | global_State *g = G(L); |
827 | int ow = otherwhite(g); | 822 | int ow = otherwhite(g); |
828 | int i; | 823 | int i; |
@@ -839,8 +834,6 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, int countin, | |||
839 | p = &curr->next; /* go to next element */ | 834 | p = &curr->next; /* go to next element */ |
840 | } | 835 | } |
841 | } | 836 | } |
842 | if (countout) | ||
843 | *countout = i; /* number of elements traversed */ | ||
844 | return (*p == NULL) ? NULL : p; | 837 | return (*p == NULL) ? NULL : p; |
845 | } | 838 | } |
846 | 839 | ||
@@ -851,7 +844,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, int countin, | |||
851 | static GCObject **sweeptolive (lua_State *L, GCObject **p) { | 844 | static GCObject **sweeptolive (lua_State *L, GCObject **p) { |
852 | GCObject **old = p; | 845 | GCObject **old = p; |
853 | do { | 846 | do { |
854 | p = sweeplist(L, p, 1, NULL); | 847 | p = sweeplist(L, p, 1); |
855 | } while (p == old); | 848 | } while (p == old); |
856 | return p; | 849 | return p; |
857 | } | 850 | } |
@@ -870,11 +863,8 @@ static GCObject **sweeptolive (lua_State *L, GCObject **p) { | |||
870 | */ | 863 | */ |
871 | static void checkSizes (lua_State *L, global_State *g) { | 864 | static void checkSizes (lua_State *L, global_State *g) { |
872 | if (!g->gcemergency) { | 865 | if (!g->gcemergency) { |
873 | if (g->strt.nuse < g->strt.size / 4) { /* string table too big? */ | 866 | if (g->strt.nuse < g->strt.size / 4) /* string table too big? */ |
874 | l_mem olddebt = g->GCdebt; | ||
875 | luaS_resize(L, g->strt.size / 2); | 867 | luaS_resize(L, g->strt.size / 2); |
876 | g->GCestimate += g->GCdebt - olddebt; /* correct estimate */ | ||
877 | } | ||
878 | } | 868 | } |
879 | } | 869 | } |
880 | 870 | ||
@@ -933,18 +923,6 @@ static void GCTM (lua_State *L) { | |||
933 | 923 | ||
934 | 924 | ||
935 | /* | 925 | /* |
936 | ** Call a few finalizers | ||
937 | */ | ||
938 | static int runafewfinalizers (lua_State *L, int n) { | ||
939 | global_State *g = G(L); | ||
940 | int i; | ||
941 | for (i = 0; i < n && g->tobefnz; i++) | ||
942 | GCTM(L); /* call one finalizer */ | ||
943 | return i; | ||
944 | } | ||
945 | |||
946 | |||
947 | /* | ||
948 | ** call all pending finalizers | 926 | ** call all pending finalizers |
949 | */ | 927 | */ |
950 | static void callallpendingfinalizers (lua_State *L) { | 928 | static void callallpendingfinalizers (lua_State *L) { |
@@ -1052,20 +1030,13 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { | |||
1052 | 1030 | ||
1053 | /* | 1031 | /* |
1054 | ** Set the "time" to wait before starting a new GC cycle; cycle will | 1032 | ** Set the "time" to wait before starting a new GC cycle; cycle will |
1055 | ** start when memory use hits the threshold of ('estimate' * pause / | 1033 | ** start when number of objects in use hits the threshold of |
1056 | ** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero, | 1034 | ** approximately (marked * pause / 100). |
1057 | ** because Lua cannot even start with less than PAUSEADJ bytes). | ||
1058 | */ | 1035 | */ |
1059 | static void setpause (global_State *g) { | 1036 | static void setpause (global_State *g) { |
1060 | l_mem threshold, debt; | 1037 | l_obj threshold = applygcparam(g, gcpause, g->marked); |
1061 | int pause = getgcparam(g->gcpause); | 1038 | l_obj debt = threshold - gettotalobjs(g); |
1062 | l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */ | 1039 | if (debt < 0) debt = 0; |
1063 | lua_assert(estimate > 0); | ||
1064 | threshold = (pause < MAX_LMEM / estimate) /* overflow? */ | ||
1065 | ? estimate * pause /* no overflow */ | ||
1066 | : MAX_LMEM; /* overflow; truncate to maximum */ | ||
1067 | debt = gettotalbytes(g) - threshold; | ||
1068 | if (debt > 0) debt = 0; | ||
1069 | luaE_setdebt(g, debt); | 1040 | luaE_setdebt(g, debt); |
1070 | } | 1041 | } |
1071 | 1042 | ||
@@ -1305,18 +1276,17 @@ static void atomic2gen (lua_State *L, global_State *g) { | |||
1305 | sweep2old(L, &g->tobefnz); | 1276 | sweep2old(L, &g->tobefnz); |
1306 | 1277 | ||
1307 | g->gckind = KGC_GEN; | 1278 | g->gckind = KGC_GEN; |
1308 | g->lastatomic = 0; | 1279 | g->GClastmajor = gettotalobjs(g); /* base for memory control */ |
1309 | g->GCestimate = gettotalbytes(g); /* base for memory control */ | ||
1310 | finishgencycle(L, g); | 1280 | finishgencycle(L, g); |
1311 | } | 1281 | } |
1312 | 1282 | ||
1313 | 1283 | ||
1314 | /* | 1284 | /* |
1315 | ** Set debt for the next minor collection, which will happen when | 1285 | ** Set debt for the next minor collection, which will happen when |
1316 | ** memory grows 'genminormul'%. | 1286 | ** total number of objects grows 'genminormul'%. |
1317 | */ | 1287 | */ |
1318 | static void setminordebt (global_State *g) { | 1288 | static void setminordebt (global_State *g) { |
1319 | luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul)); | 1289 | luaE_setdebt(g, applygcparam(g, genminormul, gettotalobjs(g))); |
1320 | } | 1290 | } |
1321 | 1291 | ||
1322 | 1292 | ||
@@ -1326,14 +1296,12 @@ static void setminordebt (global_State *g) { | |||
1326 | ** are cleared. Then, turn all objects into old and finishes the | 1296 | ** are cleared. Then, turn all objects into old and finishes the |
1327 | ** collection. | 1297 | ** collection. |
1328 | */ | 1298 | */ |
1329 | static lu_mem entergen (lua_State *L, global_State *g) { | 1299 | static void entergen (lua_State *L, global_State *g) { |
1330 | lu_mem numobjs; | ||
1331 | luaC_runtilstate(L, bitmask(GCSpause)); /* prepare to start a new cycle */ | 1300 | luaC_runtilstate(L, bitmask(GCSpause)); /* prepare to start a new cycle */ |
1332 | luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ | 1301 | luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ |
1333 | numobjs = atomic(L); /* propagates all and then do the atomic stuff */ | 1302 | atomic(L); /* propagates all and then do the atomic stuff */ |
1334 | atomic2gen(L, g); | 1303 | atomic2gen(L, g); |
1335 | setminordebt(g); /* set debt assuming next cycle will be minor */ | 1304 | setminordebt(g); /* set debt assuming next cycle will be minor */ |
1336 | return numobjs; | ||
1337 | } | 1305 | } |
1338 | 1306 | ||
1339 | 1307 | ||
@@ -1350,7 +1318,6 @@ static void enterinc (global_State *g) { | |||
1350 | g->finobjrold = g->finobjold1 = g->finobjsur = NULL; | 1318 | g->finobjrold = g->finobjold1 = g->finobjsur = NULL; |
1351 | g->gcstate = GCSpause; | 1319 | g->gcstate = GCSpause; |
1352 | g->gckind = KGC_INC; | 1320 | g->gckind = KGC_INC; |
1353 | g->lastatomic = 0; | ||
1354 | } | 1321 | } |
1355 | 1322 | ||
1356 | 1323 | ||
@@ -1359,111 +1326,75 @@ static void enterinc (global_State *g) { | |||
1359 | */ | 1326 | */ |
1360 | void luaC_changemode (lua_State *L, int newmode) { | 1327 | void luaC_changemode (lua_State *L, int newmode) { |
1361 | global_State *g = G(L); | 1328 | global_State *g = G(L); |
1362 | if (newmode != g->gckind) { | 1329 | if (newmode != g->gckind) { /* does it need to change? */ |
1363 | if (newmode == KGC_GEN) /* entering generational mode? */ | 1330 | if (newmode == KGC_INC) { /* entering incremental mode? */ |
1331 | if (g->gckind == KGC_GENMAJOR) | ||
1332 | g->gckind = KGC_INC; /* already incremental but in name */ | ||
1333 | else | ||
1334 | enterinc(g); /* entering incremental mode */ | ||
1335 | } | ||
1336 | else { | ||
1337 | lua_assert(newmode == KGC_GEN); | ||
1364 | entergen(L, g); | 1338 | entergen(L, g); |
1365 | else | 1339 | } |
1366 | enterinc(g); /* entering incremental mode */ | ||
1367 | } | 1340 | } |
1368 | g->lastatomic = 0; | ||
1369 | } | 1341 | } |
1370 | 1342 | ||
1371 | 1343 | ||
1372 | /* | 1344 | /* |
1373 | ** Does a full collection in generational mode. | 1345 | ** Does a full collection in generational mode. |
1374 | */ | 1346 | */ |
1375 | static lu_mem fullgen (lua_State *L, global_State *g) { | 1347 | static void fullgen (lua_State *L, global_State *g) { |
1376 | enterinc(g); | 1348 | enterinc(g); |
1377 | return entergen(L, g); | 1349 | entergen(L, g); |
1378 | } | 1350 | } |
1379 | 1351 | ||
1380 | 1352 | ||
1381 | /* | 1353 | /* |
1382 | ** Does a major collection after last collection was a "bad collection". | 1354 | ** Does a major collector up to the atomic phase and then either |
1383 | ** | 1355 | ** returns to minor collections or stays doing major ones. If the |
1384 | ** When the program is building a big structure, it allocates lots of | 1356 | ** number of objects collected this time (numobjs - marked) is more than |
1385 | ** memory but generates very little garbage. In those scenarios, | 1357 | ** half the number of objects created since the last major collection |
1386 | ** the generational mode just wastes time doing small collections, and | 1358 | ** (numobjs - lastmajor), it goes back to minor collections. |
1387 | ** major collections are frequently what we call a "bad collection", a | 1359 | */ |
1388 | ** collection that frees too few objects. To avoid the cost of switching | 1360 | static void genmajorstep (lua_State *L, global_State *g) { |
1389 | ** between generational mode and the incremental mode needed for full | 1361 | l_obj lastmajor = g->GClastmajor; /* count from last collection */ |
1390 | ** (major) collections, the collector tries to stay in incremental mode | 1362 | l_obj numobjs = gettotalobjs(g); /* current count */ |
1391 | ** after a bad collection, and to switch back to generational mode only | ||
1392 | ** after a "good" collection (one that traverses less than 9/8 objects | ||
1393 | ** of the previous one). | ||
1394 | ** The collector must choose whether to stay in incremental mode or to | ||
1395 | ** switch back to generational mode before sweeping. At this point, it | ||
1396 | ** does not know the real memory in use, so it cannot use memory to | ||
1397 | ** decide whether to return to generational mode. Instead, it uses the | ||
1398 | ** number of objects traversed (returned by 'atomic') as a proxy. The | ||
1399 | ** field 'g->lastatomic' keeps this count from the last collection. | ||
1400 | ** ('g->lastatomic != 0' also means that the last collection was bad.) | ||
1401 | */ | ||
1402 | static void stepgenfull (lua_State *L, global_State *g) { | ||
1403 | lu_mem newatomic; /* count of traversed objects */ | ||
1404 | lu_mem lastatomic = g->lastatomic; /* count from last collection */ | ||
1405 | if (g->gckind == KGC_GEN) /* still in generational mode? */ | ||
1406 | enterinc(g); /* enter incremental mode */ | ||
1407 | luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ | 1363 | luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ |
1408 | newatomic = atomic(L); /* mark everybody */ | 1364 | atomic(L); /* mark everybody */ |
1409 | if (newatomic < lastatomic + (lastatomic >> 3)) { /* good collection? */ | 1365 | if ((numobjs - g->marked) > ((numobjs - lastmajor) >> 1)) { |
1410 | atomic2gen(L, g); /* return to generational mode */ | 1366 | atomic2gen(L, g); /* return to generational mode */ |
1411 | setminordebt(g); | 1367 | setminordebt(g); |
1412 | } | 1368 | } |
1413 | else { /* another bad collection; stay in incremental mode */ | 1369 | else { /* bad collection; stay in major mode */ |
1414 | g->GCestimate = gettotalbytes(g); /* first estimate */ | ||
1415 | entersweep(L); | 1370 | entersweep(L); |
1416 | luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ | 1371 | luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ |
1417 | setpause(g); | 1372 | setpause(g); |
1418 | g->lastatomic = newatomic; | 1373 | g->GClastmajor = gettotalobjs(g); |
1419 | } | 1374 | } |
1420 | } | 1375 | } |
1421 | 1376 | ||
1422 | 1377 | ||
1423 | /* | 1378 | /* |
1424 | ** Does a generational "step". | 1379 | ** Does a generational "step". If the total number of objects grew |
1425 | ** Usually, this means doing a minor collection and setting the debt to | 1380 | ** more than 'majormul'% since the last major collection, does a |
1426 | ** make another collection when memory grows 'genminormul'% larger. | 1381 | ** major collection. Otherwise, does a minor collection. |
1427 | ** | ||
1428 | ** However, there are exceptions. If memory grows 'genmajormul'% | ||
1429 | ** larger than it was at the end of the last major collection (kept | ||
1430 | ** in 'g->GCestimate'), the function does a major collection. At the | ||
1431 | ** end, it checks whether the major collection was able to free a | ||
1432 | ** decent amount of memory (at least half the growth in memory since | ||
1433 | ** previous major collection). If so, the collector keeps its state, | ||
1434 | ** and the next collection will probably be minor again. Otherwise, | ||
1435 | ** we have what we call a "bad collection". In that case, set the field | ||
1436 | ** 'g->lastatomic' to signal that fact, so that the next collection will | ||
1437 | ** go to 'stepgenfull'. | ||
1438 | ** | ||
1439 | ** 'GCdebt <= 0' means an explicit call to GC step with "size" zero; | ||
1440 | ** in that case, do a minor collection. | ||
1441 | */ | 1382 | */ |
1442 | static void genstep (lua_State *L, global_State *g) { | 1383 | static void genstep (lua_State *L, global_State *g) { |
1443 | if (g->lastatomic != 0) /* last collection was a bad one? */ | 1384 | l_obj majorbase = g->GClastmajor; /* count after last major collection */ |
1444 | stepgenfull(L, g); /* do a full step */ | 1385 | l_obj majorinc = applygcparam(g, genmajormul, majorbase); |
1445 | else { | 1386 | if (gettotalobjs(g) > majorbase + majorinc && 0) { |
1446 | lu_mem majorbase = g->GCestimate; /* memory after last major collection */ | 1387 | /* do a major collection */ |
1447 | lu_mem majorinc = (majorbase / 100) * getgcparam(g->genmajormul); | 1388 | enterinc(g); |
1448 | if (g->GCdebt > 0 && gettotalbytes(g) > majorbase + majorinc) { | 1389 | g->gckind = KGC_GENMAJOR; |
1449 | lu_mem numobjs = fullgen(L, g); /* do a major collection */ | 1390 | genmajorstep(L, g); |
1450 | if (gettotalbytes(g) < majorbase + (majorinc / 2)) { | 1391 | } |
1451 | /* collected at least half of memory growth since last major | 1392 | else { /* regular case; do a minor collection */ |
1452 | collection; keep doing minor collections. */ | 1393 | g->marked = 0; |
1453 | lua_assert(g->lastatomic == 0); | 1394 | youngcollection(L, g); |
1454 | } | 1395 | setminordebt(g); |
1455 | else { /* bad collection */ | 1396 | lua_assert(g->GClastmajor == majorbase); |
1456 | g->lastatomic = numobjs; /* signal that last collection was bad */ | ||
1457 | setpause(g); /* do a long wait for next (major) collection */ | ||
1458 | } | ||
1459 | } | ||
1460 | else { /* regular case; do a minor collection */ | ||
1461 | youngcollection(L, g); | ||
1462 | setminordebt(g); | ||
1463 | g->GCestimate = majorbase; /* preserve base value */ | ||
1464 | } | ||
1465 | } | 1397 | } |
1466 | lua_assert(isdecGCmodegen(g)); | ||
1467 | } | 1398 | } |
1468 | 1399 | ||
1469 | /* }====================================================== */ | 1400 | /* }====================================================== */ |
@@ -1522,9 +1453,9 @@ void luaC_freeallobjects (lua_State *L) { | |||
1522 | } | 1453 | } |
1523 | 1454 | ||
1524 | 1455 | ||
1525 | static lu_mem atomic (lua_State *L) { | 1456 | static l_obj atomic (lua_State *L) { |
1457 | l_obj work = 0; | ||
1526 | global_State *g = G(L); | 1458 | global_State *g = G(L); |
1527 | lu_mem work = 0; | ||
1528 | GCObject *origweak, *origall; | 1459 | GCObject *origweak, *origall; |
1529 | GCObject *grayagain = g->grayagain; /* save original list */ | 1460 | GCObject *grayagain = g->grayagain; /* save original list */ |
1530 | g->grayagain = NULL; | 1461 | g->grayagain = NULL; |
@@ -1541,50 +1472,44 @@ static lu_mem atomic (lua_State *L) { | |||
1541 | work += propagateall(g); /* propagate changes */ | 1472 | work += propagateall(g); /* propagate changes */ |
1542 | g->gray = grayagain; | 1473 | g->gray = grayagain; |
1543 | work += propagateall(g); /* traverse 'grayagain' list */ | 1474 | work += propagateall(g); /* traverse 'grayagain' list */ |
1544 | convergeephemerons(g); | 1475 | work += convergeephemerons(g); |
1545 | /* at this point, all strongly accessible objects are marked. */ | 1476 | /* at this point, all strongly accessible objects are marked. */ |
1546 | /* Clear values from weak tables, before checking finalizers */ | 1477 | /* Clear values from weak tables, before checking finalizers */ |
1547 | clearbyvalues(g, g->weak, NULL); | 1478 | work += clearbyvalues(g, g->weak, NULL); |
1548 | clearbyvalues(g, g->allweak, NULL); | 1479 | work += clearbyvalues(g, g->allweak, NULL); |
1549 | origweak = g->weak; origall = g->allweak; | 1480 | origweak = g->weak; origall = g->allweak; |
1550 | separatetobefnz(g, 0); /* separate objects to be finalized */ | 1481 | separatetobefnz(g, 0); /* separate objects to be finalized */ |
1551 | work += markbeingfnz(g); /* mark objects that will be finalized */ | 1482 | work += markbeingfnz(g); /* mark objects that will be finalized */ |
1552 | work += propagateall(g); /* remark, to propagate 'resurrection' */ | 1483 | work += propagateall(g); /* remark, to propagate 'resurrection' */ |
1553 | convergeephemerons(g); | 1484 | work += convergeephemerons(g); |
1554 | /* at this point, all resurrected objects are marked. */ | 1485 | /* at this point, all resurrected objects are marked. */ |
1555 | /* remove dead objects from weak tables */ | 1486 | /* remove dead objects from weak tables */ |
1556 | clearbykeys(g, g->ephemeron); /* clear keys from all ephemeron tables */ | 1487 | work += clearbykeys(g, g->ephemeron); /* clear keys from all ephemeron */ |
1557 | clearbykeys(g, g->allweak); /* clear keys from all 'allweak' tables */ | 1488 | work += clearbykeys(g, g->allweak); /* clear keys from all 'allweak' */ |
1558 | /* clear values from resurrected weak tables */ | 1489 | /* clear values from resurrected weak tables */ |
1559 | clearbyvalues(g, g->weak, origweak); | 1490 | work += clearbyvalues(g, g->weak, origweak); |
1560 | clearbyvalues(g, g->allweak, origall); | 1491 | work += clearbyvalues(g, g->allweak, origall); |
1561 | luaS_clearcache(g); | 1492 | luaS_clearcache(g); |
1562 | g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ | 1493 | g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ |
1563 | lua_assert(g->gray == NULL); | 1494 | lua_assert(g->gray == NULL); |
1564 | return work; /* estimate of slots marked by 'atomic' */ | 1495 | return work; |
1565 | } | 1496 | } |
1566 | 1497 | ||
1567 | 1498 | ||
1568 | static int sweepstep (lua_State *L, global_State *g, | 1499 | static void sweepstep (lua_State *L, global_State *g, |
1569 | int nextstate, GCObject **nextlist) { | 1500 | int nextstate, GCObject **nextlist) { |
1570 | if (g->sweepgc) { | 1501 | if (g->sweepgc) |
1571 | l_mem olddebt = g->GCdebt; | 1502 | g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); |
1572 | int count; | ||
1573 | g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX, &count); | ||
1574 | g->GCestimate += g->GCdebt - olddebt; /* update estimate */ | ||
1575 | return count; | ||
1576 | } | ||
1577 | else { /* enter next state */ | 1503 | else { /* enter next state */ |
1578 | g->gcstate = nextstate; | 1504 | g->gcstate = nextstate; |
1579 | g->sweepgc = nextlist; | 1505 | g->sweepgc = nextlist; |
1580 | return 0; /* no work done */ | ||
1581 | } | 1506 | } |
1582 | } | 1507 | } |
1583 | 1508 | ||
1584 | 1509 | ||
1585 | static lu_mem singlestep (lua_State *L) { | 1510 | static l_obj singlestep (lua_State *L) { |
1586 | global_State *g = G(L); | 1511 | global_State *g = G(L); |
1587 | lu_mem work; | 1512 | l_obj work; |
1588 | lua_assert(!g->gcstopem); /* collector is not reentrant */ | 1513 | lua_assert(!g->gcstopem); /* collector is not reentrant */ |
1589 | g->gcstopem = 1; /* no emergency collections while collecting */ | 1514 | g->gcstopem = 1; /* no emergency collections while collecting */ |
1590 | switch (g->gcstate) { | 1515 | switch (g->gcstate) { |
@@ -1599,26 +1524,30 @@ static lu_mem singlestep (lua_State *L) { | |||
1599 | g->gcstate = GCSenteratomic; /* finish propagate phase */ | 1524 | g->gcstate = GCSenteratomic; /* finish propagate phase */ |
1600 | work = 0; | 1525 | work = 0; |
1601 | } | 1526 | } |
1602 | else | 1527 | else { |
1603 | work = propagatemark(g); /* traverse one gray object */ | 1528 | propagatemark(g); /* traverse one gray object */ |
1529 | work = 1; | ||
1530 | } | ||
1604 | break; | 1531 | break; |
1605 | } | 1532 | } |
1606 | case GCSenteratomic: { | 1533 | case GCSenteratomic: { |
1607 | work = atomic(L); /* work is what was traversed by 'atomic' */ | 1534 | work = atomic(L); |
1608 | entersweep(L); | 1535 | entersweep(L); |
1609 | g->GCestimate = gettotalbytes(g); /* first estimate */ | ||
1610 | break; | 1536 | break; |
1611 | } | 1537 | } |
1612 | case GCSswpallgc: { /* sweep "regular" objects */ | 1538 | case GCSswpallgc: { /* sweep "regular" objects */ |
1613 | work = sweepstep(L, g, GCSswpfinobj, &g->finobj); | 1539 | sweepstep(L, g, GCSswpfinobj, &g->finobj); |
1540 | work = GCSWEEPMAX; | ||
1614 | break; | 1541 | break; |
1615 | } | 1542 | } |
1616 | case GCSswpfinobj: { /* sweep objects with finalizers */ | 1543 | case GCSswpfinobj: { /* sweep objects with finalizers */ |
1617 | work = sweepstep(L, g, GCSswptobefnz, &g->tobefnz); | 1544 | sweepstep(L, g, GCSswptobefnz, &g->tobefnz); |
1545 | work = GCSWEEPMAX; | ||
1618 | break; | 1546 | break; |
1619 | } | 1547 | } |
1620 | case GCSswptobefnz: { /* sweep objects to be finalized */ | 1548 | case GCSswptobefnz: { /* sweep objects to be finalized */ |
1621 | work = sweepstep(L, g, GCSswpend, NULL); | 1549 | sweepstep(L, g, GCSswpend, NULL); |
1550 | work = GCSWEEPMAX; | ||
1622 | break; | 1551 | break; |
1623 | } | 1552 | } |
1624 | case GCSswpend: { /* finish sweeps */ | 1553 | case GCSswpend: { /* finish sweeps */ |
@@ -1627,10 +1556,11 @@ static lu_mem singlestep (lua_State *L) { | |||
1627 | work = 0; | 1556 | work = 0; |
1628 | break; | 1557 | break; |
1629 | } | 1558 | } |
1630 | case GCScallfin: { /* call remaining finalizers */ | 1559 | case GCScallfin: { /* call finalizers */ |
1631 | if (g->tobefnz && !g->gcemergency) { | 1560 | if (g->tobefnz && !g->gcemergency) { |
1632 | g->gcstopem = 0; /* ok collections during finalizers */ | 1561 | g->gcstopem = 0; /* ok collections during finalizers */ |
1633 | work = runafewfinalizers(L, GCFINMAX) * GCFINALIZECOST; | 1562 | GCTM(L); /* call one finalizer */ |
1563 | work = 1; | ||
1634 | } | 1564 | } |
1635 | else { /* emergency mode or no more finalizers */ | 1565 | else { /* emergency mode or no more finalizers */ |
1636 | g->gcstate = GCSpause; /* finish collection */ | 1566 | g->gcstate = GCSpause; /* finish collection */ |
@@ -1665,20 +1595,16 @@ void luaC_runtilstate (lua_State *L, int statesmask) { | |||
1665 | ** controls when next step will be performed. | 1595 | ** controls when next step will be performed. |
1666 | */ | 1596 | */ |
1667 | static void incstep (lua_State *L, global_State *g) { | 1597 | static void incstep (lua_State *L, global_State *g) { |
1668 | int stepmul = (getgcparam(g->gcstepmul) | 1); /* avoid division by 0 */ | 1598 | l_obj stepsize = cast(l_obj, 1) << g->gcstepsize; |
1669 | l_mem debt = (g->GCdebt / WORK2MEM) * stepmul; | 1599 | l_obj work2do = applygcparam(g, gcstepmul, stepsize); |
1670 | l_mem stepsize = (g->gcstepsize <= log2maxs(l_mem)) | ||
1671 | ? ((cast(l_mem, 1) << g->gcstepsize) / WORK2MEM) * stepmul | ||
1672 | : MAX_LMEM; /* overflow; keep maximum value */ | ||
1673 | do { /* repeat until pause or enough "credit" (negative debt) */ | 1600 | do { /* repeat until pause or enough "credit" (negative debt) */ |
1674 | lu_mem work = singlestep(L); /* perform one single step */ | 1601 | l_obj work = singlestep(L); /* perform one single step */ |
1675 | debt -= work; | 1602 | work2do -= work; |
1676 | } while (debt > -stepsize && g->gcstate != GCSpause); | 1603 | } while (work2do > 0 && g->gcstate != GCSpause); |
1677 | if (g->gcstate == GCSpause) | 1604 | if (g->gcstate == GCSpause) |
1678 | setpause(g); /* pause until next cycle */ | 1605 | setpause(g); /* pause until next cycle */ |
1679 | else { | 1606 | else { |
1680 | debt = (debt / stepmul) * WORK2MEM; /* convert 'work units' to bytes */ | 1607 | luaE_setdebt(g, stepsize); |
1681 | luaE_setdebt(g, debt); | ||
1682 | } | 1608 | } |
1683 | } | 1609 | } |
1684 | 1610 | ||
@@ -1689,13 +1615,21 @@ static void incstep (lua_State *L, global_State *g) { | |||
1689 | */ | 1615 | */ |
1690 | void luaC_step (lua_State *L) { | 1616 | void luaC_step (lua_State *L) { |
1691 | global_State *g = G(L); | 1617 | global_State *g = G(L); |
1618 | lua_assert(!g->gcemergency); | ||
1692 | if (!gcrunning(g)) /* not running? */ | 1619 | if (!gcrunning(g)) /* not running? */ |
1693 | luaE_setdebt(g, -2000); | 1620 | luaE_setdebt(g, 2000); |
1694 | else { | 1621 | else { |
1695 | if(isdecGCmodegen(g)) | 1622 | switch (g->gckind) { |
1696 | genstep(L, g); | 1623 | case KGC_INC: |
1697 | else | 1624 | incstep(L, g); |
1698 | incstep(L, g); | 1625 | break; |
1626 | case KGC_GEN: | ||
1627 | genstep(L, g); | ||
1628 | break; | ||
1629 | case KGC_GENMAJOR: | ||
1630 | genmajorstep(L, g); | ||
1631 | break; | ||
1632 | } | ||
1699 | } | 1633 | } |
1700 | } | 1634 | } |
1701 | 1635 | ||
@@ -1715,8 +1649,8 @@ static void fullinc (lua_State *L, global_State *g) { | |||
1715 | luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ | 1649 | luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ |
1716 | g->gcstate = GCSenteratomic; /* go straight to atomic phase ??? */ | 1650 | g->gcstate = GCSenteratomic; /* go straight to atomic phase ??? */ |
1717 | luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ | 1651 | luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ |
1718 | /* estimate must be correct after a full GC cycle */ | 1652 | /* 'marked' must be correct after a full GC cycle */ |
1719 | lua_assert(g->GCestimate == gettotalbytes(g)); | 1653 | lua_assert(g->marked == gettotalobjs(g)); |
1720 | luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ | 1654 | luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ |
1721 | setpause(g); | 1655 | setpause(g); |
1722 | } | 1656 | } |
@@ -1731,10 +1665,10 @@ void luaC_fullgc (lua_State *L, int isemergency) { | |||
1731 | global_State *g = G(L); | 1665 | global_State *g = G(L); |
1732 | lua_assert(!g->gcemergency); | 1666 | lua_assert(!g->gcemergency); |
1733 | g->gcemergency = isemergency; /* set flag */ | 1667 | g->gcemergency = isemergency; /* set flag */ |
1734 | if (g->gckind == KGC_INC) | 1668 | if (g->gckind == KGC_GEN) |
1735 | fullinc(L, g); | ||
1736 | else | ||
1737 | fullgen(L, g); | 1669 | fullgen(L, g); |
1670 | else | ||
1671 | fullinc(L, g); | ||
1738 | g->gcemergency = 0; | 1672 | g->gcemergency = 0; |
1739 | } | 1673 | } |
1740 | 1674 | ||
@@ -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))) |
@@ -392,7 +392,7 @@ typedef struct TString { | |||
392 | size_t lnglen; /* length for long strings */ | 392 | size_t lnglen; /* length for long strings */ |
393 | struct TString *hnext; /* linked list for hash table */ | 393 | struct TString *hnext; /* linked list for hash table */ |
394 | } u; | 394 | } u; |
395 | char contents[1]; | 395 | char contents[1]; /* string body starts here */ |
396 | } TString; | 396 | } TString; |
397 | 397 | ||
398 | 398 | ||
@@ -401,15 +401,22 @@ typedef struct TString { | |||
401 | ** Get the actual string (array of bytes) from a 'TString'. (Generic | 401 | ** Get the actual string (array of bytes) from a 'TString'. (Generic |
402 | ** version and specialized versions for long and short strings.) | 402 | ** version and specialized versions for long and short strings.) |
403 | */ | 403 | */ |
404 | #define getstr(ts) ((ts)->contents) | ||
405 | #define getlngstr(ts) check_exp((ts)->shrlen == 0xFF, (ts)->contents) | 404 | #define getlngstr(ts) check_exp((ts)->shrlen == 0xFF, (ts)->contents) |
406 | #define getshrstr(ts) check_exp((ts)->shrlen != 0xFF, (ts)->contents) | 405 | #define getshrstr(ts) check_exp((ts)->shrlen != 0xFF, (ts)->contents) |
406 | #define getstr(ts) ((ts)->contents) | ||
407 | 407 | ||
408 | 408 | ||
409 | /* get string length from 'TString *s' */ | 409 | /* get string length from 'TString *s' */ |
410 | #define tsslen(s) \ | 410 | #define tsslen(s) \ |
411 | ((s)->shrlen != 0xFF ? (s)->shrlen : (s)->u.lnglen) | 411 | ((s)->shrlen != 0xFF ? (s)->shrlen : (s)->u.lnglen) |
412 | 412 | ||
413 | /* | ||
414 | ** Get string and length */ | ||
415 | #define getlstr(ts, len) \ | ||
416 | ((ts)->shrlen != 0xFF \ | ||
417 | ? (cast_void(len = (ts)->shrlen), (ts)->contents) \ | ||
418 | : (cast_void(len = (ts)->u.lnglen), (ts)->contents)) | ||
419 | |||
413 | /* }================================================================== */ | 420 | /* }================================================================== */ |
414 | 421 | ||
415 | 422 | ||
@@ -544,13 +551,21 @@ typedef struct AbsLineInfo { | |||
544 | int line; | 551 | int line; |
545 | } AbsLineInfo; | 552 | } AbsLineInfo; |
546 | 553 | ||
554 | |||
555 | /* | ||
556 | ** Flags in Prototypes | ||
557 | */ | ||
558 | #define PF_ISVARARG 1 | ||
559 | #define PF_FIXED 2 /* prototype has parts in fixed memory */ | ||
560 | |||
561 | |||
547 | /* | 562 | /* |
548 | ** Function Prototypes | 563 | ** Function Prototypes |
549 | */ | 564 | */ |
550 | typedef struct Proto { | 565 | typedef struct Proto { |
551 | CommonHeader; | 566 | CommonHeader; |
552 | lu_byte numparams; /* number of fixed (named) parameters */ | 567 | lu_byte numparams; /* number of fixed (named) parameters */ |
553 | lu_byte is_vararg; | 568 | lu_byte flag; |
554 | lu_byte maxstacksize; /* number of registers needed by this function */ | 569 | lu_byte maxstacksize; /* number of registers needed by this function */ |
555 | int sizeupvalues; /* size of 'upvalues' */ | 570 | int sizeupvalues; /* size of 'upvalues' */ |
556 | int sizek; /* size of 'k' */ | 571 | int sizek; /* size of 'k' */ |
@@ -741,7 +756,6 @@ typedef struct Table { | |||
741 | unsigned int alimit; /* "limit" of 'array' array */ | 756 | unsigned int alimit; /* "limit" of 'array' array */ |
742 | TValue *array; /* array part */ | 757 | TValue *array; /* array part */ |
743 | Node *node; | 758 | Node *node; |
744 | Node *lastfree; /* any free position is before this position */ | ||
745 | struct Table *metatable; | 759 | struct Table *metatable; |
746 | GCObject *gclist; | 760 | GCObject *gclist; |
747 | } Table; | 761 | } 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 | ||
@@ -278,7 +247,8 @@ static void close_state (lua_State *L) { | |||
278 | } | 247 | } |
279 | luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); | 248 | luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); |
280 | freestack(L); | 249 | freestack(L); |
281 | lua_assert(gettotalbytes(g) == sizeof(LG)); | 250 | lua_assert(g->totalbytes == sizeof(LG)); |
251 | lua_assert(gettotalobjs(g) == 1); | ||
282 | (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ | 252 | (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ |
283 | } | 253 | } |
284 | 254 | ||
@@ -349,15 +319,7 @@ LUA_API int lua_closethread (lua_State *L, lua_State *from) { | |||
349 | } | 319 | } |
350 | 320 | ||
351 | 321 | ||
352 | /* | 322 | LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud, unsigned int seed) { |
353 | ** Deprecated! Use 'lua_closethread' instead. | ||
354 | */ | ||
355 | LUA_API int lua_resetthread (lua_State *L) { | ||
356 | return lua_closethread(L, NULL); | ||
357 | } | ||
358 | |||
359 | |||
360 | LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | ||
361 | int i; | 323 | int i; |
362 | lua_State *L; | 324 | lua_State *L; |
363 | global_State *g; | 325 | global_State *g; |
@@ -377,7 +339,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
377 | g->warnf = NULL; | 339 | g->warnf = NULL; |
378 | g->ud_warn = NULL; | 340 | g->ud_warn = NULL; |
379 | g->mainthread = L; | 341 | g->mainthread = L; |
380 | g->seed = luai_makeseed(L); | 342 | g->seed = seed; |
381 | g->gcstp = GCSTPGC; /* no GC while building state */ | 343 | g->gcstp = GCSTPGC; /* no GC while building state */ |
382 | g->strt.size = g->strt.nuse = 0; | 344 | g->strt.size = g->strt.nuse = 0; |
383 | g->strt.hash = NULL; | 345 | g->strt.hash = NULL; |
@@ -395,14 +357,15 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
395 | g->weak = g->ephemeron = g->allweak = NULL; | 357 | g->weak = g->ephemeron = g->allweak = NULL; |
396 | g->twups = NULL; | 358 | g->twups = NULL; |
397 | g->totalbytes = sizeof(LG); | 359 | g->totalbytes = sizeof(LG); |
360 | g->totalobjs = 1; | ||
361 | g->marked = 0; | ||
398 | g->GCdebt = 0; | 362 | g->GCdebt = 0; |
399 | g->lastatomic = 0; | ||
400 | setivalue(&g->nilvalue, 0); /* to signal that state is not yet built */ | 363 | setivalue(&g->nilvalue, 0); /* to signal that state is not yet built */ |
401 | setgcparam(g->gcpause, LUAI_GCPAUSE); | 364 | setgcparam(g, gcpause, LUAI_GCPAUSE); |
402 | setgcparam(g->gcstepmul, LUAI_GCMUL); | 365 | setgcparam(g, gcstepmul, LUAI_GCMUL); |
403 | g->gcstepsize = LUAI_GCSTEPSIZE; | 366 | g->gcstepsize = LUAI_GCSTEPSIZE; |
404 | setgcparam(g->genmajormul, LUAI_GENMAJORMUL); | 367 | setgcparam(g, genmajormul, LUAI_GENMAJORMUL); |
405 | g->genminormul = LUAI_GENMINORMUL; | 368 | setgcparam(g, genminormul, LUAI_GENMINORMUL); |
406 | for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; | 369 | for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; |
407 | if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { | 370 | if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { |
408 | /* memory allocation error: free partial state */ | 371 | /* 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 | */ |
@@ -369,8 +390,15 @@ int luaH_next (lua_State *L, Table *t, StkId key) { | |||
369 | 390 | ||
370 | 391 | ||
371 | static void freehash (lua_State *L, Table *t) { | 392 | static void freehash (lua_State *L, Table *t) { |
372 | if (!isdummy(t)) | 393 | if (!isdummy(t)) { |
373 | luaM_freearray(L, t->node, cast_sizet(sizenode(t))); | 394 | size_t bsize = sizenode(t) * sizeof(Node); /* 'node' size in bytes */ |
395 | char *arr = cast_charp(t->node); | ||
396 | if (haslastfree(t)) { | ||
397 | bsize += sizeof(Limbox); | ||
398 | arr -= sizeof(Limbox); | ||
399 | } | ||
400 | luaM_freearray(L, arr, bsize); | ||
401 | } | ||
374 | } | 402 | } |
375 | 403 | ||
376 | 404 | ||
@@ -481,7 +509,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) { | |||
481 | if (size == 0) { /* no elements to hash part? */ | 509 | if (size == 0) { /* no elements to hash part? */ |
482 | t->node = cast(Node *, dummynode); /* use common 'dummynode' */ | 510 | t->node = cast(Node *, dummynode); /* use common 'dummynode' */ |
483 | t->lsizenode = 0; | 511 | t->lsizenode = 0; |
484 | t->lastfree = NULL; /* signal that it is using dummy node */ | 512 | setdummy(t); /* signal that it is using dummy node */ |
485 | } | 513 | } |
486 | else { | 514 | else { |
487 | int i; | 515 | int i; |
@@ -489,15 +517,22 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) { | |||
489 | if (lsize > MAXHBITS || (1u << lsize) > MAXHSIZE) | 517 | if (lsize > MAXHBITS || (1u << lsize) > MAXHSIZE) |
490 | luaG_runerror(L, "table overflow"); | 518 | luaG_runerror(L, "table overflow"); |
491 | size = twoto(lsize); | 519 | size = twoto(lsize); |
492 | t->node = luaM_newvector(L, size, Node); | 520 | if (lsize <= LLIMFORLAST) /* no 'lastfree' field? */ |
521 | t->node = luaM_newvector(L, size, Node); | ||
522 | else { | ||
523 | size_t bsize = size * sizeof(Node) + sizeof(Limbox); | ||
524 | char *node = luaM_newblock(L, bsize); | ||
525 | t->node = cast(Node *, node + sizeof(Limbox)); | ||
526 | *getlastfree(t) = size; /* all positions are free */ | ||
527 | } | ||
528 | t->lsizenode = cast_byte(lsize); | ||
529 | setnodummy(t); | ||
493 | for (i = 0; i < cast_int(size); i++) { | 530 | for (i = 0; i < cast_int(size); i++) { |
494 | Node *n = gnode(t, i); | 531 | Node *n = gnode(t, i); |
495 | gnext(n) = 0; | 532 | gnext(n) = 0; |
496 | setnilkey(n); | 533 | setnilkey(n); |
497 | setempty(gval(n)); | 534 | setempty(gval(n)); |
498 | } | 535 | } |
499 | t->lsizenode = cast_byte(lsize); | ||
500 | t->lastfree = gnode(t, size); /* all positions are free */ | ||
501 | } | 536 | } |
502 | } | 537 | } |
503 | 538 | ||
@@ -522,18 +557,21 @@ static void reinsert (lua_State *L, Table *ot, Table *t) { | |||
522 | 557 | ||
523 | 558 | ||
524 | /* | 559 | /* |
525 | ** Exchange the hash part of 't1' and 't2'. | 560 | ** Exchange the hash part of 't1' and 't2'. (In 'flags', only the |
561 | ** dummy bit must be exchanged: The 'isrealasize' is not related | ||
562 | ** to the hash part, and the metamethod bits do not change during | ||
563 | ** a resize, so the "real" table can keep their values.) | ||
526 | */ | 564 | */ |
527 | static void exchangehashpart (Table *t1, Table *t2) { | 565 | static void exchangehashpart (Table *t1, Table *t2) { |
528 | lu_byte lsizenode = t1->lsizenode; | 566 | lu_byte lsizenode = t1->lsizenode; |
529 | Node *node = t1->node; | 567 | Node *node = t1->node; |
530 | Node *lastfree = t1->lastfree; | 568 | int bitdummy1 = t1->flags & BITDUMMY; |
531 | t1->lsizenode = t2->lsizenode; | 569 | t1->lsizenode = t2->lsizenode; |
532 | t1->node = t2->node; | 570 | t1->node = t2->node; |
533 | t1->lastfree = t2->lastfree; | 571 | t1->flags = (t1->flags & NOTBITDUMMY) | (t2->flags & BITDUMMY); |
534 | t2->lsizenode = lsizenode; | 572 | t2->lsizenode = lsizenode; |
535 | t2->node = node; | 573 | t2->node = node; |
536 | t2->lastfree = lastfree; | 574 | t2->flags = (t2->flags & NOTBITDUMMY) | bitdummy1; |
537 | } | 575 | } |
538 | 576 | ||
539 | 577 | ||
@@ -557,6 +595,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize, | |||
557 | unsigned int oldasize = setlimittosize(t); | 595 | unsigned int oldasize = setlimittosize(t); |
558 | TValue *newarray; | 596 | TValue *newarray; |
559 | /* create new hash part with appropriate size into 'newt' */ | 597 | /* create new hash part with appropriate size into 'newt' */ |
598 | newt.flags = 0; | ||
560 | setnodevector(L, &newt, nhsize); | 599 | setnodevector(L, &newt, nhsize); |
561 | if (newasize < oldasize) { /* will array shrink? */ | 600 | if (newasize < oldasize) { /* will array shrink? */ |
562 | t->alimit = newasize; /* pretend array has new size... */ | 601 | t->alimit = newasize; /* pretend array has new size... */ |
@@ -643,11 +682,22 @@ void luaH_free (lua_State *L, Table *t) { | |||
643 | 682 | ||
644 | 683 | ||
645 | static Node *getfreepos (Table *t) { | 684 | static Node *getfreepos (Table *t) { |
646 | if (!isdummy(t)) { | 685 | if (haslastfree(t)) { /* does it have 'lastfree' information? */ |
647 | while (t->lastfree > t->node) { | 686 | /* look for a spot before 'lastfree', updating 'lastfree' */ |
648 | t->lastfree--; | 687 | while (*getlastfree(t) > 0) { |
649 | if (keyisnil(t->lastfree)) | 688 | Node *free = gnode(t, --(*getlastfree(t))); |
650 | return t->lastfree; | 689 | if (keyisnil(free)) |
690 | return free; | ||
691 | } | ||
692 | } | ||
693 | else { /* no 'lastfree' information */ | ||
694 | if (!isdummy(t)) { | ||
695 | int i = sizenode(t); | ||
696 | while (i--) { /* do a linear search */ | ||
697 | Node *free = gnode(t, i); | ||
698 | if (keyisnil(free)) | ||
699 | return free; | ||
700 | } | ||
651 | } | 701 | } |
652 | } | 702 | } |
653 | return NULL; /* could not find a free place */ | 703 | 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)) |
@@ -531,7 +531,7 @@ static void checkobject (global_State *g, GCObject *o, int maybedead, | |||
531 | } | 531 | } |
532 | 532 | ||
533 | 533 | ||
534 | static lu_mem checkgraylist (global_State *g, GCObject *o) { | 534 | static l_obj checkgraylist (global_State *g, GCObject *o) { |
535 | int total = 0; /* count number of elements in the list */ | 535 | int total = 0; /* count number of elements in the list */ |
536 | cast_void(g); /* better to keep it if we need to print an object */ | 536 | cast_void(g); /* better to keep it if we need to print an object */ |
537 | while (o) { | 537 | while (o) { |
@@ -560,7 +560,7 @@ static lu_mem checkgraylist (global_State *g, GCObject *o) { | |||
560 | /* | 560 | /* |
561 | ** Check objects in gray lists. | 561 | ** Check objects in gray lists. |
562 | */ | 562 | */ |
563 | static lu_mem checkgrays (global_State *g) { | 563 | static l_obj checkgrays (global_State *g) { |
564 | int total = 0; /* count number of elements in all lists */ | 564 | int total = 0; /* count number of elements in all lists */ |
565 | if (!keepinvariant(g)) return total; | 565 | if (!keepinvariant(g)) return total; |
566 | total += checkgraylist(g, g->gray); | 566 | total += checkgraylist(g, g->gray); |
@@ -577,7 +577,7 @@ static lu_mem checkgrays (global_State *g) { | |||
577 | ** 'count' and check its TESTBIT. (It must have been previously set by | 577 | ** 'count' and check its TESTBIT. (It must have been previously set by |
578 | ** 'checkgraylist'.) | 578 | ** 'checkgraylist'.) |
579 | */ | 579 | */ |
580 | static void incifingray (global_State *g, GCObject *o, lu_mem *count) { | 580 | static void incifingray (global_State *g, GCObject *o, l_obj *count) { |
581 | if (!keepinvariant(g)) | 581 | if (!keepinvariant(g)) |
582 | return; /* gray lists not being kept in these phases */ | 582 | return; /* gray lists not being kept in these phases */ |
583 | if (o->tt == LUA_VUPVAL) { | 583 | if (o->tt == LUA_VUPVAL) { |
@@ -594,10 +594,10 @@ static void incifingray (global_State *g, GCObject *o, lu_mem *count) { | |||
594 | } | 594 | } |
595 | 595 | ||
596 | 596 | ||
597 | static lu_mem checklist (global_State *g, int maybedead, int tof, | 597 | static l_obj checklist (global_State *g, int maybedead, int tof, |
598 | GCObject *newl, GCObject *survival, GCObject *old, GCObject *reallyold) { | 598 | GCObject *newl, GCObject *survival, GCObject *old, GCObject *reallyold) { |
599 | GCObject *o; | 599 | GCObject *o; |
600 | lu_mem total = 0; /* number of object that should be in gray lists */ | 600 | l_obj total = 0; /* number of object that should be in gray lists */ |
601 | for (o = newl; o != survival; o = o->next) { | 601 | for (o = newl; o != survival; o = o->next) { |
602 | checkobject(g, o, maybedead, G_NEW); | 602 | checkobject(g, o, maybedead, G_NEW); |
603 | incifingray(g, o, &total); | 603 | incifingray(g, o, &total); |
@@ -626,8 +626,8 @@ int lua_checkmemory (lua_State *L) { | |||
626 | global_State *g = G(L); | 626 | global_State *g = G(L); |
627 | GCObject *o; | 627 | GCObject *o; |
628 | int maybedead; | 628 | int maybedead; |
629 | lu_mem totalin; /* total of objects that are in gray lists */ | 629 | l_obj totalin; /* total of objects that are in gray lists */ |
630 | lu_mem totalshould; /* total of objects that should be in gray lists */ | 630 | l_obj totalshould; /* total of objects that should be in gray lists */ |
631 | if (keepinvariant(g)) { | 631 | if (keepinvariant(g)) { |
632 | assert(!iswhite(g->mainthread)); | 632 | assert(!iswhite(g->mainthread)); |
633 | assert(!iswhite(gcvalue(&g->l_registry))); | 633 | assert(!iswhite(gcvalue(&g->l_registry))); |
@@ -999,9 +999,8 @@ static int table_query (lua_State *L) { | |||
999 | if (i == -1) { | 999 | if (i == -1) { |
1000 | lua_pushinteger(L, asize); | 1000 | lua_pushinteger(L, asize); |
1001 | lua_pushinteger(L, allocsizenode(t)); | 1001 | lua_pushinteger(L, allocsizenode(t)); |
1002 | lua_pushinteger(L, isdummy(t) ? 0 : t->lastfree - t->node); | ||
1003 | lua_pushinteger(L, t->alimit); | 1002 | lua_pushinteger(L, t->alimit); |
1004 | return 4; | 1003 | return 3; |
1005 | } | 1004 | } |
1006 | else if ((unsigned int)i < asize) { | 1005 | else if ((unsigned int)i < asize) { |
1007 | lua_pushinteger(L, i); | 1006 | lua_pushinteger(L, i); |
@@ -1028,6 +1027,16 @@ static int table_query (lua_State *L) { | |||
1028 | } | 1027 | } |
1029 | 1028 | ||
1030 | 1029 | ||
1030 | static int query_inc (lua_State *L) { | ||
1031 | global_State *g = G(L); | ||
1032 | lua_pushinteger(L, gettotalobjs(g)); | ||
1033 | lua_pushinteger(L, g->GCdebt); | ||
1034 | lua_pushinteger(L, applygcparam(g, gcpause, 100)); | ||
1035 | lua_pushinteger(L, applygcparam(g, gcstepmul, 100)); | ||
1036 | lua_pushinteger(L, cast(l_obj, 1) << g->gcstepsize); | ||
1037 | return 5; | ||
1038 | } | ||
1039 | |||
1031 | static int string_query (lua_State *L) { | 1040 | static int string_query (lua_State *L) { |
1032 | stringtable *tb = &G(L)->strt; | 1041 | stringtable *tb = &G(L)->strt; |
1033 | int s = cast_int(luaL_optinteger(L, 1, 0)) - 1; | 1042 | int s = cast_int(luaL_optinteger(L, 1, 0)) - 1; |
@@ -1150,7 +1159,7 @@ static int num2int (lua_State *L) { | |||
1150 | static int newstate (lua_State *L) { | 1159 | static int newstate (lua_State *L) { |
1151 | void *ud; | 1160 | void *ud; |
1152 | lua_Alloc f = lua_getallocf(L, &ud); | 1161 | lua_Alloc f = lua_getallocf(L, &ud); |
1153 | lua_State *L1 = lua_newstate(f, ud); | 1162 | lua_State *L1 = lua_newstate(f, ud, 0); |
1154 | if (L1) { | 1163 | if (L1) { |
1155 | lua_atpanic(L1, tpanic); | 1164 | lua_atpanic(L1, tpanic); |
1156 | lua_pushlightuserdata(L, L1); | 1165 | lua_pushlightuserdata(L, L1); |
@@ -1169,31 +1178,15 @@ static lua_State *getstate (lua_State *L) { | |||
1169 | 1178 | ||
1170 | 1179 | ||
1171 | static int loadlib (lua_State *L) { | 1180 | static int loadlib (lua_State *L) { |
1172 | static const luaL_Reg libs[] = { | ||
1173 | {LUA_GNAME, luaopen_base}, | ||
1174 | {"coroutine", luaopen_coroutine}, | ||
1175 | {"debug", luaopen_debug}, | ||
1176 | {"io", luaopen_io}, | ||
1177 | {"os", luaopen_os}, | ||
1178 | {"math", luaopen_math}, | ||
1179 | {"string", luaopen_string}, | ||
1180 | {"table", luaopen_table}, | ||
1181 | {"T", luaB_opentests}, | ||
1182 | {NULL, NULL} | ||
1183 | }; | ||
1184 | lua_State *L1 = getstate(L); | 1181 | lua_State *L1 = getstate(L); |
1185 | int i; | 1182 | int what = luaL_checkinteger(L, 2); |
1186 | luaL_requiref(L1, "package", luaopen_package, 0); | 1183 | luaL_openselectedlibs(L1, what); |
1184 | luaL_requiref(L1, "T", luaB_opentests, 0); | ||
1187 | lua_assert(lua_type(L1, -1) == LUA_TTABLE); | 1185 | lua_assert(lua_type(L1, -1) == LUA_TTABLE); |
1188 | /* 'requiref' should not reload module already loaded... */ | 1186 | /* 'requiref' should not reload module already loaded... */ |
1189 | luaL_requiref(L1, "package", NULL, 1); /* seg. fault if it reloads */ | 1187 | luaL_requiref(L1, "T", NULL, 1); /* seg. fault if it reloads */ |
1190 | /* ...but should return the same module */ | 1188 | /* ...but should return the same module */ |
1191 | lua_assert(lua_compare(L1, -1, -2, LUA_OPEQ)); | 1189 | lua_assert(lua_compare(L1, -1, -2, LUA_OPEQ)); |
1192 | luaL_getsubtable(L1, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); | ||
1193 | for (i = 0; libs[i].name; i++) { | ||
1194 | lua_pushcfunction(L1, libs[i].func); | ||
1195 | lua_setfield(L1, -2, libs[i].name); | ||
1196 | } | ||
1197 | return 0; | 1190 | return 0; |
1198 | } | 1191 | } |
1199 | 1192 | ||
@@ -1259,7 +1252,7 @@ static int checkpanic (lua_State *L) { | |||
1259 | lua_Alloc f = lua_getallocf(L, &ud); | 1252 | lua_Alloc f = lua_getallocf(L, &ud); |
1260 | b.paniccode = luaL_optstring(L, 2, ""); | 1253 | b.paniccode = luaL_optstring(L, 2, ""); |
1261 | b.L = L; | 1254 | b.L = L; |
1262 | L1 = lua_newstate(f, ud); /* create new state */ | 1255 | L1 = lua_newstate(f, ud, 0); /* create new state */ |
1263 | if (L1 == NULL) { /* error? */ | 1256 | if (L1 == NULL) { /* error? */ |
1264 | lua_pushnil(L); | 1257 | lua_pushnil(L); |
1265 | return 1; | 1258 | return 1; |
@@ -1520,8 +1513,11 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) { | |||
1520 | luaL_loadfile(L1, luaL_checkstring(L1, getnum)); | 1513 | luaL_loadfile(L1, luaL_checkstring(L1, getnum)); |
1521 | } | 1514 | } |
1522 | else if EQ("loadstring") { | 1515 | else if EQ("loadstring") { |
1523 | const char *s = luaL_checkstring(L1, getnum); | 1516 | size_t slen; |
1524 | luaL_loadstring(L1, s); | 1517 | const char *s = luaL_checklstring(L1, getnum, &slen); |
1518 | const char *name = getstring; | ||
1519 | const char *mode = getstring; | ||
1520 | luaL_loadbufferx(L1, s, slen, name, mode); | ||
1525 | } | 1521 | } |
1526 | else if EQ("newmetatable") { | 1522 | else if EQ("newmetatable") { |
1527 | lua_pushboolean(L1, luaL_newmetatable(L1, getstring)); | 1523 | lua_pushboolean(L1, luaL_newmetatable(L1, getstring)); |
@@ -1934,6 +1930,7 @@ static const struct luaL_Reg tests_funcs[] = { | |||
1934 | {"pushuserdata", pushuserdata}, | 1930 | {"pushuserdata", pushuserdata}, |
1935 | {"querystr", string_query}, | 1931 | {"querystr", string_query}, |
1936 | {"querytab", table_query}, | 1932 | {"querytab", table_query}, |
1933 | {"queryinc", query_inc}, | ||
1937 | {"ref", tref}, | 1934 | {"ref", tref}, |
1938 | {"resume", coresume}, | 1935 | {"resume", coresume}, |
1939 | {"s2d", s2d}, | 1936 | {"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 |
@@ -260,7 +260,7 @@ void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) { | |||
260 | int nextra = ci->u.l.nextraargs; | 260 | int nextra = ci->u.l.nextraargs; |
261 | if (wanted < 0) { | 261 | if (wanted < 0) { |
262 | wanted = nextra; /* get all extra arguments available */ | 262 | wanted = nextra; /* get all extra arguments available */ |
263 | checkstackGCp(L, nextra, where); /* ensure stack space */ | 263 | checkstackp(L, nextra, where); /* ensure stack space */ |
264 | L->top.p = where + nextra; /* next instruction will need top */ | 264 | L->top.p = where + nextra; /* next instruction will need top */ |
265 | } | 265 | } |
266 | for (i = 0; i < wanted && i < nextra; i++) | 266 | 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 |
@@ -376,10 +379,10 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, | |||
376 | ** have different lengths. | 379 | ** have different lengths. |
377 | */ | 380 | */ |
378 | static int l_strcmp (const TString *ts1, const TString *ts2) { | 381 | static int l_strcmp (const TString *ts1, const TString *ts2) { |
379 | const char *s1 = getstr(ts1); | 382 | size_t rl1; /* real length */ |
380 | size_t rl1 = tsslen(ts1); /* real length */ | 383 | const char *s1 = getlstr(ts1, rl1); |
381 | const char *s2 = getstr(ts2); | 384 | size_t rl2; |
382 | size_t rl2 = tsslen(ts2); | 385 | const char *s2 = getlstr(ts2, rl2); |
383 | for (;;) { /* for each segment */ | 386 | for (;;) { /* for each segment */ |
384 | int temp = strcoll(s1, s2); | 387 | int temp = strcoll(s1, s2); |
385 | if (temp != 0) /* not equal? */ | 388 | if (temp != 0) /* not equal? */ |
@@ -629,8 +632,9 @@ static void copy2buff (StkId top, int n, char *buff) { | |||
629 | size_t tl = 0; /* size already copied */ | 632 | size_t tl = 0; /* size already copied */ |
630 | do { | 633 | do { |
631 | TString *st = tsvalue(s2v(top - n)); | 634 | TString *st = tsvalue(s2v(top - n)); |
632 | size_t l = tsslen(st); /* length of string being copied */ | 635 | size_t l; /* length of string being copied */ |
633 | memcpy(buff + tl, getstr(st), l * sizeof(char)); | 636 | const char *s = getlstr(st, l); |
637 | memcpy(buff + tl, s, l * sizeof(char)); | ||
634 | tl += l; | 638 | tl += l; |
635 | } while (--n > 0); | 639 | } while (--n > 0); |
636 | } | 640 | } |
@@ -1783,15 +1787,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1783 | } | 1787 | } |
1784 | vmcase(OP_FORLOOP) { | 1788 | vmcase(OP_FORLOOP) { |
1785 | StkId ra = RA(i); | 1789 | StkId ra = RA(i); |
1786 | if (ttisinteger(s2v(ra + 2))) { /* integer loop? */ | 1790 | if (ttisinteger(s2v(ra + 1))) { /* integer loop? */ |
1787 | lua_Unsigned count = l_castS2U(ivalue(s2v(ra + 1))); | 1791 | lua_Unsigned count = l_castS2U(ivalue(s2v(ra))); |
1788 | if (count > 0) { /* still more iterations? */ | 1792 | if (count > 0) { /* still more iterations? */ |
1789 | lua_Integer step = ivalue(s2v(ra + 2)); | 1793 | lua_Integer step = ivalue(s2v(ra + 1)); |
1790 | lua_Integer idx = ivalue(s2v(ra)); /* internal index */ | 1794 | lua_Integer idx = ivalue(s2v(ra + 2)); /* control variable */ |
1791 | chgivalue(s2v(ra + 1), count - 1); /* update counter */ | 1795 | chgivalue(s2v(ra), count - 1); /* update counter */ |
1792 | idx = intop(+, idx, step); /* add step to index */ | 1796 | idx = intop(+, idx, step); /* add step to index */ |
1793 | chgivalue(s2v(ra), idx); /* update internal index */ | 1797 | chgivalue(s2v(ra + 2), idx); /* update control variable */ |
1794 | setivalue(s2v(ra + 3), idx); /* and control variable */ | ||
1795 | pc -= GETARG_Bx(i); /* jump back */ | 1798 | pc -= GETARG_Bx(i); /* jump back */ |
1796 | } | 1799 | } |
1797 | } | 1800 | } |
@@ -1808,26 +1811,38 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1808 | vmbreak; | 1811 | vmbreak; |
1809 | } | 1812 | } |
1810 | vmcase(OP_TFORPREP) { | 1813 | vmcase(OP_TFORPREP) { |
1814 | /* before: 'ra' has the iterator function, 'ra + 1' has the state, | ||
1815 | 'ra + 2' has the initial value for the control variable, and | ||
1816 | 'ra + 3' has the closing variable. This opcode then swaps the | ||
1817 | control and the closing variables and marks the closing variable | ||
1818 | as to-be-closed. | ||
1819 | */ | ||
1811 | StkId ra = RA(i); | 1820 | StkId ra = RA(i); |
1812 | /* create to-be-closed upvalue (if needed) */ | 1821 | TValue temp; /* to swap control and closing variables */ |
1813 | halfProtect(luaF_newtbcupval(L, ra + 3)); | 1822 | setobj(L, &temp, s2v(ra + 3)); |
1814 | pc += GETARG_Bx(i); | 1823 | setobjs2s(L, ra + 3, ra + 2); |
1815 | i = *(pc++); /* go to next instruction */ | 1824 | setobj2s(L, ra + 2, &temp); |
1825 | /* create to-be-closed upvalue (if closing var. is not nil) */ | ||
1826 | halfProtect(luaF_newtbcupval(L, ra + 2)); | ||
1827 | pc += GETARG_Bx(i); /* go to end of the loop */ | ||
1828 | i = *(pc++); /* fetch next instruction */ | ||
1816 | lua_assert(GET_OPCODE(i) == OP_TFORCALL && ra == RA(i)); | 1829 | lua_assert(GET_OPCODE(i) == OP_TFORCALL && ra == RA(i)); |
1817 | goto l_tforcall; | 1830 | goto l_tforcall; |
1818 | } | 1831 | } |
1819 | vmcase(OP_TFORCALL) { | 1832 | vmcase(OP_TFORCALL) { |
1820 | l_tforcall: { | 1833 | l_tforcall: { |
1821 | StkId ra = RA(i); | ||
1822 | /* 'ra' has the iterator function, 'ra + 1' has the state, | 1834 | /* 'ra' has the iterator function, 'ra + 1' has the state, |
1823 | 'ra + 2' has the control variable, and 'ra + 3' has the | 1835 | 'ra + 2' has the closing variable, and 'ra + 3' has the control |
1824 | to-be-closed variable. The call will use the stack after | 1836 | variable. The call will use the stack starting at 'ra + 3', |
1825 | these values (starting at 'ra + 4') | 1837 | so that it preserves the first three values, and the first |
1838 | return will be the new value for the control variable. | ||
1826 | */ | 1839 | */ |
1827 | /* push function, state, and control variable */ | 1840 | StkId ra = RA(i); |
1828 | memcpy(ra + 4, ra, 3 * sizeof(*ra)); | 1841 | setobjs2s(L, ra + 5, ra + 3); /* copy the control variable */ |
1829 | L->top.p = ra + 4 + 3; | 1842 | setobjs2s(L, ra + 4, ra + 1); /* copy state */ |
1830 | ProtectNT(luaD_call(L, ra + 4, GETARG_C(i))); /* do the call */ | 1843 | setobjs2s(L, ra + 3, ra); /* copy function */ |
1844 | L->top.p = ra + 3 + 3; | ||
1845 | ProtectNT(luaD_call(L, ra + 3, GETARG_C(i))); /* do the call */ | ||
1831 | updatestack(ci); /* stack may have changed */ | 1846 | updatestack(ci); /* stack may have changed */ |
1832 | i = *(pc++); /* go to next instruction */ | 1847 | i = *(pc++); /* go to next instruction */ |
1833 | lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i)); | 1848 | lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i)); |
@@ -1836,10 +1851,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1836 | vmcase(OP_TFORLOOP) { | 1851 | vmcase(OP_TFORLOOP) { |
1837 | l_tforloop: { | 1852 | l_tforloop: { |
1838 | StkId ra = RA(i); | 1853 | StkId ra = RA(i); |
1839 | if (!ttisnil(s2v(ra + 4))) { /* continue loop? */ | 1854 | if (!ttisnil(s2v(ra + 3))) /* continue loop? */ |
1840 | setobjs2s(L, ra + 2, ra + 4); /* save control variable */ | ||
1841 | pc -= GETARG_Bx(i); /* jump back */ | 1855 | pc -= GETARG_Bx(i); /* jump back */ |
1842 | } | ||
1843 | vmbreak; | 1856 | vmbreak; |
1844 | }} | 1857 | }} |
1845 | vmcase(OP_SETLIST) { | 1858 | 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 |