lua

A copy of the Lua development repository
Log | Files | Refs | README

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