diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2022-12-15 16:44:22 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2022-12-15 16:44:22 -0300 |
| commit | d70a0c91ad42275af1f6f1b6e37c604442b3f0d1 (patch) | |
| tree | 1507250574d5f9b34c32a0fade34fbeaecb7c5f9 | |
| parent | 3e6818ca87b8d7aa007e6992295956a92bb89de4 (diff) | |
| download | lua-d70a0c91ad42275af1f6f1b6e37c604442b3f0d1.tar.gz lua-d70a0c91ad42275af1f6f1b6e37c604442b3f0d1.tar.bz2 lua-d70a0c91ad42275af1f6f1b6e37c604442b3f0d1.zip | |
Dump/undump reuse strings
A repeated string in a dump is represented as an index to its first
occurence, instead of another copy of the string.
| -rw-r--r-- | lapi.c | 29 | ||||
| -rw-r--r-- | ldump.c | 37 | ||||
| -rw-r--r-- | lstrlib.c | 1 | ||||
| -rw-r--r-- | lundump.c | 20 | ||||
| -rw-r--r-- | lundump.h | 2 |
5 files changed, 77 insertions, 12 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 | } |
| @@ -14,8 +14,10 @@ | |||
| 14 | 14 | ||
| 15 | #include "lua.h" | 15 | #include "lua.h" |
| 16 | 16 | ||
| 17 | #include "lgc.h" | ||
| 17 | #include "lobject.h" | 18 | #include "lobject.h" |
| 18 | #include "lstate.h" | 19 | #include "lstate.h" |
| 20 | #include "ltable.h" | ||
| 19 | #include "lundump.h" | 21 | #include "lundump.h" |
| 20 | 22 | ||
| 21 | 23 | ||
| @@ -25,6 +27,8 @@ typedef struct { | |||
| 25 | void *data; | 27 | void *data; |
| 26 | int strip; | 28 | int strip; |
| 27 | int status; | 29 | int status; |
| 30 | Table *h; /* table to track saved strings */ | ||
| 31 | lua_Integer nstr; /* counter to number saved strings */ | ||
| 28 | } DumpState; | 32 | } DumpState; |
| 29 | 33 | ||
| 30 | 34 | ||
| @@ -85,14 +89,33 @@ static void dumpInteger (DumpState *D, lua_Integer x) { | |||
| 85 | } | 89 | } |
| 86 | 90 | ||
| 87 | 91 | ||
| 88 | static void dumpString (DumpState *D, const TString *s) { | 92 | /* |
| 93 | ** Dump a String. First dump its "size": size==0 means NULL; | ||
| 94 | ** size==1 is followed by an index and means "reuse saved string with | ||
| 95 | ** that index"; size>=2 is followed by the string contents with real | ||
| 96 | ** size==size-2 and means that string, which will be saved with | ||
| 97 | ** the next available index. | ||
| 98 | */ | ||
| 99 | static void dumpString (DumpState *D, TString *s) { | ||
| 89 | if (s == NULL) | 100 | if (s == NULL) |
| 90 | dumpSize(D, 0); | 101 | dumpSize(D, 0); |
| 91 | else { | 102 | else { |
| 92 | size_t size = tsslen(s); | 103 | const TValue *idx = luaH_getstr(D->h, s); |
| 93 | const char *str = getstr(s); | 104 | if (ttisinteger(idx)) { /* string already saved? */ |
| 94 | dumpSize(D, size + 1); | 105 | dumpSize(D, 1); /* reuse a saved string */ |
| 95 | dumpVector(D, str, size); | 106 | dumpInt(D, ivalue(idx)); /* index of saved string */ |
| 107 | } | ||
| 108 | else { /* must write and save the string */ | ||
| 109 | TValue key, value; /* to save the string in the hash */ | ||
| 110 | size_t size = tsslen(s); | ||
| 111 | dumpSize(D, size + 2); | ||
| 112 | dumpVector(D, getstr(s), size); | ||
| 113 | D->nstr++; /* one more saved string */ | ||
| 114 | setsvalue(D->L, &key, s); /* the string is the key */ | ||
| 115 | setivalue(&value, D->nstr); /* its index is the value */ | ||
| 116 | luaH_finishset(D->L, D->h, &key, idx, &value); /* h[s] = nstr */ | ||
| 117 | /* integer value does not need barrier */ | ||
| 118 | } | ||
| 96 | } | 119 | } |
| 97 | } | 120 | } |
| 98 | 121 | ||
| @@ -211,13 +234,15 @@ static void dumpHeader (DumpState *D) { | |||
| 211 | ** dump Lua function as precompiled chunk | 234 | ** dump Lua function as precompiled chunk |
| 212 | */ | 235 | */ |
| 213 | int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data, | 236 | int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data, |
| 214 | int strip) { | 237 | int strip, Table *h) { |
| 215 | DumpState D; | 238 | DumpState D; |
| 216 | D.L = L; | 239 | D.L = L; |
| 217 | D.writer = w; | 240 | D.writer = w; |
| 218 | D.data = data; | 241 | D.data = data; |
| 219 | D.strip = strip; | 242 | D.strip = strip; |
| 220 | D.status = 0; | 243 | D.status = 0; |
| 244 | D.h = h; | ||
| 245 | D.nstr = 0; | ||
| 221 | dumpHeader(&D); | 246 | dumpHeader(&D); |
| 222 | dumpByte(&D, f->sizeupvalues); | 247 | dumpByte(&D, f->sizeupvalues); |
| 223 | dumpFunction(&D, f, NULL); | 248 | dumpFunction(&D, f, NULL); |
| @@ -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 | ||
| @@ -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,8 @@ 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 | lua_Integer nstr; /* number of strings in the list */ | ||
| 37 | } LoadState; | 40 | } LoadState; |
| 38 | 41 | ||
| 39 | 42 | ||
| @@ -110,10 +113,16 @@ static lua_Integer loadInteger (LoadState *S) { | |||
| 110 | static TString *loadStringN (LoadState *S, Proto *p) { | 113 | static TString *loadStringN (LoadState *S, Proto *p) { |
| 111 | lua_State *L = S->L; | 114 | lua_State *L = S->L; |
| 112 | TString *ts; | 115 | TString *ts; |
| 116 | TValue sv; | ||
| 113 | size_t size = loadSize(S); | 117 | size_t size = loadSize(S); |
| 114 | if (size == 0) /* no string? */ | 118 | if (size == 0) /* no string? */ |
| 115 | return NULL; | 119 | return NULL; |
| 116 | else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */ | 120 | else if (size == 1) { /* previously saved string? */ |
| 121 | int idx = loadInt(S); /* get its index */ | ||
| 122 | const TValue *stv = luaH_getint(S->h, idx); | ||
| 123 | return tsvalue(stv); | ||
| 124 | } | ||
| 125 | else if (size -= 2, size <= LUAI_MAXSHORTLEN) { /* short string? */ | ||
| 117 | char buff[LUAI_MAXSHORTLEN]; | 126 | char buff[LUAI_MAXSHORTLEN]; |
| 118 | loadVector(S, buff, size); /* load string into buffer */ | 127 | loadVector(S, buff, size); /* load string into buffer */ |
| 119 | ts = luaS_newlstr(L, buff, size); /* create string */ | 128 | ts = luaS_newlstr(L, buff, size); /* create string */ |
| @@ -126,6 +135,10 @@ static TString *loadStringN (LoadState *S, Proto *p) { | |||
| 126 | L->top.p--; /* pop string */ | 135 | L->top.p--; /* pop string */ |
| 127 | } | 136 | } |
| 128 | luaC_objbarrier(L, p, ts); | 137 | luaC_objbarrier(L, p, ts); |
| 138 | S->nstr++; /* add string to list of saved strings */ | ||
| 139 | setsvalue(L, &sv, ts); | ||
| 140 | luaH_setint(L, S->h, S->nstr, &sv); | ||
| 141 | luaC_objbarrierback(L, obj2gco(S->h), ts); | ||
| 129 | return ts; | 142 | return ts; |
| 130 | } | 143 | } |
| 131 | 144 | ||
| @@ -323,11 +336,16 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) { | |||
| 323 | cl = luaF_newLclosure(L, loadByte(&S)); | 336 | cl = luaF_newLclosure(L, loadByte(&S)); |
| 324 | setclLvalue2s(L, L->top.p, cl); | 337 | setclLvalue2s(L, L->top.p, cl); |
| 325 | luaD_inctop(L); | 338 | luaD_inctop(L); |
| 339 | S.h = luaH_new(L); /* create list of saved strings */ | ||
| 340 | S.nstr = 0; | ||
| 341 | sethvalue2s(L, L->top.p, S.h); /* anchor it */ | ||
| 342 | luaD_inctop(L); | ||
| 326 | cl->p = luaF_newproto(L); | 343 | cl->p = luaF_newproto(L); |
| 327 | luaC_objbarrier(L, cl, cl->p); | 344 | luaC_objbarrier(L, cl, cl->p); |
| 328 | loadFunction(&S, cl->p, NULL); | 345 | loadFunction(&S, cl->p, NULL); |
| 329 | lua_assert(cl->nupvalues == cl->p->sizeupvalues); | 346 | lua_assert(cl->nupvalues == cl->p->sizeupvalues); |
| 330 | luai_verifycode(L, cl->p); | 347 | luai_verifycode(L, cl->p); |
| 348 | L->top.p--; /* pop table */ | ||
| 331 | return cl; | 349 | return cl; |
| 332 | } | 350 | } |
| 333 | 351 | ||
| @@ -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); | 34 | void* data, int strip, Table *h); |
| 35 | 35 | ||
| 36 | #endif | 36 | #endif |
