aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2023-09-05 15:30:45 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2023-09-05 15:30:45 -0300
commit14e416355f83cf0a1b871eedec2c92b86dbe76d6 (patch)
tree620c7fa0b811d5f91d3d2f9b4879b289df6d137c
parentf33cda8d6eb1cac5b9042429e85f1096175c7ca5 (diff)
downloadlua-14e416355f83cf0a1b871eedec2c92b86dbe76d6.tar.gz
lua-14e416355f83cf0a1b871eedec2c92b86dbe76d6.tar.bz2
lua-14e416355f83cf0a1b871eedec2c92b86dbe76d6.zip
Added suport for Fixed Buffers
A fixed buffer keeps a binary chunk "forever", so that the program does not need to copy some of its parts when loading it.
Diffstat (limited to '')
-rw-r--r--lbaselib.c15
-rw-r--r--ldo.c13
-rw-r--r--lfunc.c6
-rw-r--r--lobject.h1
-rw-r--r--lstring.c2
-rw-r--r--ltests.c7
-rw-r--r--lundump.c42
-rw-r--r--lundump.h3
-rw-r--r--lzio.c36
-rw-r--r--lzio.h1
-rw-r--r--manual/manual.of17
-rw-r--r--testes/api.lua51
12 files changed, 160 insertions, 34 deletions
diff --git a/lbaselib.c b/lbaselib.c
index 1d60c9de..5a23c937 100644
--- a/lbaselib.c
+++ b/lbaselib.c
@@ -337,9 +337,20 @@ static int load_aux (lua_State *L, int status, int envidx) {
337} 337}
338 338
339 339
340static 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
340static int luaB_loadfile (lua_State *L) { 351static 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);
diff --git a/ldo.c b/ldo.c
index a0e00229..e9f91384 100644
--- a/ldo.c
+++ b/ldo.c
@@ -977,7 +977,7 @@ struct SParser { /* data to 'f_parser' */
977 977
978 978
979static void checkmode (lua_State *L, const char *mode, const char *x) { 979static 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) {
988static void f_parser (lua_State *L, void *ud) { 988static 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);
diff --git a/lfunc.c b/lfunc.c
index 9866a2d5..066409c0 100644
--- a/lfunc.c
+++ b/lfunc.c
@@ -265,10 +265,12 @@ Proto *luaF_newproto (lua_State *L) {
265 265
266 266
267void luaF_freeproto (lua_State *L, Proto *f) { 267void 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);
diff --git a/lobject.h b/lobject.h
index 9e7953e3..209a87fc 100644
--- a/lobject.h
+++ b/lobject.h
@@ -556,6 +556,7 @@ typedef struct AbsLineInfo {
556** Flags in Prototypes 556** Flags in Prototypes
557*/ 557*/
558#define PF_ISVARARG 1 558#define PF_ISVARARG 1
559#define PF_FIXED 2 /* prototype has parts in fixed memory */
559 560
560 561
561/* 562/*
diff --git a/lstring.c b/lstring.c
index 1032ad86..e921dd0f 100644
--- a/lstring.c
+++ b/lstring.c
@@ -207,8 +207,8 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
207 list = &tb->hash[lmod(h, tb->size)]; /* rehash with new size */ 207 list = &tb->hash[lmod(h, tb->size)]; /* rehash with new size */
208 } 208 }
209 ts = createstrobj(L, l, LUA_VSHRSTR, h); 209 ts = createstrobj(L, l, LUA_VSHRSTR, h);
210 memcpy(getshrstr(ts), str, l * sizeof(char));
211 ts->shrlen = cast_byte(l); 210 ts->shrlen = cast_byte(l);
211 memcpy(getshrstr(ts), str, l * sizeof(char));
212 ts->u.hnext = *list; 212 ts->u.hnext = *list;
213 *list = ts; 213 *list = ts;
214 tb->nuse++; 214 tb->nuse++;
diff --git a/ltests.c b/ltests.c
index e218778a..15d1a564 100644
--- a/ltests.c
+++ b/ltests.c
@@ -1513,8 +1513,11 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
1513 luaL_loadfile(L1, luaL_checkstring(L1, getnum)); 1513 luaL_loadfile(L1, luaL_checkstring(L1, getnum));
1514 } 1514 }
1515 else if EQ("loadstring") { 1515 else if EQ("loadstring") {
1516 const char *s = luaL_checkstring(L1, getnum); 1516 size_t slen;
1517 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);
1518 } 1521 }
1519 else if EQ("newmetatable") { 1522 else if EQ("newmetatable") {
1520 lua_pushboolean(L1, luaL_newmetatable(L1, getstring)); 1523 lua_pushboolean(L1, luaL_newmetatable(L1, getstring));
diff --git a/lundump.c b/lundump.c
index 07c42e62..100521a9 100644
--- a/lundump.c
+++ b/lundump.c
@@ -38,6 +38,7 @@ typedef struct {
38 Table *h; /* list for string reuse */ 38 Table *h; /* list for string reuse */
39 lu_mem offset; /* current position relative to beginning of dump */ 39 lu_mem offset; /* current position relative to beginning of dump */
40 lua_Integer nstr; /* number of strings in the list */ 40 lua_Integer nstr; /* number of strings in the list */
41 lu_byte fixed; /* dump is fixed in memory */
41} LoadState; 42} LoadState;
42 43
43 44
@@ -70,6 +71,16 @@ static void loadAlign (LoadState *S, int align) {
70} 71}
71 72
72 73
74#define getaddr(S,n,t) cast(t *, getaddr_(S,n,sizeof(t)))
75
76static 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;
81}
82
83
73#define loadVar(S,x) loadVector(S,&x,1) 84#define loadVar(S,x) loadVector(S,&x,1)
74 85
75 86
@@ -169,10 +180,16 @@ static TString *loadString (LoadState *S, Proto *p) {
169 180
170static void loadCode (LoadState *S, Proto *f) { 181static void loadCode (LoadState *S, Proto *f) {
171 int n = loadInt(S); 182 int n = loadInt(S);
172 f->code = luaM_newvectorchecked(S->L, n, Instruction);
173 f->sizecode = n;
174 loadAlign(S, sizeof(f->code[0])); 183 loadAlign(S, sizeof(f->code[0]));
175 loadVector(S, f->code, n); 184 if (S->fixed) {
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 }
176} 193}
177 194
178 195
@@ -254,9 +271,15 @@ static void loadUpvalues (LoadState *S, Proto *f) {
254static void loadDebug (LoadState *S, Proto *f) { 271static void loadDebug (LoadState *S, Proto *f) {
255 int i, n; 272 int i, n;
256 n = loadInt(S); 273 n = loadInt(S);
257 f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte); 274 if (S->fixed) {
258 f->sizelineinfo = n; 275 f->lineinfo = getaddr(S, n, ls_byte);
259 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 }
260 n = loadInt(S); 283 n = loadInt(S);
261 f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo); 284 f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo);
262 f->sizeabslineinfo = n; 285 f->sizeabslineinfo = n;
@@ -287,7 +310,9 @@ static void loadFunction (LoadState *S, Proto *f) {
287 f->linedefined = loadInt(S); 310 f->linedefined = loadInt(S);
288 f->lastlinedefined = loadInt(S); 311 f->lastlinedefined = loadInt(S);
289 f->numparams = loadByte(S); 312 f->numparams = loadByte(S);
290 f->flag = loadByte(S) & PF_ISVARARG; /* keep only the meaningful flags */ 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 */
291 f->maxstacksize = loadByte(S); 316 f->maxstacksize = loadByte(S);
292 loadCode(S, f); 317 loadCode(S, f);
293 loadConstants(S, f); 318 loadConstants(S, f);
@@ -335,7 +360,7 @@ static void checkHeader (LoadState *S) {
335/* 360/*
336** Load precompiled chunk. 361** Load precompiled chunk.
337*/ 362*/
338LClosure *luaU_undump (lua_State *L, ZIO *Z, const char *name) { 363LClosure *luaU_undump (lua_State *L, ZIO *Z, const char *name, int fixed) {
339 LoadState S; 364 LoadState S;
340 LClosure *cl; 365 LClosure *cl;
341 if (*name == '@' || *name == '=') 366 if (*name == '@' || *name == '=')
@@ -346,6 +371,7 @@ LClosure *luaU_undump (lua_State *L, ZIO *Z, const char *name) {
346 S.name = name; 371 S.name = name;
347 S.L = L; 372 S.L = L;
348 S.Z = Z; 373 S.Z = Z;
374 S.fixed = fixed;
349 S.offset = 1; /* fist byte was already read */ 375 S.offset = 1; /* fist byte was already read */
350 checkHeader(&S); 376 checkHeader(&S);
351 cl = luaF_newLclosure(L, loadByte(&S)); 377 cl = luaF_newLclosure(L, loadByte(&S));
diff --git a/lundump.h b/lundump.h
index bfabaa63..05ac7f85 100644
--- a/lundump.h
+++ b/lundump.h
@@ -26,7 +26,8 @@
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 */
29LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name); 29LUAI_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 */
32LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, 33LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w,
diff --git a/lzio.c b/lzio.c
index cd0a02d5..78f7ac83 100644
--- a/lzio.c
+++ b/lzio.c
@@ -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
49static 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
48size_t luaZ_read (ZIO *z, void *b, size_t n) { 62size_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
78const 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}
diff --git a/lzio.h b/lzio.h
index 38f397fd..55cc74ad 100644
--- a/lzio.h
+++ b/lzio.h
@@ -48,6 +48,7 @@ LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader,
48 void *data); 48 void *data);
49LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */ 49LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */
50 50
51LUAI_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 c16039b4..3eab69fa 100644
--- a/manual/manual.of
+++ b/manual/manual.of
@@ -2730,7 +2730,8 @@ For such errors, Lua does not call the @x{message handler}.
2730 2730
2731@item{@defid{LUA_ERRERR}| error while running the @x{message handler}.} 2731@item{@defid{LUA_ERRERR}| error while running the @x{message handler}.}
2732 2732
2733@item{@defid{LUA_ERRSYNTAX}| syntax error during precompilation.} 2733@item{@defid{LUA_ERRSYNTAX}| syntax error during precompilation
2734or format error in a binary chunk.}
2734 2735
2735@item{@defid{LUA_YIELD}| the thread (coroutine) yields.} 2736@item{@defid{LUA_YIELD}| the thread (coroutine) yields.}
2736 2737
@@ -3646,6 +3647,18 @@ and loads it accordingly (see program @idx{luac}).
3646The string @id{mode} works as in function @Lid{load}, 3647The string @id{mode} works as in function @Lid{load},
3647with the addition that 3648with the addition that
3648a @id{NULL} value is equivalent to the string @St{bt}. 3649a @id{NULL} value is equivalent to the string @St{bt}.
3650Moreover, it may have a @Char{B} instead of a @Char{b},
3651meaning a @emphx{fixed buffer} with the binary dump.
3652
3653A fixed buffer means that the address returned by the reader function
3654should contain the chunk until everything created by the chunk has
3655been collected.
3656(In general, a fixed buffer would keep the chunk
3657as its contents until the end of the program,
3658for instance with the chunk in ROM.)
3659Moreover, for a fixed buffer,
3660the reader function should return the entire chunk in the first read.
3661(As an example, @Lid{luaL_loadbufferx} does that.)
3649 3662
3650@id{lua_load} uses the stack internally, 3663@id{lua_load} uses the stack internally,
3651so the reader function must always leave the stack 3664so the reader function must always leave the stack
@@ -5688,6 +5701,8 @@ This function returns the same results as @Lid{lua_load}.
5688@id{name} is the chunk name, 5701@id{name} is the chunk name,
5689used for debug information and error messages. 5702used for debug information and error messages.
5690The string @id{mode} works as in the function @Lid{lua_load}. 5703The string @id{mode} works as in the function @Lid{lua_load}.
5704In particular, this function supports mode @Char{B} for
5705fixed buffers.
5691 5706
5692} 5707}
5693 5708
diff --git a/testes/api.lua b/testes/api.lua
index dece98f5..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'+'
459end 459end
460 460
461
462
461local lim = _soft and 500 or 12000 463local lim = _soft and 500 or 12000
462local prog = {"checkstack " .. (lim * 2 + 100) .. "msg", "newtable"} 464local prog = {"checkstack " .. (lim * 2 + 100) .. "msg", "newtable"}
463for i = 1,lim do 465for i = 1,lim do
@@ -481,10 +483,20 @@ for i = 1,lim do assert(t[i] == i*10); t[i] = undef end
481assert(next(t) == nil) 483assert(next(t) == nil)
482prog, g, t = nil 484prog, g, t = nil
483 485
486do -- 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
493end
494
495
484-- testing errors 496-- testing errors
485 497
486a = T.testC([[ 498a = 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))
500end 512end
501check3(":1:", T.testC("loadstring 2; return *", "x=")) 513check3(":1:", T.testC("loadstring 2 name t; return *", "x="))
502check3("%.", T.testC("loadfile 2; return *", ".")) 514check3("%.", T.testC("loadfile 2; return *", "."))
503check3("xxxx", T.testC("loadfile 2; return *", "xxxx")) 515check3("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))
510end 522end
511 523
524
525do
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
550end
551
552
512if not _soft then 553if 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")