mirror of
https://github.com/lua/lua
synced 2024-11-22 12:51:30 +03:00
5ff408d218
Instead of an explicit value (field 'b'), true and false use different tag variants. This avoids reading an extra field and results in more direct code. (Most code that uses booleans needs to distinguish between true and false anyway.)
227 lines
4.7 KiB
C
227 lines
4.7 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 <stddef.h>
|
|
|
|
#include "lua.h"
|
|
|
|
#include "lobject.h"
|
|
#include "lstate.h"
|
|
#include "lundump.h"
|
|
|
|
|
|
typedef struct {
|
|
lua_State *L;
|
|
lua_Writer writer;
|
|
void *data;
|
|
int strip;
|
|
int status;
|
|
} DumpState;
|
|
|
|
|
|
/*
|
|
** All high-level dumps go through DumpVector; you can change it to
|
|
** change the endianness of the result
|
|
*/
|
|
#define DumpVector(v,n,D) DumpBlock(v,(n)*sizeof((v)[0]),D)
|
|
|
|
#define DumpLiteral(s,D) DumpBlock(s, sizeof(s) - sizeof(char), D)
|
|
|
|
|
|
static void DumpBlock (const void *b, size_t size, DumpState *D) {
|
|
if (D->status == 0 && size > 0) {
|
|
lua_unlock(D->L);
|
|
D->status = (*D->writer)(D->L, b, size, D->data);
|
|
lua_lock(D->L);
|
|
}
|
|
}
|
|
|
|
|
|
#define DumpVar(x,D) DumpVector(&x,1,D)
|
|
|
|
|
|
static void DumpByte (int y, DumpState *D) {
|
|
lu_byte x = (lu_byte)y;
|
|
DumpVar(x, D);
|
|
}
|
|
|
|
|
|
/* DumpInt Buff Size */
|
|
#define DIBS ((sizeof(size_t) * 8 / 7) + 1)
|
|
|
|
static void DumpSize (size_t x, DumpState *D) {
|
|
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(buff + DIBS - n, n, D);
|
|
}
|
|
|
|
|
|
static void DumpInt (int x, DumpState *D) {
|
|
DumpSize(x, D);
|
|
}
|
|
|
|
|
|
static void DumpNumber (lua_Number x, DumpState *D) {
|
|
DumpVar(x, D);
|
|
}
|
|
|
|
|
|
static void DumpInteger (lua_Integer x, DumpState *D) {
|
|
DumpVar(x, D);
|
|
}
|
|
|
|
|
|
static void DumpString (const TString *s, DumpState *D) {
|
|
if (s == NULL)
|
|
DumpSize(0, D);
|
|
else {
|
|
size_t size = tsslen(s);
|
|
const char *str = getstr(s);
|
|
DumpSize(size + 1, D);
|
|
DumpVector(str, size, D);
|
|
}
|
|
}
|
|
|
|
|
|
static void DumpCode (const Proto *f, DumpState *D) {
|
|
DumpInt(f->sizecode, D);
|
|
DumpVector(f->code, f->sizecode, D);
|
|
}
|
|
|
|
|
|
static void DumpFunction(const Proto *f, TString *psource, DumpState *D);
|
|
|
|
static void DumpConstants (const Proto *f, DumpState *D) {
|
|
int i;
|
|
int n = f->sizek;
|
|
DumpInt(n, D);
|
|
for (i = 0; i < n; i++) {
|
|
const TValue *o = &f->k[i];
|
|
DumpByte(ttypetag(o), D);
|
|
switch (ttypetag(o)) {
|
|
case LUA_TNIL: case LUA_TFALSE: case LUA_TTRUE:
|
|
break;
|
|
case LUA_TNUMFLT:
|
|
DumpNumber(fltvalue(o), D);
|
|
break;
|
|
case LUA_TNUMINT:
|
|
DumpInteger(ivalue(o), D);
|
|
break;
|
|
case LUA_TSHRSTR:
|
|
case LUA_TLNGSTR:
|
|
DumpString(tsvalue(o), D);
|
|
break;
|
|
default: lua_assert(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void DumpProtos (const Proto *f, DumpState *D) {
|
|
int i;
|
|
int n = f->sizep;
|
|
DumpInt(n, D);
|
|
for (i = 0; i < n; i++)
|
|
DumpFunction(f->p[i], f->source, D);
|
|
}
|
|
|
|
|
|
static void DumpUpvalues (const Proto *f, DumpState *D) {
|
|
int i, n = f->sizeupvalues;
|
|
DumpInt(n, D);
|
|
for (i = 0; i < n; i++) {
|
|
DumpByte(f->upvalues[i].instack, D);
|
|
DumpByte(f->upvalues[i].idx, D);
|
|
DumpByte(f->upvalues[i].kind, D);
|
|
}
|
|
}
|
|
|
|
|
|
static void DumpDebug (const Proto *f, DumpState *D) {
|
|
int i, n;
|
|
n = (D->strip) ? 0 : f->sizelineinfo;
|
|
DumpInt(n, D);
|
|
DumpVector(f->lineinfo, n, D);
|
|
n = (D->strip) ? 0 : f->sizeabslineinfo;
|
|
DumpInt(n, D);
|
|
for (i = 0; i < n; i++) {
|
|
DumpInt(f->abslineinfo[i].pc, D);
|
|
DumpInt(f->abslineinfo[i].line, D);
|
|
}
|
|
n = (D->strip) ? 0 : f->sizelocvars;
|
|
DumpInt(n, D);
|
|
for (i = 0; i < n; i++) {
|
|
DumpString(f->locvars[i].varname, D);
|
|
DumpInt(f->locvars[i].startpc, D);
|
|
DumpInt(f->locvars[i].endpc, D);
|
|
}
|
|
n = (D->strip) ? 0 : f->sizeupvalues;
|
|
DumpInt(n, D);
|
|
for (i = 0; i < n; i++)
|
|
DumpString(f->upvalues[i].name, D);
|
|
}
|
|
|
|
|
|
static void DumpFunction (const Proto *f, TString *psource, DumpState *D) {
|
|
if (D->strip || f->source == psource)
|
|
DumpString(NULL, D); /* no debug info or same source as its parent */
|
|
else
|
|
DumpString(f->source, D);
|
|
DumpInt(f->linedefined, D);
|
|
DumpInt(f->lastlinedefined, D);
|
|
DumpByte(f->numparams, D);
|
|
DumpByte(f->is_vararg, D);
|
|
DumpByte(f->maxstacksize, D);
|
|
DumpCode(f, D);
|
|
DumpConstants(f, D);
|
|
DumpUpvalues(f, D);
|
|
DumpProtos(f, D);
|
|
DumpDebug(f, D);
|
|
}
|
|
|
|
|
|
static void DumpHeader (DumpState *D) {
|
|
DumpLiteral(LUA_SIGNATURE, D);
|
|
DumpInt(LUAC_VERSION, D);
|
|
DumpByte(LUAC_FORMAT, D);
|
|
DumpLiteral(LUAC_DATA, D);
|
|
DumpByte(sizeof(Instruction), D);
|
|
DumpByte(sizeof(lua_Integer), D);
|
|
DumpByte(sizeof(lua_Number), D);
|
|
DumpInteger(LUAC_INT, D);
|
|
DumpNumber(LUAC_NUM, D);
|
|
}
|
|
|
|
|
|
/*
|
|
** dump Lua function as precompiled chunk
|
|
*/
|
|
int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data,
|
|
int strip) {
|
|
DumpState D;
|
|
D.L = L;
|
|
D.writer = w;
|
|
D.data = data;
|
|
D.strip = strip;
|
|
D.status = 0;
|
|
DumpHeader(&D);
|
|
DumpByte(f->sizeupvalues, &D);
|
|
DumpFunction(f, NULL, &D);
|
|
return D.status;
|
|
}
|
|
|