ldump.c (7179B)
1 /* 2 ** $Id: ldump.c $ 3 ** save precompiled Lua chunks 4 ** See Copyright Notice in lua.h 5 */ 6 7 #define ldump_c 8 #define LUA_CORE 9 10 #include "lprefix.h" 11 12 13 #include <limits.h> 14 #include <stddef.h> 15 16 #include "lua.h" 17 18 #include "lapi.h" 19 #include "lgc.h" 20 #include "lobject.h" 21 #include "lstate.h" 22 #include "ltable.h" 23 #include "lundump.h" 24 25 26 typedef struct { 27 lua_State *L; 28 lua_Writer writer; 29 void *data; 30 size_t offset; /* current position relative to beginning of dump */ 31 int strip; 32 int status; 33 Table *h; /* table to track saved strings */ 34 lua_Integer nstr; /* counter for counting saved strings */ 35 } DumpState; 36 37 38 /* 39 ** All high-level dumps go through dumpVector; you can change it to 40 ** change the endianness of the result 41 */ 42 #define dumpVector(D,v,n) dumpBlock(D,v,(n)*sizeof((v)[0])) 43 44 #define dumpLiteral(D, s) dumpBlock(D,s,sizeof(s) - sizeof(char)) 45 46 47 /* 48 ** Dump the block of memory pointed by 'b' with given 'size'. 49 ** 'b' should not be NULL, except for the last call signaling the end 50 ** of the dump. 51 */ 52 static void dumpBlock (DumpState *D, const void *b, size_t size) { 53 if (D->status == 0) { /* do not write anything after an error */ 54 lua_unlock(D->L); 55 D->status = (*D->writer)(D->L, b, size, D->data); 56 lua_lock(D->L); 57 D->offset += size; 58 } 59 } 60 61 62 /* 63 ** Dump enough zeros to ensure that current position is a multiple of 64 ** 'align'. 65 */ 66 static void dumpAlign (DumpState *D, unsigned align) { 67 unsigned padding = align - cast_uint(D->offset % align); 68 if (padding < align) { /* padding == align means no padding */ 69 static lua_Integer paddingContent = 0; 70 lua_assert(align <= sizeof(lua_Integer)); 71 dumpBlock(D, &paddingContent, padding); 72 } 73 lua_assert(D->offset % align == 0); 74 } 75 76 77 #define dumpVar(D,x) dumpVector(D,&x,1) 78 79 80 static void dumpByte (DumpState *D, int y) { 81 lu_byte x = (lu_byte)y; 82 dumpVar(D, x); 83 } 84 85 86 /* 87 ** size for 'dumpVarint' buffer: each byte can store up to 7 bits. 88 ** (The "+6" rounds up the division.) 89 */ 90 #define DIBS ((sizeof(size_t) * CHAR_BIT + 6) / 7) 91 92 /* 93 ** Dumps an unsigned integer using the MSB Varint encoding 94 */ 95 static void dumpVarint (DumpState *D, size_t x) { 96 lu_byte buff[DIBS]; 97 unsigned n = 1; 98 buff[DIBS - 1] = x & 0x7f; /* fill least-significant byte */ 99 while ((x >>= 7) != 0) /* fill other bytes in reverse order */ 100 buff[DIBS - (++n)] = cast_byte((x & 0x7f) | 0x80); 101 dumpVector(D, buff + DIBS - n, n); 102 } 103 104 105 static void dumpSize (DumpState *D, size_t sz) { 106 dumpVarint(D, sz); 107 } 108 109 static void dumpInt (DumpState *D, int x) { 110 lua_assert(x >= 0); 111 dumpVarint(D, cast(size_t, x)); 112 } 113 114 115 static void dumpNumber (DumpState *D, lua_Number x) { 116 dumpVar(D, x); 117 } 118 119 120 static void dumpInteger (DumpState *D, lua_Integer x) { 121 dumpVar(D, x); 122 } 123 124 125 /* 126 ** Dump a String. First dump its "size": size==0 means NULL; 127 ** size==1 is followed by an index and means "reuse saved string with 128 ** that index"; size>=2 is followed by the string contents with real 129 ** size==size-2 and means that string, which will be saved with 130 ** the next available index. 131 */ 132 static void dumpString (DumpState *D, TString *ts) { 133 if (ts == NULL) 134 dumpSize(D, 0); 135 else { 136 TValue idx; 137 int tag = luaH_getstr(D->h, ts, &idx); 138 if (!tagisempty(tag)) { /* string already saved? */ 139 dumpSize(D, 1); /* reuse a saved string */ 140 dumpSize(D, cast_sizet(ivalue(&idx))); /* index of saved string */ 141 } 142 else { /* must write and save the string */ 143 TValue key, value; /* to save the string in the hash */ 144 size_t size; 145 const char *s = getlstr(ts, size); 146 dumpSize(D, size + 2); 147 dumpVector(D, s, size + 1); /* include ending '\0' */ 148 D->nstr++; /* one more saved string */ 149 setsvalue(D->L, &key, ts); /* the string is the key */ 150 setivalue(&value, D->nstr); /* its index is the value */ 151 luaH_set(D->L, D->h, &key, &value); /* h[ts] = nstr */ 152 /* integer value does not need barrier */ 153 } 154 } 155 } 156 157 158 static void dumpCode (DumpState *D, const Proto *f) { 159 dumpInt(D, f->sizecode); 160 dumpAlign(D, sizeof(f->code[0])); 161 lua_assert(f->code != NULL); 162 dumpVector(D, f->code, cast_uint(f->sizecode)); 163 } 164 165 166 static void dumpFunction (DumpState *D, const Proto *f); 167 168 static void dumpConstants (DumpState *D, const Proto *f) { 169 int i; 170 int n = f->sizek; 171 dumpInt(D, n); 172 for (i = 0; i < n; i++) { 173 const TValue *o = &f->k[i]; 174 int tt = ttypetag(o); 175 dumpByte(D, tt); 176 switch (tt) { 177 case LUA_VNUMFLT: 178 dumpNumber(D, fltvalue(o)); 179 break; 180 case LUA_VNUMINT: 181 dumpInteger(D, ivalue(o)); 182 break; 183 case LUA_VSHRSTR: 184 case LUA_VLNGSTR: 185 dumpString(D, tsvalue(o)); 186 break; 187 default: 188 lua_assert(tt == LUA_VNIL || tt == LUA_VFALSE || tt == LUA_VTRUE); 189 } 190 } 191 } 192 193 194 static void dumpProtos (DumpState *D, const Proto *f) { 195 int i; 196 int n = f->sizep; 197 dumpInt(D, n); 198 for (i = 0; i < n; i++) 199 dumpFunction(D, f->p[i]); 200 } 201 202 203 static void dumpUpvalues (DumpState *D, const Proto *f) { 204 int i, n = f->sizeupvalues; 205 dumpInt(D, n); 206 for (i = 0; i < n; i++) { 207 dumpByte(D, f->upvalues[i].instack); 208 dumpByte(D, f->upvalues[i].idx); 209 dumpByte(D, f->upvalues[i].kind); 210 } 211 } 212 213 214 static void dumpDebug (DumpState *D, const Proto *f) { 215 int i, n; 216 n = (D->strip) ? 0 : f->sizelineinfo; 217 dumpInt(D, n); 218 if (f->lineinfo != NULL) 219 dumpVector(D, f->lineinfo, cast_uint(n)); 220 n = (D->strip) ? 0 : f->sizeabslineinfo; 221 dumpInt(D, n); 222 if (n > 0) { 223 /* 'abslineinfo' is an array of structures of int's */ 224 dumpAlign(D, sizeof(int)); 225 dumpVector(D, f->abslineinfo, cast_uint(n)); 226 } 227 n = (D->strip) ? 0 : f->sizelocvars; 228 dumpInt(D, n); 229 for (i = 0; i < n; i++) { 230 dumpString(D, f->locvars[i].varname); 231 dumpInt(D, f->locvars[i].startpc); 232 dumpInt(D, f->locvars[i].endpc); 233 } 234 n = (D->strip) ? 0 : f->sizeupvalues; 235 dumpInt(D, n); 236 for (i = 0; i < n; i++) 237 dumpString(D, f->upvalues[i].name); 238 } 239 240 241 static void dumpFunction (DumpState *D, const Proto *f) { 242 dumpInt(D, f->linedefined); 243 dumpInt(D, f->lastlinedefined); 244 dumpByte(D, f->numparams); 245 dumpByte(D, f->flag); 246 dumpByte(D, f->maxstacksize); 247 dumpCode(D, f); 248 dumpConstants(D, f); 249 dumpUpvalues(D, f); 250 dumpProtos(D, f); 251 dumpString(D, D->strip ? NULL : f->source); 252 dumpDebug(D, f); 253 } 254 255 256 static void dumpHeader (DumpState *D) { 257 dumpLiteral(D, LUA_SIGNATURE); 258 dumpByte(D, LUAC_VERSION); 259 dumpByte(D, LUAC_FORMAT); 260 dumpLiteral(D, LUAC_DATA); 261 dumpByte(D, sizeof(Instruction)); 262 dumpByte(D, sizeof(lua_Integer)); 263 dumpByte(D, sizeof(lua_Number)); 264 dumpInteger(D, LUAC_INT); 265 dumpNumber(D, LUAC_NUM); 266 } 267 268 269 /* 270 ** dump Lua function as precompiled chunk 271 */ 272 int luaU_dump (lua_State *L, const Proto *f, lua_Writer w, void *data, 273 int strip) { 274 DumpState D; 275 D.h = luaH_new(L); /* aux. table to keep strings already dumped */ 276 sethvalue2s(L, L->top.p, D.h); /* anchor it */ 277 L->top.p++; 278 D.L = L; 279 D.writer = w; 280 D.offset = 0; 281 D.data = data; 282 D.strip = strip; 283 D.status = 0; 284 D.nstr = 0; 285 dumpHeader(&D); 286 dumpByte(&D, f->sizeupvalues); 287 dumpFunction(&D, f); 288 dumpBlock(&D, NULL, 0); /* signal end of dump */ 289 return D.status; 290 } 291