mirror of
https://github.com/LuaJIT/LuaJIT.git
synced 2025-02-07 15:14:08 +00:00
Add support for bytecode loading/saving.
This commit is contained in:
parent
9da94d1355
commit
4994fcc32c
@ -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 5.1 — loading foreign
|
||||
bytecode is not supported at all.
|
||||
</li>
|
||||
<li>
|
||||
Some of the <b>configuration options</b> of Lua 5.1 are not supported:
|
||||
<ul>
|
||||
<li>The <b>number type</b> cannot be changed (it's always a <tt>double</tt>).</li>
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
15
src/lj_api.c
15
src/lj_api.c
@ -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
66
src/lj_bcdump.h
Normal 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
466
src/lj_bcread.c
Normal 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
388
src/lj_bcwrite.c
Normal 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;
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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. */
|
||||
|
@ -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);
|
||||
|
10
src/lj_obj.h
10
src/lj_obj.h
@ -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. */
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user