mirror of
https://github.com/LuaJIT/LuaJIT.git
synced 2025-02-07 23:24:09 +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).
|
(no per-coroutine hooks, no tail call counting).
|
||||||
</li>
|
</li>
|
||||||
<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:
|
Some of the <b>configuration options</b> of Lua 5.1 are not supported:
|
||||||
<ul>
|
<ul>
|
||||||
<li>The <b>number type</b> cannot be changed (it's always a <tt>double</tt>).</li>
|
<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 \
|
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_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_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_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_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 \
|
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
|
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 \
|
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_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 \
|
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_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_lib.h \
|
||||||
lj_libdef.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_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_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_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_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_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 \
|
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_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_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_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_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_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
|
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_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_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_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_vmevent.h lj_vmmath.c lj_api.c lj_bcdump.h lj_parse.h lj_lex.c \
|
||||||
lj_parse.c lj_ctype.c lj_cdata.c lj_cconv.h lj_cconv.c lj_ccall.c \
|
lualib.h lj_parse.c lj_bcread.c lj_bcwrite.c lj_ctype.c lj_cdata.c \
|
||||||
lj_ccall.h lj_carith.c lj_carith.h lj_clib.c lj_clib.h lj_cparse.c \
|
lj_cconv.h lj_cconv.c lj_ccall.c lj_ccall.h lj_carith.c lj_carith.h \
|
||||||
lj_cparse.h lj_lib.c lj_lib.h lj_ir.c lj_ircall.h lj_iropt.h \
|
lj_clib.c lj_clib.h lj_cparse.c lj_cparse.h lj_lib.c lj_lib.h lj_ir.c \
|
||||||
lj_opt_mem.c lj_opt_fold.c lj_folddef.h lj_opt_narrow.c lj_opt_dce.c \
|
lj_ircall.h lj_iropt.h lj_opt_mem.c lj_opt_fold.c lj_folddef.h \
|
||||||
lj_opt_loop.c lj_snap.h lj_opt_split.c lj_mcode.c lj_mcode.h lj_snap.c \
|
lj_opt_narrow.c lj_opt_dce.c lj_opt_loop.c lj_snap.h lj_opt_split.c \
|
||||||
lj_target.h lj_target_*.h lj_record.c lj_record.h lj_ffrecord.h \
|
lj_mcode.c lj_mcode.h lj_snap.c lj_target.h lj_target_*.h lj_record.c \
|
||||||
lj_crecord.c lj_crecord.h lj_ffrecord.c lj_recdef.h lj_asm.c lj_asm.h \
|
lj_record.h lj_ffrecord.h lj_crecord.c lj_crecord.h lj_ffrecord.c \
|
||||||
lj_emit_*.h lj_asm_*.h lj_trace.c lj_gdbjit.h lj_gdbjit.c lj_alloc.c \
|
lj_recdef.h lj_asm.c lj_asm.h lj_emit_*.h lj_asm_*.h lj_trace.c \
|
||||||
lib_aux.c lib_base.c lj_libdef.h lib_math.c lib_string.c lib_table.c \
|
lj_gdbjit.h lj_gdbjit.c lj_alloc.c lib_aux.c lib_base.c lj_libdef.h \
|
||||||
lib_io.c lib_os.c lib_package.c lib_debug.c lib_bit.c lib_jit.c \
|
lib_math.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c \
|
||||||
lib_ffi.c lib_init.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
|
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_tab.h"
|
||||||
#include "lj_state.h"
|
#include "lj_state.h"
|
||||||
#include "lj_ff.h"
|
#include "lj_ff.h"
|
||||||
|
#include "lj_bcdump.h"
|
||||||
#include "lj_char.h"
|
#include "lj_char.h"
|
||||||
#include "lj_lib.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)
|
LJLIB_CF(string_dump)
|
||||||
{
|
{
|
||||||
|
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);
|
lj_err_caller(L, LJ_ERR_STRDUMP);
|
||||||
return 0; /* unreachable */
|
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_trace.h"
|
||||||
#include "lj_vm.h"
|
#include "lj_vm.h"
|
||||||
#include "lj_lex.h"
|
#include "lj_lex.h"
|
||||||
|
#include "lj_bcdump.h"
|
||||||
#include "lj_parse.h"
|
#include "lj_parse.h"
|
||||||
|
|
||||||
/* -- Common helper functions --------------------------------------------- */
|
/* -- 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)
|
static TValue *cpparser(lua_State *L, lua_CFunction dummy, void *ud)
|
||||||
{
|
{
|
||||||
LexState *ls = (LexState *)ud;
|
LexState *ls = (LexState *)ud;
|
||||||
|
GCproto *pt;
|
||||||
GCfunc *fn;
|
GCfunc *fn;
|
||||||
UNUSED(dummy);
|
UNUSED(dummy);
|
||||||
cframe_errfunc(L->cframe) = -1; /* Inherit error function. */
|
cframe_errfunc(L->cframe) = -1; /* Inherit error function. */
|
||||||
lj_lex_setup(L, ls);
|
pt = lj_lex_setup(L, ls) ? lj_bcread(ls) : lj_parse(ls);
|
||||||
fn = lj_func_newL(L, lj_parse(ls), tabref(L->env));
|
fn = lj_func_newL_empty(L, pt, tabref(L->env));
|
||||||
/* Parser may realloc stack. Don't combine above/below into one statement. */
|
/* Don't combine above/below into one statement. */
|
||||||
setfuncV(L, L->top++, fn);
|
setfuncV(L, L->top++, fn);
|
||||||
return NULL;
|
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)
|
LUA_API int lua_dump(lua_State *L, lua_Writer writer, void *data)
|
||||||
{
|
{
|
||||||
|
cTValue *o = L->top-1;
|
||||||
api_checknelems(L, 1);
|
api_checknelems(L, 1);
|
||||||
UNUSED(L); UNUSED(writer); UNUSED(data);
|
if (tvisfunc(o) && isluafunc(funcV(o)))
|
||||||
return 1; /* Error, not supported. */
|
return lj_bcwrite(L, funcproto(funcV(o)), writer, data, 0);
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- GC and memory management -------------------------------------------- */
|
/* -- 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(IOSTDCL, "standard file is closed")
|
||||||
ERRDEF(OSUNIQF, "unable to generate a unique filename")
|
ERRDEF(OSUNIQF, "unable to generate a unique filename")
|
||||||
ERRDEF(OSDATEF, "field " LUA_QS " missing in date table")
|
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(STRSLC, "string slice too long")
|
||||||
ERRDEF(STRPATB, "missing " LUA_QL("[") " after " LUA_QL("%f") " in pattern")
|
ERRDEF(STRPATB, "missing " LUA_QL("[") " after " LUA_QL("%f") " in pattern")
|
||||||
ERRDEF(STRPATC, "invalid pattern capture")
|
ERRDEF(STRPATC, "invalid pattern capture")
|
||||||
@ -119,7 +119,6 @@ ERRDEF(XLCOM, "unfinished long comment")
|
|||||||
ERRDEF(XSTR, "unfinished string")
|
ERRDEF(XSTR, "unfinished string")
|
||||||
ERRDEF(XESC, "invalid escape sequence")
|
ERRDEF(XESC, "invalid escape sequence")
|
||||||
ERRDEF(XLDELIM, "invalid long string delimiter")
|
ERRDEF(XLDELIM, "invalid long string delimiter")
|
||||||
ERRDEF(XBCLOAD, "cannot load Lua bytecode")
|
|
||||||
ERRDEF(XTOKEN, LUA_QS " expected")
|
ERRDEF(XTOKEN, LUA_QS " expected")
|
||||||
ERRDEF(XJUMP, "control structure too long")
|
ERRDEF(XJUMP, "control structure too long")
|
||||||
ERRDEF(XSLOTS, "function or expression too complex")
|
ERRDEF(XSLOTS, "function or expression too complex")
|
||||||
@ -137,6 +136,10 @@ ERRDEF(XSYNTAX, "syntax error")
|
|||||||
ERRDEF(XBREAK, "no loop to break")
|
ERRDEF(XBREAK, "no loop to break")
|
||||||
ERRDEF(XFOR, LUA_QL("=") " or " LUA_QL("in") " expected")
|
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
|
#if LJ_HASFFI
|
||||||
/* FFI errors. */
|
/* FFI errors. */
|
||||||
ERRDEF(FFI_INVTYPE, "invalid C type")
|
ERRDEF(FFI_INVTYPE, "invalid C type")
|
||||||
|
@ -65,6 +65,17 @@ static GCupval *func_finduv(lua_State *L, TValue *slot)
|
|||||||
return uv;
|
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. */
|
/* Close all open upvalues pointing to some stack level or above. */
|
||||||
void LJ_FASTCALL lj_func_closeuv(lua_State *L, TValue *level)
|
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;
|
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));
|
GCfunc *fn = (GCfunc *)lj_mem_newgco(L, sizeLfunc((MSize)pt->sizeuv));
|
||||||
fn->l.gct = ~LJ_TFUNC;
|
fn->l.gct = ~LJ_TFUNC;
|
||||||
fn->l.ffid = FF_LUA;
|
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). */
|
/* NOBARRIER: Really a setgcref. But the GCfunc is new (marked white). */
|
||||||
setmref(fn->l.pc, proto_bc(pt));
|
setmref(fn->l.pc, proto_bc(pt));
|
||||||
setgcref(fn->l.env, obj2gco(env));
|
setgcref(fn->l.env, obj2gco(env));
|
||||||
return fn;
|
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. */
|
/* 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 *lj_func_newL_gc(lua_State *L, GCproto *pt, GCfuncL *parent)
|
||||||
{
|
{
|
||||||
GCfunc *fn;
|
GCfunc *fn;
|
||||||
GCRef *puv;
|
GCRef *puv;
|
||||||
uint32_t i, nuv;
|
MSize i, nuv;
|
||||||
TValue *base;
|
TValue *base;
|
||||||
lj_gc_check_fixtop(L);
|
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). */
|
/* NOBARRIER: The GCfunc is new (marked white). */
|
||||||
puv = parent->uvptr;
|
puv = parent->uvptr;
|
||||||
nuv = fn->l.nupvalues;
|
nuv = pt->sizeuv;
|
||||||
base = L->base;
|
base = L->base;
|
||||||
for (i = 0; i < nuv; i++) {
|
for (i = 0; i < nuv; i++) {
|
||||||
uint32_t v = proto_uv(pt)[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));
|
setgcref(fn->l.uvptr[i], obj2gco(uv));
|
||||||
}
|
}
|
||||||
|
fn->l.nupvalues = (uint8_t)nuv;
|
||||||
return fn;
|
return fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ LJ_FUNC void LJ_FASTCALL lj_func_freeuv(global_State *g, GCupval *uv);
|
|||||||
|
|
||||||
/* Functions (closures). */
|
/* Functions (closures). */
|
||||||
LJ_FUNC GCfunc *lj_func_newC(lua_State *L, MSize nelems, GCtab *env);
|
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_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);
|
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));
|
gc_markobj(g, tabref(fn->c.env));
|
||||||
if (isluafunc(fn)) {
|
if (isluafunc(fn)) {
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
lua_assert(fn->l.nupvalues == funcproto(fn)->sizeuv);
|
lua_assert(fn->l.nupvalues <= funcproto(fn)->sizeuv);
|
||||||
gc_markobj(g, funcproto(fn));
|
gc_markobj(g, funcproto(fn));
|
||||||
for (i = 0; i < fn->l.nupvalues; i++) /* Mark Lua function upvalues. */
|
for (i = 0; i < fn->l.nupvalues; i++) /* Mark Lua function upvalues. */
|
||||||
gc_markobj(g, &gcref(fn->l.uvptr[i])->uv);
|
gc_markobj(g, &gcref(fn->l.uvptr[i])->uv);
|
||||||
|
@ -408,7 +408,7 @@ static int llex(LexState *ls, TValue *tv)
|
|||||||
/* -- Lexer API ----------------------------------------------------------- */
|
/* -- Lexer API ----------------------------------------------------------- */
|
||||||
|
|
||||||
/* Setup lexer state. */
|
/* 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->L = L;
|
||||||
ls->fs = NULL;
|
ls->fs = NULL;
|
||||||
@ -433,14 +433,11 @@ void lj_lex_setup(lua_State *L, LexState *ls)
|
|||||||
if (ls->current == '#') { /* Skip POSIX #! header line. */
|
if (ls->current == '#') { /* Skip POSIX #! header line. */
|
||||||
do {
|
do {
|
||||||
next(ls);
|
next(ls);
|
||||||
if (ls->current == END_OF_STREAM) return;
|
if (ls->current == END_OF_STREAM) return 0;
|
||||||
} while (!currIsNewline(ls));
|
} while (!currIsNewline(ls));
|
||||||
inclinenumber(ls);
|
inclinenumber(ls);
|
||||||
}
|
}
|
||||||
if (ls->current == LUA_SIGNATURE[0]) {
|
return (ls->current == LUA_SIGNATURE[0]); /* Bytecode dump? */
|
||||||
setstrV(L, L->top++, lj_err_str(L, LJ_ERR_XBCLOAD));
|
|
||||||
lj_err_throw(L, LUA_ERRSYNTAX);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cleanup lexer state. */
|
/* Cleanup lexer state. */
|
||||||
|
@ -71,7 +71,7 @@ typedef struct LexState {
|
|||||||
uint32_t level; /* Syntactical nesting level. */
|
uint32_t level; /* Syntactical nesting level. */
|
||||||
} LexState;
|
} 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_cleanup(lua_State *L, LexState *ls);
|
||||||
LJ_FUNC void lj_lex_next(LexState *ls);
|
LJ_FUNC void lj_lex_next(LexState *ls);
|
||||||
LJ_FUNC LexToken lj_lex_lookahead(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;
|
} GCproto;
|
||||||
|
|
||||||
/* Flags for prototype. */
|
/* Flags for prototype. */
|
||||||
#define PROTO_VARARG 0x01 /* Vararg function. */
|
#define PROTO_CHILD 0x01 /* Has child prototypes. */
|
||||||
#define PROTO_CHILD 0x02 /* Has child prototypes. */
|
#define PROTO_VARARG 0x02 /* Vararg function. */
|
||||||
#define PROTO_NOJIT 0x04 /* JIT disabled for this function. */
|
#define PROTO_FFI 0x04 /* Uses BC_KCDATA for FFI datatypes. */
|
||||||
#define PROTO_ILOOP 0x08 /* Patched bytecode with ILOOP etc. */
|
#define PROTO_NOJIT 0x08 /* JIT disabled for this function. */
|
||||||
#define PROTO_FFI 0x10 /* Uses BC_KCDATA for FFI datatypes. */
|
#define PROTO_ILOOP 0x10 /* Patched bytecode with ILOOP etc. */
|
||||||
/* Only used during parsing. */
|
/* Only used during parsing. */
|
||||||
#define PROTO_HAS_RETURN 0x20 /* Already emitted a return. */
|
#define PROTO_HAS_RETURN 0x20 /* Already emitted a return. */
|
||||||
#define PROTO_FIXUP_RETURN 0x40 /* Need to fixup emitted returns. */
|
#define PROTO_FIXUP_RETURN 0x40 /* Need to fixup emitted returns. */
|
||||||
|
@ -46,6 +46,8 @@
|
|||||||
#include "lj_api.c"
|
#include "lj_api.c"
|
||||||
#include "lj_lex.c"
|
#include "lj_lex.c"
|
||||||
#include "lj_parse.c"
|
#include "lj_parse.c"
|
||||||
|
#include "lj_bcread.c"
|
||||||
|
#include "lj_bcwrite.c"
|
||||||
#include "lj_ctype.c"
|
#include "lj_ctype.c"
|
||||||
#include "lj_cdata.c"
|
#include "lj_cdata.c"
|
||||||
#include "lj_cconv.c"
|
#include "lj_cconv.c"
|
||||||
|
Loading…
Reference in New Issue
Block a user