mirror of
https://github.com/lua/lua.git
synced 2025-01-28 06:03:00 +08:00
19afd91687
The use of tables in dump/undump to reuse strings did not exist in the version that changed the representation of arrays, so it was not corrected for the new API for tables.
271 lines
6.1 KiB
C
271 lines
6.1 KiB
C
/*
|
|
** $Id: ldump.c $
|
|
** save precompiled Lua chunks
|
|
** See Copyright Notice in lua.h
|
|
*/
|
|
|
|
#define ldump_c
|
|
#define LUA_CORE
|
|
|
|
#include "lprefix.h"
|
|
|
|
|
|
#include <limits.h>
|
|
#include <stddef.h>
|
|
|
|
#include "lua.h"
|
|
|
|
#include "lgc.h"
|
|
#include "lobject.h"
|
|
#include "lstate.h"
|
|
#include "ltable.h"
|
|
#include "lundump.h"
|
|
|
|
|
|
typedef struct {
|
|
lua_State *L;
|
|
lua_Writer writer;
|
|
void *data;
|
|
lu_mem offset; /* current position relative to beginning of dump */
|
|
int strip;
|
|
int status;
|
|
Table *h; /* table to track saved strings */
|
|
lua_Integer nstr; /* counter to number saved strings */
|
|
} DumpState;
|
|
|
|
|
|
/*
|
|
** All high-level dumps go through dumpVector; you can change it to
|
|
** change the endianness of the result
|
|
*/
|
|
#define dumpVector(D,v,n) dumpBlock(D,v,(n)*sizeof((v)[0]))
|
|
|
|
#define dumpLiteral(D, s) dumpBlock(D,s,sizeof(s) - sizeof(char))
|
|
|
|
|
|
static void dumpBlock (DumpState *D, const void *b, size_t size) {
|
|
if (D->status == 0 && size > 0) {
|
|
lua_unlock(D->L);
|
|
D->status = (*D->writer)(D->L, b, size, D->data);
|
|
lua_lock(D->L);
|
|
D->offset += size;
|
|
}
|
|
}
|
|
|
|
|
|
static void dumpAlign (DumpState *D, int align) {
|
|
int padding = align - (D->offset % align);
|
|
if (padding < align) { /* apd == align means no padding */
|
|
static lua_Integer paddingContent = 0;
|
|
dumpBlock(D, &paddingContent, padding);
|
|
lua_assert(D->offset % align == 0);
|
|
}
|
|
}
|
|
|
|
|
|
#define dumpVar(D,x) dumpVector(D,&x,1)
|
|
|
|
|
|
static void dumpByte (DumpState *D, int y) {
|
|
lu_byte x = (lu_byte)y;
|
|
dumpVar(D, x);
|
|
}
|
|
|
|
|
|
/*
|
|
** 'dumpSize' buffer size: each byte can store up to 7 bits. (The "+6"
|
|
** rounds up the division.)
|
|
*/
|
|
#define DIBS ((sizeof(size_t) * CHAR_BIT + 6) / 7)
|
|
|
|
static void dumpSize (DumpState *D, size_t x) {
|
|
lu_byte buff[DIBS];
|
|
int n = 0;
|
|
do {
|
|
buff[DIBS - (++n)] = x & 0x7f; /* fill buffer in reverse order */
|
|
x >>= 7;
|
|
} while (x != 0);
|
|
buff[DIBS - 1] |= 0x80; /* mark last byte */
|
|
dumpVector(D, buff + DIBS - n, n);
|
|
}
|
|
|
|
|
|
static void dumpInt (DumpState *D, int x) {
|
|
dumpSize(D, x);
|
|
}
|
|
|
|
|
|
static void dumpNumber (DumpState *D, lua_Number x) {
|
|
dumpVar(D, x);
|
|
}
|
|
|
|
|
|
static void dumpInteger (DumpState *D, lua_Integer x) {
|
|
dumpVar(D, x);
|
|
}
|
|
|
|
|
|
/*
|
|
** Dump a String. First dump its "size": size==0 means NULL;
|
|
** size==1 is followed by an index and means "reuse saved string with
|
|
** that index"; size>=2 is followed by the string contents with real
|
|
** size==size-2 and means that string, which will be saved with
|
|
** the next available index.
|
|
*/
|
|
static void dumpString (DumpState *D, TString *ts) {
|
|
if (ts == NULL)
|
|
dumpSize(D, 0);
|
|
else {
|
|
TValue idx;
|
|
if (luaH_getstr(D->h, ts, &idx) == HOK) { /* string already saved? */
|
|
dumpSize(D, 1); /* reuse a saved string */
|
|
dumpInt(D, ivalue(&idx)); /* index of saved string */
|
|
}
|
|
else { /* must write and save the string */
|
|
TValue key, value; /* to save the string in the hash */
|
|
size_t size;
|
|
const char *s = getlstr(ts, size);
|
|
dumpSize(D, size + 2);
|
|
dumpVector(D, s, size);
|
|
D->nstr++; /* one more saved string */
|
|
setsvalue(D->L, &key, ts); /* the string is the key */
|
|
setivalue(&value, D->nstr); /* its index is the value */
|
|
luaH_set(D->L, D->h, &key, &value); /* h[ts] = nstr */
|
|
/* integer value does not need barrier */
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void dumpCode (DumpState *D, const Proto *f) {
|
|
dumpInt(D, f->sizecode);
|
|
dumpAlign(D, sizeof(f->code[0]));
|
|
dumpVector(D, f->code, f->sizecode);
|
|
}
|
|
|
|
|
|
static void dumpFunction(DumpState *D, const Proto *f);
|
|
|
|
static void dumpConstants (DumpState *D, const Proto *f) {
|
|
int i;
|
|
int n = f->sizek;
|
|
dumpInt(D, n);
|
|
for (i = 0; i < n; i++) {
|
|
const TValue *o = &f->k[i];
|
|
int tt = ttypetag(o);
|
|
dumpByte(D, tt);
|
|
switch (tt) {
|
|
case LUA_VNUMFLT:
|
|
dumpNumber(D, fltvalue(o));
|
|
break;
|
|
case LUA_VNUMINT:
|
|
dumpInteger(D, ivalue(o));
|
|
break;
|
|
case LUA_VSHRSTR:
|
|
case LUA_VLNGSTR:
|
|
dumpString(D, tsvalue(o));
|
|
break;
|
|
default:
|
|
lua_assert(tt == LUA_VNIL || tt == LUA_VFALSE || tt == LUA_VTRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void dumpProtos (DumpState *D, const Proto *f) {
|
|
int i;
|
|
int n = f->sizep;
|
|
dumpInt(D, n);
|
|
for (i = 0; i < n; i++)
|
|
dumpFunction(D, f->p[i]);
|
|
}
|
|
|
|
|
|
static void dumpUpvalues (DumpState *D, const Proto *f) {
|
|
int i, n = f->sizeupvalues;
|
|
dumpInt(D, n);
|
|
for (i = 0; i < n; i++) {
|
|
dumpByte(D, f->upvalues[i].instack);
|
|
dumpByte(D, f->upvalues[i].idx);
|
|
dumpByte(D, f->upvalues[i].kind);
|
|
}
|
|
}
|
|
|
|
|
|
static void dumpDebug (DumpState *D, const Proto *f) {
|
|
int i, n;
|
|
n = (D->strip) ? 0 : f->sizelineinfo;
|
|
dumpInt(D, n);
|
|
dumpVector(D, f->lineinfo, n);
|
|
n = (D->strip) ? 0 : f->sizeabslineinfo;
|
|
dumpInt(D, n);
|
|
for (i = 0; i < n; i++) {
|
|
dumpInt(D, f->abslineinfo[i].pc);
|
|
dumpInt(D, f->abslineinfo[i].line);
|
|
}
|
|
n = (D->strip) ? 0 : f->sizelocvars;
|
|
dumpInt(D, n);
|
|
for (i = 0; i < n; i++) {
|
|
dumpString(D, f->locvars[i].varname);
|
|
dumpInt(D, f->locvars[i].startpc);
|
|
dumpInt(D, f->locvars[i].endpc);
|
|
}
|
|
n = (D->strip) ? 0 : f->sizeupvalues;
|
|
dumpInt(D, n);
|
|
for (i = 0; i < n; i++)
|
|
dumpString(D, f->upvalues[i].name);
|
|
}
|
|
|
|
|
|
static void dumpFunction (DumpState *D, const Proto *f) {
|
|
if (D->strip)
|
|
dumpString(D, NULL); /* no debug info */
|
|
else
|
|
dumpString(D, f->source);
|
|
dumpInt(D, f->linedefined);
|
|
dumpInt(D, f->lastlinedefined);
|
|
dumpByte(D, f->numparams);
|
|
dumpByte(D, f->flag);
|
|
dumpByte(D, f->maxstacksize);
|
|
dumpCode(D, f);
|
|
dumpConstants(D, f);
|
|
dumpUpvalues(D, f);
|
|
dumpProtos(D, f);
|
|
dumpDebug(D, f);
|
|
}
|
|
|
|
|
|
static void dumpHeader (DumpState *D) {
|
|
dumpLiteral(D, LUA_SIGNATURE);
|
|
dumpByte(D, LUAC_VERSION);
|
|
dumpByte(D, LUAC_FORMAT);
|
|
dumpLiteral(D, LUAC_DATA);
|
|
dumpByte(D, sizeof(Instruction));
|
|
dumpByte(D, sizeof(lua_Integer));
|
|
dumpByte(D, sizeof(lua_Number));
|
|
dumpInteger(D, LUAC_INT);
|
|
dumpNumber(D, LUAC_NUM);
|
|
}
|
|
|
|
|
|
/*
|
|
** dump Lua function as precompiled chunk
|
|
*/
|
|
int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data,
|
|
int strip, Table *h) {
|
|
DumpState D;
|
|
D.L = L;
|
|
D.writer = w;
|
|
D.offset = 0;
|
|
D.data = data;
|
|
D.strip = strip;
|
|
D.status = 0;
|
|
D.h = h;
|
|
D.nstr = 0;
|
|
dumpHeader(&D);
|
|
dumpByte(&D, f->sizeupvalues);
|
|
dumpFunction(&D, f);
|
|
return D.status;
|
|
}
|
|
|