Add support for bytecode loading/saving.

This commit is contained in:
Mike Pall 2011-06-13 00:58:13 +02:00
parent 9da94d1355
commit 4994fcc32c
16 changed files with 1019 additions and 48 deletions

View File

@ -114,11 +114,6 @@ hooks for non-Lua functions) and shows slightly different behavior
(no per-coroutine hooks, no tail call counting).
</li>
<li>
<b>Bytecode</b> currently cannot be loaded or dumped. Note that
the bytecode format differs from Lua&nbsp;5.1 &mdash; loading foreign
bytecode is not supported at all.
</li>
<li>
Some of the <b>configuration options</b> of Lua&nbsp;5.1 are not supported:
<ul>
<li>The <b>number type</b> cannot be changed (it's always a <tt>double</tt>).</li>

View File

@ -360,7 +360,7 @@ LJLIB_C= $(LJLIB_O:.o=.c)
LJCORE_O= lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o \
lj_str.o lj_tab.o lj_func.o lj_udata.o lj_meta.o lj_debug.o \
lj_state.o lj_dispatch.o lj_vmevent.o lj_vmmath.o lj_api.o \
lj_lex.o lj_parse.o \
lj_lex.o lj_parse.o lj_bcread.o lj_bcwrite.o \
lj_ir.o lj_opt_mem.o lj_opt_fold.o lj_opt_narrow.o \
lj_opt_dce.o lj_opt_loop.o lj_opt_split.o \
lj_mcode.o lj_snap.o lj_record.o lj_crecord.o lj_ffrecord.o \

View File

@ -42,7 +42,8 @@ lib_package.o: lib_package.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
lj_def.h lj_arch.h lj_err.h lj_errmsg.h lj_lib.h
lib_string.o: lib_string.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h \
lj_state.h lj_ff.h lj_ffdef.h lj_char.h lj_lib.h lj_libdef.h
lj_state.h lj_ff.h lj_ffdef.h lj_bcdump.h lj_lex.h lj_char.h lj_lib.h \
lj_libdef.h
lib_table.o: lib_table.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_lib.h \
lj_libdef.h
@ -50,7 +51,7 @@ lj_alloc.o: lj_alloc.c lj_def.h lua.h luaconf.h lj_arch.h lj_alloc.h
lj_api.o: lj_api.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
lj_err.h lj_errmsg.h lj_debug.h lj_str.h lj_tab.h lj_func.h lj_udata.h \
lj_meta.h lj_state.h lj_bc.h lj_frame.h lj_trace.h lj_jit.h lj_ir.h \
lj_dispatch.h lj_traceerr.h lj_vm.h lj_lex.h lj_parse.h
lj_dispatch.h lj_traceerr.h lj_vm.h lj_lex.h lj_bcdump.h lj_parse.h
lj_asm.o: lj_asm.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h lj_ir.h lj_jit.h \
lj_ircall.h lj_iropt.h lj_mcode.h lj_trace.h lj_dispatch.h lj_traceerr.h \
@ -58,6 +59,12 @@ lj_asm.o: lj_asm.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
lj_asm_*.h
lj_bc.o: lj_bc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_bc.h \
lj_bcdef.h
lj_bcread.o: lj_bcread.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_bc.h lj_ctype.h \
lj_cdata.h lj_lex.h lj_bcdump.h lj_state.h
lj_bcwrite.o: lj_bcwrite.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_gc.h lj_str.h lj_bc.h lj_ctype.h lj_dispatch.h lj_jit.h lj_ir.h \
lj_bcdump.h lj_lex.h lj_err.h lj_errmsg.h lj_vm.h
lj_carith.o: lj_carith.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_meta.h lj_ctype.h lj_cconv.h \
lj_cdata.h lj_carith.h
@ -180,16 +187,16 @@ ljamalg.o: ljamalg.c lua.h luaconf.h lauxlib.h lj_gc.c lj_obj.h lj_def.h \
lj_debug.h lj_ff.h lj_ffdef.h lj_char.c lj_char.h lj_bc.c lj_bcdef.h \
lj_obj.c lj_str.c lj_tab.c lj_func.c lj_udata.c lj_meta.c lj_debug.c \
lj_state.c lj_lex.h lj_alloc.h lj_dispatch.c luajit.h lj_vmevent.c \
lj_vmevent.h lj_vmmath.c lj_api.c lj_parse.h lj_lex.c lualib.h \
lj_parse.c lj_ctype.c lj_cdata.c lj_cconv.h lj_cconv.c lj_ccall.c \
lj_ccall.h lj_carith.c lj_carith.h lj_clib.c lj_clib.h lj_cparse.c \
lj_cparse.h lj_lib.c lj_lib.h lj_ir.c lj_ircall.h lj_iropt.h \
lj_opt_mem.c lj_opt_fold.c lj_folddef.h lj_opt_narrow.c lj_opt_dce.c \
lj_opt_loop.c lj_snap.h lj_opt_split.c lj_mcode.c lj_mcode.h lj_snap.c \
lj_target.h lj_target_*.h lj_record.c lj_record.h lj_ffrecord.h \
lj_crecord.c lj_crecord.h lj_ffrecord.c lj_recdef.h lj_asm.c lj_asm.h \
lj_emit_*.h lj_asm_*.h lj_trace.c lj_gdbjit.h lj_gdbjit.c lj_alloc.c \
lib_aux.c lib_base.c lj_libdef.h lib_math.c lib_string.c lib_table.c \
lib_io.c lib_os.c lib_package.c lib_debug.c lib_bit.c lib_jit.c \
lib_ffi.c lib_init.c
lj_vmevent.h lj_vmmath.c lj_api.c lj_bcdump.h lj_parse.h lj_lex.c \
lualib.h lj_parse.c lj_bcread.c lj_bcwrite.c lj_ctype.c lj_cdata.c \
lj_cconv.h lj_cconv.c lj_ccall.c lj_ccall.h lj_carith.c lj_carith.h \
lj_clib.c lj_clib.h lj_cparse.c lj_cparse.h lj_lib.c lj_lib.h lj_ir.c \
lj_ircall.h lj_iropt.h lj_opt_mem.c lj_opt_fold.c lj_folddef.h \
lj_opt_narrow.c lj_opt_dce.c lj_opt_loop.c lj_snap.h lj_opt_split.c \
lj_mcode.c lj_mcode.h lj_snap.c lj_target.h lj_target_*.h lj_record.c \
lj_record.h lj_ffrecord.h lj_crecord.c lj_crecord.h lj_ffrecord.c \
lj_recdef.h lj_asm.c lj_asm.h lj_emit_*.h lj_asm_*.h lj_trace.c \
lj_gdbjit.h lj_gdbjit.c lj_alloc.c lib_aux.c lib_base.c lj_libdef.h \
lib_math.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c \
lib_debug.c lib_bit.c lib_jit.c lib_ffi.c lib_init.c
luajit.o: luajit.c lua.h luaconf.h lauxlib.h lualib.h luajit.h lj_arch.h

View File

@ -22,6 +22,7 @@
#include "lj_tab.h"
#include "lj_state.h"
#include "lj_ff.h"
#include "lj_bcdump.h"
#include "lj_char.h"
#include "lj_lib.h"
@ -114,10 +115,24 @@ LJLIB_ASM_(string_upper)
/* ------------------------------------------------------------------------ */
static int writer_buf(lua_State *L, const void *p, size_t size, void *b)
{
luaL_addlstring((luaL_Buffer *)b, (const char *)p, size);
UNUSED(L);
return 0;
}
LJLIB_CF(string_dump)
{
lj_err_caller(L, LJ_ERR_STRDUMP);
return 0; /* unreachable */
GCfunc *fn = lj_lib_checkfunc(L, 1);
int strip = L->base+1 < L->top && tvistruecond(L->base+1);
luaL_Buffer b;
L->top = L->base+1;
luaL_buffinit(L, &b);
if (!isluafunc(fn) || lj_bcwrite(L, funcproto(fn), writer_buf, &b, strip))
lj_err_caller(L, LJ_ERR_STRDUMP);
luaL_pushresult(&b);
return 1;
}
/* ------------------------------------------------------------------------ */

View File

@ -24,6 +24,7 @@
#include "lj_trace.h"
#include "lj_vm.h"
#include "lj_lex.h"
#include "lj_bcdump.h"
#include "lj_parse.h"
/* -- Common helper functions --------------------------------------------- */
@ -1115,12 +1116,13 @@ LUA_API int lua_resume(lua_State *L, int nargs)
static TValue *cpparser(lua_State *L, lua_CFunction dummy, void *ud)
{
LexState *ls = (LexState *)ud;
GCproto *pt;
GCfunc *fn;
UNUSED(dummy);
cframe_errfunc(L->cframe) = -1; /* Inherit error function. */
lj_lex_setup(L, ls);
fn = lj_func_newL(L, lj_parse(ls), tabref(L->env));
/* Parser may realloc stack. Don't combine above/below into one statement. */
pt = lj_lex_setup(L, ls) ? lj_bcread(ls) : lj_parse(ls);
fn = lj_func_newL_empty(L, pt, tabref(L->env));
/* Don't combine above/below into one statement. */
setfuncV(L, L->top++, fn);
return NULL;
}
@ -1142,9 +1144,12 @@ LUA_API int lua_load(lua_State *L, lua_Reader reader, void *data,
LUA_API int lua_dump(lua_State *L, lua_Writer writer, void *data)
{
cTValue *o = L->top-1;
api_checknelems(L, 1);
UNUSED(L); UNUSED(writer); UNUSED(data);
return 1; /* Error, not supported. */
if (tvisfunc(o) && isluafunc(funcV(o)))
return lj_bcwrite(L, funcproto(funcV(o)), writer, data, 0);
else
return 1;
}
/* -- GC and memory management -------------------------------------------- */

66
src/lj_bcdump.h Normal file
View File

@ -0,0 +1,66 @@
/*
** Bytecode dump definitions.
** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_BCDUMP_H
#define _LJ_BCDUMP_H
#include "lj_obj.h"
#include "lj_lex.h"
/* -- Bytecode dump format ------------------------------------------------ */
/*
** dump = header proto+ 0U
** header = ESC 'L' 'J' versionB flagsU [namelenU nameB*]
** proto = lengthU pdata
** pdata = phead bcinsW* uvdataH* kgc* knum* [debugB*]
** phead = flagsB numparamsB framesizeB numuvB numkgcU numknU numbcU
** [debuglenU [firstlineU numlineU]]
** kgc = kgctypeU { ktab | (loU hiU) | (rloU rhiU iloU ihiU) | strB* }
** knum = intU0 | (loU1 hiU)
** ktab = narrayU nhashU karray* khash*
** karray = ktabk
** khash = ktabk ktabk
** ktabk = ktabtypeU { intU | (loU hiU) | strB* }
**
** B = 8 bit, H = 16 bit, W = 32 bit, U = ULEB128 of W, U0/U1 = ULEB128 of W+1
*/
/* Bytecode dump header. */
#define BCDUMP_HEAD1 0x1b
#define BCDUMP_HEAD2 0x4c
#define BCDUMP_HEAD3 0x4a
/* If you perform *any* kind of private modifications to the bytecode itself
** or to the dump format, you *must* set BCDUMP_VERSION to 0x80 or higher.
*/
#define BCDUMP_VERSION 1
/* Compatibility flags. */
#define BCDUMP_F_BE 0x01
#define BCDUMP_F_STRIP 0x02
#define BCDUMP_F_FFI 0x04
#define BCDUMP_F_KNOWN (BCDUMP_F_FFI*2-1)
/* Type codes for the GC constants of a prototype. Plus length for strings. */
enum {
BCDUMP_KGC_CHILD, BCDUMP_KGC_TAB, BCDUMP_KGC_I64, BCDUMP_KGC_U64,
BCDUMP_KGC_COMPLEX, BCDUMP_KGC_STR
};
/* Type codes for the keys/values of a constant table. */
enum {
BCDUMP_KTAB_NIL, BCDUMP_KTAB_FALSE, BCDUMP_KTAB_TRUE,
BCDUMP_KTAB_INT, BCDUMP_KTAB_NUM, BCDUMP_KTAB_STR
};
/* -- Bytecode reader/writer ---------------------------------------------- */
LJ_FUNC int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer,
void *data, int strip);
LJ_FUNC GCproto *lj_bcread(LexState *ls);
#endif

466
src/lj_bcread.c Normal file
View File

@ -0,0 +1,466 @@
/*
** Bytecode reader.
** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h
*/
#define lj_bcread_c
#define LUA_CORE
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_bc.h"
#if LJ_HASFFI
#include "lj_ctype.h"
#include "lj_cdata.h"
#endif
#include "lj_lex.h"
#include "lj_bcdump.h"
#include "lj_state.h"
/* Reuse some lexer fields for our own purposes. */
#define bcread_flags(ls) ls->level
#define bcread_swap(ls) \
((bcread_flags(ls) & BCDUMP_F_BE) != LJ_BE*BCDUMP_F_BE)
#define bcread_oldtop(L, ls) restorestack(L, ls->lastline)
#define bcread_savetop(L, ls, top) \
ls->lastline = (BCLine)savestack(L, (top))
/* -- Input buffer handling ----------------------------------------------- */
/* Throw reader error. */
static LJ_NOINLINE void bcread_error(LexState *ls, ErrMsg em)
{
lua_State *L = ls->L;
const char *name = ls->chunkarg;
if (*name == BCDUMP_HEAD1) name = "(binary)";
else if (*name == '@' || *name == '=') name++;
lj_str_pushf(L, "%s: %s", name, err2msg(em));
lj_err_throw(L, LUA_ERRSYNTAX);
}
/* Resize input buffer. */
static void bcread_resize(LexState *ls, MSize len)
{
if (ls->sb.sz < len) {
MSize sz = ls->sb.sz * 2;
while (len > sz) sz = sz * 2;
lj_str_resizebuf(ls->L, &ls->sb, sz);
/* Caveat: this may change ls->sb.buf which may affect ls->p. */
}
}
/* Refill buffer if needed. */
static LJ_NOINLINE void bcread_fill(LexState *ls, MSize len, int need)
{
lua_assert(len != 0);
if (len > LJ_MAX_MEM || ls->current < 0)
bcread_error(ls, LJ_ERR_BCBAD);
do {
const char *buf;
size_t size;
if (ls->n) { /* Copy remainder to buffer. */
if (ls->sb.n) { /* Move down in buffer. */
lua_assert(ls->p + ls->n == ls->sb.buf + ls->sb.n);
if (ls->n != ls->sb.n)
memmove(ls->sb.buf, ls->p, ls->n);
} else { /* Copy from buffer provided by reader. */
bcread_resize(ls, len);
memcpy(ls->sb.buf, ls->p, ls->n);
}
ls->p = ls->sb.buf;
}
ls->sb.n = ls->n;
buf = ls->rfunc(ls->L, ls->rdata, &size); /* Get more data from reader. */
if (buf == NULL || size == 0) { /* EOF? */
if (need) bcread_error(ls, LJ_ERR_BCBAD);
ls->current = -1; /* Only bad if we get called again. */
break;
}
if (ls->sb.n) { /* Append to buffer. */
MSize n = ls->sb.n + (MSize)size;
bcread_resize(ls, n < len ? len : n);
memcpy(ls->sb.buf + ls->sb.n, buf, size);
ls->n = ls->sb.n = n;
ls->p = ls->sb.buf;
} else { /* Return buffer provided by reader. */
ls->n = (MSize)size;
ls->p = buf;
}
} while (ls->n < len);
}
/* Need a certain number of bytes. */
static LJ_AINLINE void bcread_need(LexState *ls, MSize len)
{
if (LJ_UNLIKELY(ls->n < len))
bcread_fill(ls, len, 1);
}
/* Want to read up to a certain number of bytes, but may need less. */
static LJ_AINLINE void bcread_want(LexState *ls, MSize len)
{
if (LJ_UNLIKELY(ls->n < len))
bcread_fill(ls, len, 0);
}
#define bcread_dec(ls) check_exp(ls->n > 0, ls->n--)
#define bcread_consume(ls, len) check_exp(ls->n >= (len), ls->n -= (len))
/* Return memory block from buffer. */
static uint8_t *bcread_mem(LexState *ls, MSize len)
{
uint8_t *p = (uint8_t *)ls->p;
bcread_consume(ls, len);
ls->p = (char *)p + len;
return p;
}
/* Copy memory block from buffer. */
static void bcread_block(LexState *ls, void *q, MSize len)
{
memcpy(q, bcread_mem(ls, len), len);
}
/* Read byte from buffer. */
static LJ_AINLINE uint32_t bcread_byte(LexState *ls)
{
bcread_dec(ls);
return (uint32_t)(uint8_t)*ls->p++;
}
/* Read ULEB128 value from buffer. */
static uint32_t bcread_uleb128(LexState *ls)
{
const uint8_t *p = (const uint8_t *)ls->p;
uint32_t v = *p++;
if (LJ_UNLIKELY(v >= 0x80)) {
int sh = 0;
v &= 0x7f;
do {
v |= ((*p & 0x7f) << (sh += 7));
bcread_dec(ls);
} while (*p++ >= 0x80);
}
bcread_dec(ls);
ls->p = (char *)p;
return v;
}
/* Read top 32 bits of 33 bit ULEB128 value from buffer. */
static uint32_t bcread_uleb128_33(LexState *ls)
{
const uint8_t *p = (const uint8_t *)ls->p;
uint32_t v = (*p++ >> 1);
if (LJ_UNLIKELY(v >= 0x40)) {
int sh = -1;
v &= 0x3f;
do {
v |= ((*p & 0x7f) << (sh += 7));
bcread_dec(ls);
} while (*p++ >= 0x80);
}
bcread_dec(ls);
ls->p = (char *)p;
return v;
}
/* -- Bytecode reader ----------------------------------------------------- */
/* Read debug info of a prototype. */
static void bcread_dbg(LexState *ls, GCproto *pt, MSize sizedbg)
{
void *lineinfo = (void *)proto_lineinfo(pt);
bcread_block(ls, lineinfo, sizedbg);
/* Swap lineinfo if the endianess differs. */
if (bcread_swap(ls) && pt->numline >= 256) {
MSize i, n = pt->sizebc-1;
if (pt->numline < 65536) {
uint16_t *p = (uint16_t *)lineinfo;
for (i = 0; i < n; i++) p[i] = (uint16_t)((p[i] >> 8)|(p[i] << 8));
} else {
uint32_t *p = (uint32_t *)lineinfo;
for (i = 0; i < n; i++) p[i] = lj_bswap(p[i]);
}
}
}
/* Find pointer to varinfo. */
static const void *bcread_varinfo(GCproto *pt)
{
const uint8_t *p = proto_uvinfo(pt);
MSize n = pt->sizeuv;
if (n) while (*p++ || --n) ;
return p;
}
/* Read a single constant key/value of a template table. */
static void bcread_ktabk(LexState *ls, TValue *o)
{
MSize tp = bcread_uleb128(ls);
if (tp >= BCDUMP_KTAB_STR) {
MSize len = tp - BCDUMP_KTAB_STR;
const char *p = (const char *)bcread_mem(ls, len);
setstrV(ls->L, o, lj_str_new(ls->L, p, len));
} else if (tp == BCDUMP_KTAB_INT) {
setintV(o, (int32_t)bcread_uleb128(ls));
} else if (tp == BCDUMP_KTAB_NUM) {
o->u32.lo = bcread_uleb128(ls);
o->u32.hi = bcread_uleb128(ls);
} else {
lua_assert(tp <= BCDUMP_KTAB_TRUE);
setitype(o, ~tp);
}
}
/* Read a template table. */
static GCtab *bcread_ktab(LexState *ls)
{
MSize narray = bcread_uleb128(ls);
MSize nhash = bcread_uleb128(ls);
GCtab *t = lj_tab_new(ls->L, narray, hsize2hbits(nhash));
if (narray) { /* Read array entries. */
MSize i;
TValue *o = tvref(t->array);
for (i = 0; i < narray; i++, o++)
bcread_ktabk(ls, o);
}
if (nhash) { /* Read hash entries. */
MSize i;
for (i = 0; i < nhash; i++) {
TValue key;
bcread_ktabk(ls, &key);
lua_assert(!tvisnil(&key));
bcread_ktabk(ls, lj_tab_set(ls->L, t, &key));
}
}
return t;
}
/* Read GC constants of a prototype. */
static void bcread_kgc(LexState *ls, GCproto *pt, MSize sizekgc)
{
MSize i;
GCRef *kr = mref(pt->k, GCRef) - (ptrdiff_t)sizekgc;
for (i = 0; i < sizekgc; i++, kr++) {
MSize tp = bcread_uleb128(ls);
if (tp >= BCDUMP_KGC_STR) {
MSize len = tp - BCDUMP_KGC_STR;
const char *p = (const char *)bcread_mem(ls, len);
setgcref(*kr, obj2gco(lj_str_new(ls->L, p, len)));
} else if (tp == BCDUMP_KGC_TAB) {
setgcref(*kr, obj2gco(bcread_ktab(ls)));
#if LJ_HASFFI
} else if (tp != BCDUMP_KGC_CHILD) {
CTypeID id = tp == BCDUMP_KGC_COMPLEX ? CTID_COMPLEX_DOUBLE :
tp == BCDUMP_KGC_I64 ? CTID_INT64 : CTID_UINT64;
CTSize sz = tp == BCDUMP_KGC_COMPLEX ? 16 : 8;
GCcdata *cd = lj_cdata_new_(ls->L, id, sz);
TValue *p = (TValue *)cdataptr(cd);
setgcref(*kr, obj2gco(cd));
p[0].u32.lo = bcread_uleb128(ls);
p[0].u32.hi = bcread_uleb128(ls);
if (tp == BCDUMP_KGC_COMPLEX) {
p[1].u32.lo = bcread_uleb128(ls);
p[1].u32.hi = bcread_uleb128(ls);
}
#endif
} else {
lua_State *L = ls->L;
lua_assert(tp == BCDUMP_KGC_CHILD);
if (L->top <= bcread_oldtop(L, ls)) /* Stack underflow? */
bcread_error(ls, LJ_ERR_BCBAD);
L->top--;
setgcref(*kr, obj2gco(protoV(L->top)));
}
}
}
/* Read number constants of a prototype. */
static void bcread_knum(LexState *ls, GCproto *pt, MSize sizekn)
{
MSize i;
TValue *o = mref(pt->k, TValue);
for (i = 0; i < sizekn; i++, o++) {
int isnum = (ls->p[0] & 1);
uint32_t lo = bcread_uleb128_33(ls);
if (isnum) {
o->u32.lo = lo;
o->u32.hi = bcread_uleb128(ls);
} else {
setintV(o, lo);
}
}
}
/* Read bytecode instructions. */
static void bcread_bytecode(LexState *ls, GCproto *pt, MSize sizebc)
{
BCIns *bc = proto_bc(pt);
bc[0] = BCINS_AD((pt->flags & PROTO_VARARG) ? BC_FUNCV : BC_FUNCF,
pt->framesize, 0);
bcread_block(ls, bc+1, (sizebc-1)*(MSize)sizeof(BCIns));
/* Swap bytecode instructions if the endianess differs. */
if (bcread_swap(ls)) {
MSize i;
for (i = 1; i < sizebc; i++) bc[i] = lj_bswap(bc[i]);
}
}
/* Read upvalue refs. */
static void bcread_uv(LexState *ls, GCproto *pt, MSize sizeuv)
{
if (sizeuv) {
uint16_t *uv = proto_uv(pt);
bcread_block(ls, uv, sizeuv*2);
/* Swap upvalue refs if the endianess differs. */
if (bcread_swap(ls)) {
MSize i;
for (i = 0; i < sizeuv; i++)
uv[i] = (uint16_t)((uv[i] >> 8)|(uv[i] << 8));
}
}
}
/* Read a prototype. */
static GCproto *bcread_proto(LexState *ls)
{
GCproto *pt;
MSize framesize, numparams, flags, sizeuv, sizekgc, sizekn, sizebc, sizept;
MSize ofsk, ofsuv, ofsdbg;
MSize sizedbg = 0;
BCLine firstline = 0, numline = 0;
MSize len, startn;
/* Read length. */
if (ls->n > 0 && ls->p[0] == 0) { /* Shortcut EOF. */
ls->n--; ls->p++;
return NULL;
}
bcread_want(ls, 5);
len = bcread_uleb128(ls);
if (!len) return NULL; /* EOF */
bcread_need(ls, len);
startn = ls->n;
/* Read prototype header. */
flags = bcread_byte(ls);
numparams = bcread_byte(ls);
framesize = bcread_byte(ls);
sizeuv = bcread_byte(ls);
sizekgc = bcread_uleb128(ls);
sizekn = bcread_uleb128(ls);
sizebc = bcread_uleb128(ls) + 1;
if (!(bcread_flags(ls) & BCDUMP_F_STRIP)) {
sizedbg = bcread_uleb128(ls);
if (sizedbg) {
firstline = bcread_uleb128(ls);
numline = bcread_uleb128(ls);
}
}
/* Calculate total size of prototype including all colocated arrays. */
sizept = (MSize)sizeof(GCproto) +
sizebc*(MSize)sizeof(BCIns) +
sizekgc*(MSize)sizeof(GCRef);
sizept = (sizept + (MSize)sizeof(TValue)-1) & ~((MSize)sizeof(TValue)-1);
ofsk = sizept; sizept += sizekn*(MSize)sizeof(TValue);
ofsuv = sizept; sizept += ((sizeuv+1)&~1)*2;
ofsdbg = sizept; sizept += sizedbg;
/* Allocate prototype object and initialize its fields. */
pt = (GCproto *)lj_mem_newgco(ls->L, (MSize)sizept);
pt->gct = ~LJ_TPROTO;
pt->numparams = (uint8_t)numparams;
pt->framesize = (uint8_t)framesize;
pt->sizebc = sizebc;
setmref(pt->k, (char *)pt + ofsk);
setmref(pt->uv, (char *)pt + ofsuv);
pt->sizekgc = 0; /* Set to zero until fully initialized. */
pt->sizekn = sizekn;
pt->sizept = sizept;
pt->sizeuv = (uint8_t)sizeuv;
pt->flags = (uint8_t)flags;
pt->trace = 0;
setgcref(pt->chunkname, obj2gco(ls->chunkname));
/* Close potentially uninitialized gap between bc and kgc. */
*(uint32_t *)((char *)pt + ofsk - sizeof(GCRef)*(sizekgc+1)) = 0;
/* Read bytecode instructions and upvalue refs. */
bcread_bytecode(ls, pt, sizebc);
bcread_uv(ls, pt, sizeuv);
/* Read constants. */
bcread_kgc(ls, pt, sizekgc);
pt->sizekgc = sizekgc;
bcread_knum(ls, pt, sizekn);
/* Read and initialize debug info. */
pt->firstline = firstline;
pt->numline = numline;
if (sizedbg) {
MSize sizeli = (sizebc-1) << (numline < 256 ? 0 : numline < 65536 ? 1 : 2);
setmref(pt->lineinfo, (char *)pt + ofsdbg);
setmref(pt->uvinfo, (char *)pt + ofsdbg + sizeli);
bcread_dbg(ls, pt, sizedbg);
setmref(pt->varinfo, bcread_varinfo(pt));
} else {
setmref(pt->lineinfo, NULL);
setmref(pt->uvinfo, NULL);
setmref(pt->varinfo, NULL);
}
if (len != startn - ls->n)
bcread_error(ls, LJ_ERR_BCBAD);
return pt;
}
/* Read and check header of bytecode dump. */
static int bcread_header(LexState *ls)
{
uint32_t flags;
bcread_want(ls, 3+5+5);
if (bcread_byte(ls) != BCDUMP_HEAD2 ||
bcread_byte(ls) != BCDUMP_HEAD3 ||
bcread_byte(ls) != BCDUMP_VERSION) return 0;
bcread_flags(ls) = flags = bcread_uleb128(ls);
if ((flags & ~(BCDUMP_F_KNOWN)) != 0) return 0;
#if !LJ_HASFFI
if ((flags & BCDUMP_F_FFI)) return 0;
#endif
if ((flags & BCDUMP_F_STRIP)) {
ls->chunkname = lj_str_newz(ls->L, ls->chunkarg);
} else {
MSize len = bcread_uleb128(ls);
bcread_need(ls, len);
ls->chunkname = lj_str_new(ls->L, (const char *)bcread_mem(ls, len), len);
}
return 1; /* Ok. */
}
/* Read a bytecode dump. */
GCproto *lj_bcread(LexState *ls)
{
lua_State *L = ls->L;
lua_assert(ls->current == BCDUMP_HEAD1);
bcread_savetop(L, ls, L->top);
lj_str_resetbuf(&ls->sb);
/* Check for a valid bytecode dump header. */
if (!bcread_header(ls))
bcread_error(ls, LJ_ERR_BCFMT);
for (;;) { /* Process all prototypes in the bytecode dump. */
GCproto *pt = bcread_proto(ls);
if (!pt) break;
setprotoV(L, L->top, pt);
incr_top(L);
}
if (ls->n != 0 || L->top-1 != bcread_oldtop(L, ls))
bcread_error(ls, LJ_ERR_BCBAD);
/* Pop off last prototype. */
L->top--;
return protoV(L->top);
}

388
src/lj_bcwrite.c Normal file
View File

@ -0,0 +1,388 @@
/*
** Bytecode writer.
** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h
*/
#define lj_bcwrite_c
#define LUA_CORE
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_str.h"
#include "lj_bc.h"
#if LJ_HASFFI
#include "lj_ctype.h"
#endif
#if LJ_HASJIT
#include "lj_dispatch.h"
#include "lj_jit.h"
#endif
#include "lj_bcdump.h"
#include "lj_vm.h"
/* Context for bytecode writer. */
typedef struct BCWriteCtx {
SBuf sb; /* Output buffer. */
lua_State *L; /* Lua state. */
GCproto *pt; /* Root prototype. */
lua_Writer wfunc; /* Writer callback. */
void *wdata; /* Writer callback data. */
int strip; /* Strip debug info. */
int status; /* Status from writer callback. */
} BCWriteCtx;
/* -- Output buffer handling ---------------------------------------------- */
/* Resize buffer if needed. */
static LJ_NOINLINE void bcwrite_resize(BCWriteCtx *ctx, MSize len)
{
MSize sz = ctx->sb.sz * 2;
while (ctx->sb.n + len > sz) sz = sz * 2;
lj_str_resizebuf(ctx->L, &ctx->sb, sz);
}
/* Need a certain amount of buffer space. */
static LJ_AINLINE void bcwrite_need(BCWriteCtx *ctx, MSize len)
{
if (LJ_UNLIKELY(ctx->sb.n + len > ctx->sb.sz))
bcwrite_resize(ctx, len);
}
/* Add memory block to buffer. */
static void bcwrite_block(BCWriteCtx *ctx, const void *p, MSize len)
{
uint8_t *q = (uint8_t *)(ctx->sb.buf + ctx->sb.n);
MSize i;
ctx->sb.n += len;
for (i = 0; i < len; i++) q[i] = ((uint8_t *)p)[i];
}
/* Add byte to buffer. */
static LJ_AINLINE void bcwrite_byte(BCWriteCtx *ctx, uint8_t b)
{
ctx->sb.buf[ctx->sb.n++] = b;
}
/* Add ULEB128 value to buffer. */
static void bcwrite_uleb128(BCWriteCtx *ctx, uint32_t v)
{
MSize n = ctx->sb.n;
uint8_t *p = (uint8_t *)ctx->sb.buf;
for (; v >= 0x80; v >>= 7)
p[n++] = (uint8_t)((v & 0x7f) | 0x80);
p[n++] = (uint8_t)v;
ctx->sb.n = n;
}
/* -- Bytecode writer ----------------------------------------------------- */
/* Write a single constant key/value of a template table. */
static void bcwrite_ktabk(BCWriteCtx *ctx, cTValue *o, int narrow)
{
bcwrite_need(ctx, 1+10);
if (tvisstr(o)) {
const GCstr *str = strV(o);
MSize len = str->len;
bcwrite_need(ctx, 5+len);
bcwrite_uleb128(ctx, BCDUMP_KTAB_STR+len);
bcwrite_block(ctx, strdata(str), len);
} else if (tvisint(o)) {
bcwrite_byte(ctx, BCDUMP_KTAB_INT);
bcwrite_uleb128(ctx, intV(o));
} else if (tvisnum(o)) {
if (!LJ_DUALNUM && narrow) { /* Narrow number constants to integers. */
lua_Number num = numV(o);
int32_t k = lj_num2int(num);
if (num == (lua_Number)k) { /* -0 is never a constant. */
bcwrite_byte(ctx, BCDUMP_KTAB_INT);
bcwrite_uleb128(ctx, k);
return;
}
}
bcwrite_byte(ctx, BCDUMP_KTAB_NUM);
bcwrite_uleb128(ctx, o->u32.lo);
bcwrite_uleb128(ctx, o->u32.hi);
} else {
lua_assert(tvispri(o));
bcwrite_byte(ctx, BCDUMP_KTAB_NIL+~itype(o));
}
}
/* Write a template table. */
static void bcwrite_ktab(BCWriteCtx *ctx, const GCtab *t)
{
MSize narray = 0, nhash = 0;
if (t->asize > 0) { /* Determine max. length of array part. */
ptrdiff_t i;
TValue *array = tvref(t->array);
for (i = (ptrdiff_t)t->asize-1; i >= 0; i--)
if (!tvisnil(&array[i]))
break;
narray = (MSize)(i+1);
}
if (t->hmask > 0) { /* Count number of used hash slots. */
MSize i, hmask = t->hmask;
Node *node = noderef(t->node);
for (i = 0; i <= hmask; i++)
nhash += !tvisnil(&node[i].val);
}
/* Write number of array slots and hash slots. */
bcwrite_uleb128(ctx, narray);
bcwrite_uleb128(ctx, nhash);
if (narray) { /* Write array entries (may contain nil). */
MSize i;
TValue *o = tvref(t->array);
for (i = 0; i < narray; i++, o++)
bcwrite_ktabk(ctx, o, 1);
}
if (nhash) { /* Write hash entries. */
MSize i = nhash;
Node *node = noderef(t->node) + t->hmask;
for (;; node--)
if (!tvisnil(&node->val)) {
bcwrite_ktabk(ctx, &node->key, 0);
bcwrite_ktabk(ctx, &node->val, 1);
if (--i == 0) break;
}
}
}
/* Write GC constants of a prototype. */
static void bcwrite_kgc(BCWriteCtx *ctx, GCproto *pt)
{
MSize i, sizekgc = pt->sizekgc;
GCRef *kr = mref(pt->k, GCRef) - (ptrdiff_t)sizekgc;
for (i = 0; i < sizekgc; i++, kr++) {
GCobj *o = gcref(*kr);
MSize tp, need = 1;
/* Determine constant type and needed size. */
if (o->gch.gct == ~LJ_TSTR) {
tp = BCDUMP_KGC_STR + gco2str(o)->len;
need = 5+gco2str(o)->len;
} else if (o->gch.gct == ~LJ_TPROTO) {
lua_assert((pt->flags & PROTO_CHILD));
tp = BCDUMP_KGC_CHILD;
#if LJ_HASFFI
} else if (o->gch.gct == ~LJ_TCDATA) {
CTypeID id = gco2cd(o)->typeid;
need = 1+4*5;
if (id == CTID_INT64) {
tp = BCDUMP_KGC_I64;
} else if (id == CTID_UINT64) {
tp = BCDUMP_KGC_U64;
} else {
lua_assert(id == CTID_COMPLEX_DOUBLE);
tp = BCDUMP_KGC_COMPLEX;
}
#endif
} else {
lua_assert(o->gch.gct == ~LJ_TTAB);
tp = BCDUMP_KGC_TAB;
}
/* Write constant type. */
bcwrite_need(ctx, need);
bcwrite_uleb128(ctx, tp);
/* Write constant data (if any). */
if (tp >= BCDUMP_KGC_STR) {
bcwrite_block(ctx, strdata(gco2str(o)), gco2str(o)->len);
} else if (tp == BCDUMP_KGC_TAB) {
bcwrite_ktab(ctx, gco2tab(o));
#if LJ_HASFFI
} else if (tp != BCDUMP_KGC_CHILD) {
cTValue *p = (TValue *)cdataptr(gco2cd(o));
bcwrite_uleb128(ctx, p[0].u32.lo);
bcwrite_uleb128(ctx, p[0].u32.hi);
if (tp == BCDUMP_KGC_COMPLEX) {
bcwrite_uleb128(ctx, p[1].u32.lo);
bcwrite_uleb128(ctx, p[1].u32.hi);
}
#endif
}
}
}
/* Write number constants of a prototype. */
static void bcwrite_knum(BCWriteCtx *ctx, GCproto *pt)
{
MSize i, sizekn = pt->sizekn;
cTValue *o = mref(pt->k, TValue);
bcwrite_need(ctx, 10*sizekn);
for (i = 0; i < sizekn; i++, o++) {
int32_t k;
if (tvisint(o)) {
k = intV(o);
goto save_int;
} else {
/* Write a 33 bit ULEB128 for the int (lsb=0) or loword (lsb=1). */
if (!LJ_DUALNUM) { /* Narrow number constants to integers. */
lua_Number num = numV(o);
k = lj_num2int(num);
if (num == (lua_Number)k) { /* -0 is never a constant. */
save_int:
bcwrite_uleb128(ctx, 2*(uint32_t)k);
if (k < 0) ctx->sb.buf[ctx->sb.n-1] |= 0x10;
continue;
}
}
bcwrite_uleb128(ctx, 1+2*o->u32.lo);
if (o->u32.lo >= 0x80000000u) ctx->sb.buf[ctx->sb.n-1] |= 0x10;
bcwrite_uleb128(ctx, o->u32.hi);
}
}
}
/* Write bytecode instructions. */
static void bcwrite_bytecode(BCWriteCtx *ctx, GCproto *pt)
{
MSize nbc = pt->sizebc-1; /* Omit the [JI]FUNC* header. */
#if LJ_HASJIT
uint8_t *p = (uint8_t *)&ctx->sb.buf[ctx->sb.n];
#endif
bcwrite_block(ctx, proto_bc(pt)+1, nbc*(MSize)sizeof(BCIns));
#if LJ_HASJIT
/* Unpatch modified bytecode containing ILOOP/JLOOP etc. */
if ((pt->flags & PROTO_ILOOP) || pt->trace) {
jit_State *J = L2J(ctx->L);
MSize i;
for (i = 0; i < nbc; i++, p += sizeof(BCIns)) {
BCOp op = (BCOp)p[LJ_ENDIAN_SELECT(0, 3)];
if (op == BC_IFORL || op == BC_IITERL || op == BC_ILOOP ||
op == BC_JFORI) {
p[LJ_ENDIAN_SELECT(0, 3)] = (uint8_t)(op-BC_IFORL+BC_FORL);
} else if (op == BC_JFORL || op == BC_JITERL || op == BC_JLOOP) {
BCReg rd = p[LJ_ENDIAN_SELECT(2, 1)] + (p[LJ_ENDIAN_SELECT(3, 0)] << 8);
BCIns ins = traceref(J, rd)->startins;
p[LJ_ENDIAN_SELECT(0, 3)] = (uint8_t)(op-BC_JFORL+BC_FORL);
p[LJ_ENDIAN_SELECT(2, 1)] = bc_c(ins);
p[LJ_ENDIAN_SELECT(3, 0)] = bc_b(ins);
}
}
}
#endif
}
/* Write prototype. */
static void bcwrite_proto(BCWriteCtx *ctx, GCproto *pt)
{
MSize sizedbg = 0;
/* Recursively write children of prototype. */
if ((pt->flags & PROTO_CHILD)) {
ptrdiff_t i, n = pt->sizekgc;
GCRef *kr = mref(pt->k, GCRef) - 1;
for (i = 0; i < n; i++, kr--) {
GCobj *o = gcref(*kr);
if (o->gch.gct == ~LJ_TPROTO)
bcwrite_proto(ctx, gco2pt(o));
}
}
/* Start writing the prototype info to a buffer. */
lj_str_resetbuf(&ctx->sb);
ctx->sb.n = 5; /* Leave room for final size. */
bcwrite_need(ctx, 4+6*5+(pt->sizebc-1)*(MSize)sizeof(BCIns)+pt->sizeuv*2);
/* Write prototype header. */
bcwrite_byte(ctx, (pt->flags & (PROTO_CHILD|PROTO_VARARG|PROTO_FFI)));
bcwrite_byte(ctx, pt->numparams);
bcwrite_byte(ctx, pt->framesize);
bcwrite_byte(ctx, pt->sizeuv);
bcwrite_uleb128(ctx, pt->sizekgc);
bcwrite_uleb128(ctx, pt->sizekn);
bcwrite_uleb128(ctx, pt->sizebc-1);
if (!ctx->strip) {
sizedbg = pt->sizept - (MSize)((char *)proto_lineinfo(pt) - (char *)pt);
bcwrite_uleb128(ctx, sizedbg);
if (sizedbg) {
bcwrite_uleb128(ctx, pt->firstline);
bcwrite_uleb128(ctx, pt->numline);
}
}
/* Write bytecode instructions and upvalue refs. */
bcwrite_bytecode(ctx, pt);
bcwrite_block(ctx, proto_uv(pt), pt->sizeuv*2);
/* Write constants. */
bcwrite_kgc(ctx, pt);
bcwrite_knum(ctx, pt);
/* Write debug info, if not stripped. */
if (sizedbg) {
bcwrite_need(ctx, sizedbg);
bcwrite_block(ctx, proto_lineinfo(pt), sizedbg);
}
/* Pass buffer to writer function. */
if (ctx->status == 0) {
MSize n = ctx->sb.n - 5;
MSize nn = 1 + lj_fls(n)/7;
ctx->sb.n = 5 - nn;
bcwrite_uleb128(ctx, n); /* Fill in final size. */
lua_assert(ctx->sb.n == 5);
ctx->status = ctx->wfunc(ctx->L, ctx->sb.buf+5-nn, nn+n, ctx->wdata);
}
}
/* Write header of bytecode dump. */
static void bcwrite_header(BCWriteCtx *ctx)
{
GCstr *chunkname = proto_chunkname(ctx->pt);
const char *name = strdata(chunkname);
MSize len = chunkname->len;
lj_str_resetbuf(&ctx->sb);
bcwrite_need(ctx, 5+5+len);
bcwrite_byte(ctx, BCDUMP_HEAD1);
bcwrite_byte(ctx, BCDUMP_HEAD2);
bcwrite_byte(ctx, BCDUMP_HEAD3);
bcwrite_byte(ctx, BCDUMP_VERSION);
bcwrite_byte(ctx, (ctx->strip ? BCDUMP_F_STRIP : 0) +
(LJ_BE ? BCDUMP_F_BE : 0) +
((ctx->pt->flags & PROTO_FFI) ? BCDUMP_F_FFI : 0));
if (!ctx->strip) {
bcwrite_uleb128(ctx, len);
bcwrite_block(ctx, name, len);
}
ctx->status = ctx->wfunc(ctx->L, ctx->sb.buf, ctx->sb.n, ctx->wdata);
}
/* Write footer of bytecode dump. */
static void bcwrite_footer(BCWriteCtx *ctx)
{
if (ctx->status == 0) {
uint8_t zero = 0;
ctx->status = ctx->wfunc(ctx->L, &zero, 1, ctx->wdata);
}
}
/* Protected callback for bytecode writer. */
static TValue *cpwriter(lua_State *L, lua_CFunction dummy, void *ud)
{
BCWriteCtx *ctx = (BCWriteCtx *)ud;
UNUSED(dummy);
lj_str_resizebuf(L, &ctx->sb, 1024); /* Avoids resize for most prototypes. */
bcwrite_header(ctx);
bcwrite_proto(ctx, ctx->pt);
bcwrite_footer(ctx);
return NULL;
}
/* Write bytecode for a prototype. */
int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, void *data,
int strip)
{
BCWriteCtx ctx;
int status;
ctx.L = L;
ctx.pt = pt;
ctx.wfunc = writer;
ctx.wdata = data;
ctx.strip = strip;
ctx.status = 0;
lj_str_initbuf(&ctx.sb);
status = lj_vm_cpcall(L, NULL, &ctx, cpwriter);
if (status == 0) status = ctx.status;
lj_str_freebuf(G(ctx.L), &ctx.sb);
return status;
}

View File

@ -84,7 +84,7 @@ ERRDEF(IOCLFL, "attempt to use a closed file")
ERRDEF(IOSTDCL, "standard file is closed")
ERRDEF(OSUNIQF, "unable to generate a unique filename")
ERRDEF(OSDATEF, "field " LUA_QS " missing in date table")
ERRDEF(STRDUMP, "cannot dump functions")
ERRDEF(STRDUMP, "unable to dump given function")
ERRDEF(STRSLC, "string slice too long")
ERRDEF(STRPATB, "missing " LUA_QL("[") " after " LUA_QL("%f") " in pattern")
ERRDEF(STRPATC, "invalid pattern capture")
@ -119,7 +119,6 @@ ERRDEF(XLCOM, "unfinished long comment")
ERRDEF(XSTR, "unfinished string")
ERRDEF(XESC, "invalid escape sequence")
ERRDEF(XLDELIM, "invalid long string delimiter")
ERRDEF(XBCLOAD, "cannot load Lua bytecode")
ERRDEF(XTOKEN, LUA_QS " expected")
ERRDEF(XJUMP, "control structure too long")
ERRDEF(XSLOTS, "function or expression too complex")
@ -137,6 +136,10 @@ ERRDEF(XSYNTAX, "syntax error")
ERRDEF(XBREAK, "no loop to break")
ERRDEF(XFOR, LUA_QL("=") " or " LUA_QL("in") " expected")
/* Bytecode reader errors. */
ERRDEF(BCFMT, "cannot load incompatible bytecode")
ERRDEF(BCBAD, "cannot load malformed bytecode")
#if LJ_HASFFI
/* FFI errors. */
ERRDEF(FFI_INVTYPE, "invalid C type")

View File

@ -65,6 +65,17 @@ static GCupval *func_finduv(lua_State *L, TValue *slot)
return uv;
}
/* Create an empty and closed upvalue. */
static GCupval *func_emptyuv(lua_State *L)
{
GCupval *uv = (GCupval *)lj_mem_newgco(L, sizeof(GCupval));
uv->gct = ~LJ_TUPVAL;
uv->closed = 1;
setnilV(&uv->tv);
setmref(uv->v, &uv->tv);
return uv;
}
/* Close all open upvalues pointing to some stack level or above. */
void LJ_FASTCALL lj_func_closeuv(lua_State *L, TValue *level)
{
@ -105,30 +116,45 @@ GCfunc *lj_func_newC(lua_State *L, MSize nelems, GCtab *env)
return fn;
}
GCfunc *lj_func_newL(lua_State *L, GCproto *pt, GCtab *env)
static GCfunc *func_newL(lua_State *L, GCproto *pt, GCtab *env)
{
GCfunc *fn = (GCfunc *)lj_mem_newgco(L, sizeLfunc((MSize)pt->sizeuv));
fn->l.gct = ~LJ_TFUNC;
fn->l.ffid = FF_LUA;
fn->l.nupvalues = (uint8_t)pt->sizeuv;
fn->l.nupvalues = 0; /* Set to zero until upvalues are initialized. */
/* NOBARRIER: Really a setgcref. But the GCfunc is new (marked white). */
setmref(fn->l.pc, proto_bc(pt));
setgcref(fn->l.env, obj2gco(env));
return fn;
}
/* Create a new Lua function with empty upvalues. */
GCfunc *lj_func_newL_empty(lua_State *L, GCproto *pt, GCtab *env)
{
GCfunc *fn = func_newL(L, pt, env);
MSize i, nuv = pt->sizeuv;
/* NOBARRIER: The GCfunc is new (marked white). */
for (i = 0; i < nuv; i++) {
GCupval *uv = func_emptyuv(L);
uv->dhash = (uint32_t)(uintptr_t)pt ^ ((uint32_t)proto_uv(pt)[i] << 24);
setgcref(fn->l.uvptr[i], obj2gco(uv));
}
fn->l.nupvalues = (uint8_t)nuv;
return fn;
}
/* Do a GC check and create a new Lua function with inherited upvalues. */
GCfunc *lj_func_newL_gc(lua_State *L, GCproto *pt, GCfuncL *parent)
{
GCfunc *fn;
GCRef *puv;
uint32_t i, nuv;
MSize i, nuv;
TValue *base;
lj_gc_check_fixtop(L);
fn = lj_func_newL(L, pt, tabref(parent->env));
fn = func_newL(L, pt, tabref(parent->env));
/* NOBARRIER: The GCfunc is new (marked white). */
puv = parent->uvptr;
nuv = fn->l.nupvalues;
nuv = pt->sizeuv;
base = L->base;
for (i = 0; i < nuv; i++) {
uint32_t v = proto_uv(pt)[i];
@ -141,6 +167,7 @@ GCfunc *lj_func_newL_gc(lua_State *L, GCproto *pt, GCfuncL *parent)
}
setgcref(fn->l.uvptr[i], obj2gco(uv));
}
fn->l.nupvalues = (uint8_t)nuv;
return fn;
}

View File

@ -17,7 +17,7 @@ LJ_FUNC void LJ_FASTCALL lj_func_freeuv(global_State *g, GCupval *uv);
/* Functions (closures). */
LJ_FUNC GCfunc *lj_func_newC(lua_State *L, MSize nelems, GCtab *env);
LJ_FUNC GCfunc *lj_func_newL(lua_State *L, GCproto *pt, GCtab *env);
LJ_FUNC GCfunc *lj_func_newL_empty(lua_State *L, GCproto *pt, GCtab *env);
LJ_FUNCA GCfunc *lj_func_newL_gc(lua_State *L, GCproto *pt, GCfuncL *parent);
LJ_FUNC void LJ_FASTCALL lj_func_free(global_State *g, GCfunc *c);

View File

@ -204,7 +204,7 @@ static void gc_traverse_func(global_State *g, GCfunc *fn)
gc_markobj(g, tabref(fn->c.env));
if (isluafunc(fn)) {
uint32_t i;
lua_assert(fn->l.nupvalues == funcproto(fn)->sizeuv);
lua_assert(fn->l.nupvalues <= funcproto(fn)->sizeuv);
gc_markobj(g, funcproto(fn));
for (i = 0; i < fn->l.nupvalues; i++) /* Mark Lua function upvalues. */
gc_markobj(g, &gcref(fn->l.uvptr[i])->uv);

View File

@ -408,7 +408,7 @@ static int llex(LexState *ls, TValue *tv)
/* -- Lexer API ----------------------------------------------------------- */
/* Setup lexer state. */
void lj_lex_setup(lua_State *L, LexState *ls)
int lj_lex_setup(lua_State *L, LexState *ls)
{
ls->L = L;
ls->fs = NULL;
@ -433,14 +433,11 @@ void lj_lex_setup(lua_State *L, LexState *ls)
if (ls->current == '#') { /* Skip POSIX #! header line. */
do {
next(ls);
if (ls->current == END_OF_STREAM) return;
if (ls->current == END_OF_STREAM) return 0;
} while (!currIsNewline(ls));
inclinenumber(ls);
}
if (ls->current == LUA_SIGNATURE[0]) {
setstrV(L, L->top++, lj_err_str(L, LJ_ERR_XBCLOAD));
lj_err_throw(L, LUA_ERRSYNTAX);
}
return (ls->current == LUA_SIGNATURE[0]); /* Bytecode dump? */
}
/* Cleanup lexer state. */

View File

@ -71,7 +71,7 @@ typedef struct LexState {
uint32_t level; /* Syntactical nesting level. */
} LexState;
LJ_FUNC void lj_lex_setup(lua_State *L, LexState *ls);
LJ_FUNC int lj_lex_setup(lua_State *L, LexState *ls);
LJ_FUNC void lj_lex_cleanup(lua_State *L, LexState *ls);
LJ_FUNC void lj_lex_next(LexState *ls);
LJ_FUNC LexToken lj_lex_lookahead(LexState *ls);

View File

@ -310,11 +310,11 @@ typedef struct GCproto {
} GCproto;
/* Flags for prototype. */
#define PROTO_VARARG 0x01 /* Vararg function. */
#define PROTO_CHILD 0x02 /* Has child prototypes. */
#define PROTO_NOJIT 0x04 /* JIT disabled for this function. */
#define PROTO_ILOOP 0x08 /* Patched bytecode with ILOOP etc. */
#define PROTO_FFI 0x10 /* Uses BC_KCDATA for FFI datatypes. */
#define PROTO_CHILD 0x01 /* Has child prototypes. */
#define PROTO_VARARG 0x02 /* Vararg function. */
#define PROTO_FFI 0x04 /* Uses BC_KCDATA for FFI datatypes. */
#define PROTO_NOJIT 0x08 /* JIT disabled for this function. */
#define PROTO_ILOOP 0x10 /* Patched bytecode with ILOOP etc. */
/* Only used during parsing. */
#define PROTO_HAS_RETURN 0x20 /* Already emitted a return. */
#define PROTO_FIXUP_RETURN 0x40 /* Need to fixup emitted returns. */

View File

@ -46,6 +46,8 @@
#include "lj_api.c"
#include "lj_lex.c"
#include "lj_parse.c"
#include "lj_bcread.c"
#include "lj_bcwrite.c"
#include "lj_ctype.c"
#include "lj_cdata.c"
#include "lj_cconv.c"