diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2023-12-14 11:41:57 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2023-12-14 11:41:57 -0300 |
| commit | 4eda1acafa1a69224b2d4f786cf1ec8f7a4d9ac5 (patch) | |
| tree | 474a56c1cbb1b109f945cb3765c6ebc918d35b37 | |
| parent | ad73b332240ef5b9bab1517517f63a1425dc7545 (diff) | |
| download | lua-4eda1acafa1a69224b2d4f786cf1ec8f7a4d9ac5.tar.gz lua-4eda1acafa1a69224b2d4f786cf1ec8f7a4d9ac5.tar.bz2 lua-4eda1acafa1a69224b2d4f786cf1ec8f7a4d9ac5.zip | |
Cleaner protocol between 'lua_dump' and writer function
'lua_dump' signals to the writer function the end of a dump, so that
is has more freedom when using the stack.
| -rw-r--r-- | lapi.c | 32 | ||||
| -rw-r--r-- | ldump.c | 30 | ||||
| -rw-r--r-- | lstrlib.c | 19 | ||||
| -rw-r--r-- | lundump.c | 8 | ||||
| -rw-r--r-- | lundump.h | 2 | ||||
| -rw-r--r-- | manual/manual.of | 21 |
6 files changed, 66 insertions, 46 deletions
| @@ -1116,36 +1116,18 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, | |||
| 1116 | 1116 | ||
| 1117 | 1117 | ||
| 1118 | /* | 1118 | /* |
| 1119 | ** Dump a function, calling 'writer' to write its parts. Because the | 1119 | ** Dump a Lua function, calling 'writer' to write its parts. Ensure |
| 1120 | ** writer can use the stack in unkown ways, this function should not | 1120 | ** the stack returns with its original size. |
| 1121 | ** push things on the stack, but it must anchor an auxiliary table | ||
| 1122 | ** used by 'luaU_dump'. To do so, it creates the table, anchors the | ||
| 1123 | ** function that is on the stack in the table, and substitutes the | ||
| 1124 | ** table for the function in the stack. | ||
| 1125 | */ | 1121 | */ |
| 1126 | |||
| 1127 | LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) { | 1122 | LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) { |
| 1128 | int status; | 1123 | int status; |
| 1129 | StkId fstk; /* pointer to function */ | 1124 | ptrdiff_t otop = savestack(L, L->top.p); /* original top */ |
| 1130 | TValue *o; | 1125 | TValue *f = s2v(L->top.p - 1); /* function to be dumped */ |
| 1131 | lua_lock(L); | 1126 | lua_lock(L); |
| 1132 | api_checknelems(L, 1); | 1127 | api_checknelems(L, 1); |
| 1133 | fstk = L->top.p - 1; | 1128 | api_check(L, isLfunction(f), "Lua function expected"); |
| 1134 | o = s2v(fstk); | 1129 | status = luaU_dump(L, clLvalue(f)->p, writer, data, strip); |
| 1135 | if (!isLfunction(o)) | 1130 | L->top.p = restorestack(L, otop); /* restore top */ |
| 1136 | status = 1; | ||
| 1137 | else { | ||
| 1138 | LClosure *f = clLvalue(o); | ||
| 1139 | ptrdiff_t fidx = savestack(L, fstk); /* function index */ | ||
| 1140 | Table *h = luaH_new(L); /* auxiliary table used by 'luaU_dump' */ | ||
| 1141 | sethvalue2s(L, L->top.p, h); /* anchor it (luaH_set may call GC) */ | ||
| 1142 | L->top.p++; /* (assume extra slot) */ | ||
| 1143 | luaH_set(L, h, o, o); /* anchor function into table */ | ||
| 1144 | setobjs2s(L, fstk, L->top.p - 1); /* move table over function */ | ||
| 1145 | L->top.p--; /* stack back to initial size */ | ||
| 1146 | status = luaU_dump(L, f->p, writer, data, strip, h); | ||
| 1147 | setclLvalue2s(L, restorestack(L, fidx), f); /* put function back */ | ||
| 1148 | } | ||
| 1149 | lua_unlock(L); | 1131 | lua_unlock(L); |
| 1150 | return status; | 1132 | return status; |
| 1151 | } | 1133 | } |
| @@ -43,8 +43,13 @@ typedef struct { | |||
| 43 | #define dumpLiteral(D, s) dumpBlock(D,s,sizeof(s) - sizeof(char)) | 43 | #define dumpLiteral(D, s) dumpBlock(D,s,sizeof(s) - sizeof(char)) |
| 44 | 44 | ||
| 45 | 45 | ||
| 46 | /* | ||
| 47 | ** Dump the block of memory pointed by 'b' with given 'size'. | ||
| 48 | ** 'b' should not be NULL, except for the last call signaling the end | ||
| 49 | ** of the dump. | ||
| 50 | */ | ||
| 46 | static void dumpBlock (DumpState *D, const void *b, size_t size) { | 51 | static void dumpBlock (DumpState *D, const void *b, size_t size) { |
| 47 | if (D->status == 0 && size > 0) { | 52 | if (D->status == 0) { /* do not write anything after an error */ |
| 48 | lua_unlock(D->L); | 53 | lua_unlock(D->L); |
| 49 | D->status = (*D->writer)(D->L, b, size, D->data); | 54 | D->status = (*D->writer)(D->L, b, size, D->data); |
| 50 | lua_lock(D->L); | 55 | lua_lock(D->L); |
| @@ -53,13 +58,18 @@ static void dumpBlock (DumpState *D, const void *b, size_t size) { | |||
| 53 | } | 58 | } |
| 54 | 59 | ||
| 55 | 60 | ||
| 61 | /* | ||
| 62 | ** Dump enough zeros to ensure that current position is a multiple of | ||
| 63 | ** 'align'. | ||
| 64 | */ | ||
| 56 | static void dumpAlign (DumpState *D, int align) { | 65 | static void dumpAlign (DumpState *D, int align) { |
| 57 | int padding = align - (D->offset % align); | 66 | int padding = align - (D->offset % align); |
| 58 | if (padding < align) { /* apd == align means no padding */ | 67 | if (padding < align) { /* padding == align means no padding */ |
| 59 | static lua_Integer paddingContent = 0; | 68 | static lua_Integer paddingContent = 0; |
| 69 | lua_assert(cast_uint(align) <= sizeof(lua_Integer)); | ||
| 60 | dumpBlock(D, &paddingContent, padding); | 70 | dumpBlock(D, &paddingContent, padding); |
| 61 | lua_assert(D->offset % align == 0); | ||
| 62 | } | 71 | } |
| 72 | lua_assert(D->offset % align == 0); | ||
| 63 | } | 73 | } |
| 64 | 74 | ||
| 65 | 75 | ||
| @@ -91,6 +101,7 @@ static void dumpSize (DumpState *D, size_t x) { | |||
| 91 | 101 | ||
| 92 | 102 | ||
| 93 | static void dumpInt (DumpState *D, int x) { | 103 | static void dumpInt (DumpState *D, int x) { |
| 104 | lua_assert(x >= 0); | ||
| 94 | dumpSize(D, x); | 105 | dumpSize(D, x); |
| 95 | } | 106 | } |
| 96 | 107 | ||
| @@ -140,6 +151,7 @@ static void dumpString (DumpState *D, TString *ts) { | |||
| 140 | static void dumpCode (DumpState *D, const Proto *f) { | 151 | static void dumpCode (DumpState *D, const Proto *f) { |
| 141 | dumpInt(D, f->sizecode); | 152 | dumpInt(D, f->sizecode); |
| 142 | dumpAlign(D, sizeof(f->code[0])); | 153 | dumpAlign(D, sizeof(f->code[0])); |
| 154 | lua_assert(f->code != NULL); | ||
| 143 | dumpVector(D, f->code, f->sizecode); | 155 | dumpVector(D, f->code, f->sizecode); |
| 144 | } | 156 | } |
| 145 | 157 | ||
| @@ -196,7 +208,8 @@ static void dumpDebug (DumpState *D, const Proto *f) { | |||
| 196 | int i, n; | 208 | int i, n; |
| 197 | n = (D->strip) ? 0 : f->sizelineinfo; | 209 | n = (D->strip) ? 0 : f->sizelineinfo; |
| 198 | dumpInt(D, n); | 210 | dumpInt(D, n); |
| 199 | dumpVector(D, f->lineinfo, n); | 211 | if (f->lineinfo != NULL) |
| 212 | dumpVector(D, f->lineinfo, n); | ||
| 200 | n = (D->strip) ? 0 : f->sizeabslineinfo; | 213 | n = (D->strip) ? 0 : f->sizeabslineinfo; |
| 201 | dumpInt(D, n); | 214 | dumpInt(D, n); |
| 202 | for (i = 0; i < n; i++) { | 215 | for (i = 0; i < n; i++) { |
| @@ -248,20 +261,23 @@ static void dumpHeader (DumpState *D) { | |||
| 248 | /* | 261 | /* |
| 249 | ** dump Lua function as precompiled chunk | 262 | ** dump Lua function as precompiled chunk |
| 250 | */ | 263 | */ |
| 251 | int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data, | 264 | int luaU_dump (lua_State *L, const Proto *f, lua_Writer w, void *data, |
| 252 | int strip, Table *h) { | 265 | int strip) { |
| 253 | DumpState D; | 266 | DumpState D; |
| 267 | D.h = luaH_new(L); /* aux. table to keep strings already dumped */ | ||
| 268 | sethvalue2s(L, L->top.p, D.h); /* anchor it */ | ||
| 269 | L->top.p++; | ||
| 254 | D.L = L; | 270 | D.L = L; |
| 255 | D.writer = w; | 271 | D.writer = w; |
| 256 | D.offset = 0; | 272 | D.offset = 0; |
| 257 | D.data = data; | 273 | D.data = data; |
| 258 | D.strip = strip; | 274 | D.strip = strip; |
| 259 | D.status = 0; | 275 | D.status = 0; |
| 260 | D.h = h; | ||
| 261 | D.nstr = 0; | 276 | D.nstr = 0; |
| 262 | dumpHeader(&D); | 277 | dumpHeader(&D); |
| 263 | dumpByte(&D, f->sizeupvalues); | 278 | dumpByte(&D, f->sizeupvalues); |
| 264 | dumpFunction(&D, f); | 279 | dumpFunction(&D, f); |
| 280 | dumpBlock(&D, NULL, 0); /* signal end of dump */ | ||
| 265 | return D.status; | 281 | return D.status; |
| 266 | } | 282 | } |
| 267 | 283 | ||
| @@ -225,7 +225,12 @@ static int writer (lua_State *L, const void *b, size_t size, void *ud) { | |||
| 225 | state->init = 1; | 225 | state->init = 1; |
| 226 | luaL_buffinit(L, &state->B); | 226 | luaL_buffinit(L, &state->B); |
| 227 | } | 227 | } |
| 228 | luaL_addlstring(&state->B, (const char *)b, size); | 228 | if (b == NULL) { /* finishing dump? */ |
| 229 | luaL_pushresult(&state->B); /* push result */ | ||
| 230 | lua_replace(L, 1); /* move it to reserved slot */ | ||
| 231 | } | ||
| 232 | else | ||
| 233 | luaL_addlstring(&state->B, (const char *)b, size); | ||
| 229 | return 0; | 234 | return 0; |
| 230 | } | 235 | } |
| 231 | 236 | ||
| @@ -233,13 +238,13 @@ static int writer (lua_State *L, const void *b, size_t size, void *ud) { | |||
| 233 | static int str_dump (lua_State *L) { | 238 | static int str_dump (lua_State *L) { |
| 234 | struct str_Writer state; | 239 | struct str_Writer state; |
| 235 | int strip = lua_toboolean(L, 2); | 240 | int strip = lua_toboolean(L, 2); |
| 236 | luaL_checktype(L, 1, LUA_TFUNCTION); | 241 | luaL_argcheck(L, lua_type(L, 1) == LUA_TFUNCTION && !lua_iscfunction(L, 1), |
| 237 | lua_settop(L, 1); /* ensure function is on the top of the stack */ | 242 | 1, "Lua function expected"); |
| 243 | /* ensure function is on the top of the stack and vacate slot 1 */ | ||
| 244 | lua_pushvalue(L, 1); | ||
| 238 | state.init = 0; | 245 | state.init = 0; |
| 239 | if (l_unlikely(lua_dump(L, writer, &state, strip) != 0)) | 246 | lua_dump(L, writer, &state, strip); |
| 240 | return luaL_error(L, "unable to dump given function"); | 247 | lua_settop(L, 1); /* leave final result on top */ |
| 241 | luaL_pushresult(&state.B); | ||
| 242 | lua_assert(lua_isfunction(L, 1)); /* lua_dump kept that value */ | ||
| 243 | return 1; | 248 | return 1; |
| 244 | } | 249 | } |
| 245 | 250 | ||
| @@ -152,7 +152,7 @@ static void loadString (LoadState *S, Proto *p, TString **sl) { | |||
| 152 | luaH_getint(S->h, idx, &stv); | 152 | luaH_getint(S->h, idx, &stv); |
| 153 | *sl = ts = tsvalue(&stv); | 153 | *sl = ts = tsvalue(&stv); |
| 154 | luaC_objbarrier(L, p, ts); | 154 | luaC_objbarrier(L, p, ts); |
| 155 | return; | 155 | return; /* do not save it again */ |
| 156 | } | 156 | } |
| 157 | else if ((size -= 2) <= LUAI_MAXSHORTLEN) { /* short string? */ | 157 | else if ((size -= 2) <= LUAI_MAXSHORTLEN) { /* short string? */ |
| 158 | char buff[LUAI_MAXSHORTLEN + 1]; /* extra space for '\0' */ | 158 | char buff[LUAI_MAXSHORTLEN + 1]; /* extra space for '\0' */ |
| @@ -168,10 +168,10 @@ static void loadString (LoadState *S, Proto *p, TString **sl) { | |||
| 168 | else { /* create internal copy */ | 168 | else { /* create internal copy */ |
| 169 | *sl = ts = luaS_createlngstrobj(L, size); /* create string */ | 169 | *sl = ts = luaS_createlngstrobj(L, size); /* create string */ |
| 170 | luaC_objbarrier(L, p, ts); | 170 | luaC_objbarrier(L, p, ts); |
| 171 | loadVector(S, getlngstr(ts), size); /* load directly in final place */ | 171 | loadVector(S, getlngstr(ts), size + 1); /* load directly in final place */ |
| 172 | loadByte(S); /* skip ending '\0' */ | ||
| 173 | } | 172 | } |
| 174 | S->nstr++; /* add string to list of saved strings */ | 173 | /* add string to list of saved strings */ |
| 174 | S->nstr++; | ||
| 175 | setsvalue(L, &sv, ts); | 175 | setsvalue(L, &sv, ts); |
| 176 | luaH_setint(L, S->h, S->nstr, &sv); | 176 | luaH_setint(L, S->h, S->nstr, &sv); |
| 177 | luaC_objbarrierback(L, obj2gco(S->h), ts); | 177 | luaC_objbarrierback(L, obj2gco(S->h), ts); |
| @@ -31,6 +31,6 @@ LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name, | |||
| 31 | 31 | ||
| 32 | /* dump one chunk; from ldump.c */ | 32 | /* dump one chunk; from ldump.c */ |
| 33 | 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, |
| 34 | void* data, int strip, Table *h); | 34 | void* data, int strip); |
| 35 | 35 | ||
| 36 | #endif | 36 | #endif |
diff --git a/manual/manual.of b/manual/manual.of index 8607e57d..ef1bdfd2 100644 --- a/manual/manual.of +++ b/manual/manual.of | |||
| @@ -3266,6 +3266,13 @@ As it produces parts of the chunk, | |||
| 3266 | with the given @id{data} | 3266 | with the given @id{data} |
| 3267 | to write them. | 3267 | to write them. |
| 3268 | 3268 | ||
| 3269 | The function @Lid{lua_dump} fully preserves the Lua stack | ||
| 3270 | through the calls to the writer function, | ||
| 3271 | except that it may push some values for internal use | ||
| 3272 | before the first call, | ||
| 3273 | and it restores the stack size to its original size | ||
| 3274 | after the last call. | ||
| 3275 | |||
| 3269 | If @id{strip} is true, | 3276 | If @id{strip} is true, |
| 3270 | the binary representation may not include all debug information | 3277 | the binary representation may not include all debug information |
| 3271 | about the function, | 3278 | about the function, |
| @@ -3275,8 +3282,6 @@ The value returned is the error code returned by the last | |||
| 3275 | call to the writer; | 3282 | call to the writer; |
| 3276 | @N{0 means} no errors. | 3283 | @N{0 means} no errors. |
| 3277 | 3284 | ||
| 3278 | This function does not pop the Lua function from the stack. | ||
| 3279 | |||
| 3280 | } | 3285 | } |
| 3281 | 3286 | ||
| 3282 | @APIEntry{int lua_error (lua_State *L);| | 3287 | @APIEntry{int lua_error (lua_State *L);| |
| @@ -4688,6 +4693,10 @@ passing along the buffer to be written (@id{p}), | |||
| 4688 | its size (@id{sz}), | 4693 | its size (@id{sz}), |
| 4689 | and the @id{ud} parameter supplied to @Lid{lua_dump}. | 4694 | and the @id{ud} parameter supplied to @Lid{lua_dump}. |
| 4690 | 4695 | ||
| 4696 | After @Lid{lua_dump} writes its last piece, | ||
| 4697 | it will signal that by calling the writer function one more time, | ||
| 4698 | with a @id{NULL} buffer (and size 0). | ||
| 4699 | |||
| 4691 | The writer returns an error code: | 4700 | The writer returns an error code: |
| 4692 | @N{0 means} no errors; | 4701 | @N{0 means} no errors; |
| 4693 | any other value means an error and stops @Lid{lua_dump} from | 4702 | any other value means an error and stops @Lid{lua_dump} from |
| @@ -9260,6 +9269,14 @@ it is equivalent to @Lid{lua_closethread} with | |||
| 9260 | } | 9269 | } |
| 9261 | 9270 | ||
| 9262 | @item{ | 9271 | @item{ |
| 9272 | The function @Lid{lua_dump} changed the way it keeps the stack | ||
| 9273 | through the calls to the writer function. | ||
| 9274 | (That was not specified in previous versions.) | ||
| 9275 | Also, it calls the writer function one extra time, | ||
| 9276 | to signal the end of the dump. | ||
| 9277 | } | ||
| 9278 | |||
| 9279 | @item{ | ||
| 9263 | There were several changes in the parameters | 9280 | There were several changes in the parameters |
| 9264 | for the options @Lid{LUA_GCINC} and @Lid{LUA_GCGEN} | 9281 | for the options @Lid{LUA_GCINC} and @Lid{LUA_GCGEN} |
| 9265 | of the function @Lid{lua_gc}. | 9282 | of the function @Lid{lua_gc}. |
