aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pall <mike>2011-06-13 00:58:13 +0200
committerMike Pall <mike>2011-06-13 01:04:11 +0200
commit4994fcc32caa90eb25e9e7532c5ed195abb4bb95 (patch)
treed1741d1b9e61c10145775ec805639c389b7ef2a8
parent9da94d135535c607d71a5d7e902b561ee418f0ca (diff)
downloadluajit-4994fcc32caa90eb25e9e7532c5ed195abb4bb95.tar.gz
luajit-4994fcc32caa90eb25e9e7532c5ed195abb4bb95.tar.bz2
luajit-4994fcc32caa90eb25e9e7532c5ed195abb4bb95.zip
Add support for bytecode loading/saving.
-rw-r--r--doc/status.html5
-rw-r--r--src/Makefile2
-rw-r--r--src/Makefile.dep35
-rw-r--r--src/lib_string.c19
-rw-r--r--src/lj_api.c15
-rw-r--r--src/lj_bcdump.h66
-rw-r--r--src/lj_bcread.c466
-rw-r--r--src/lj_bcwrite.c388
-rw-r--r--src/lj_errmsg.h7
-rw-r--r--src/lj_func.c37
-rw-r--r--src/lj_func.h2
-rw-r--r--src/lj_gc.c2
-rw-r--r--src/lj_lex.c9
-rw-r--r--src/lj_lex.h2
-rw-r--r--src/lj_obj.h10
-rw-r--r--src/ljamalg.c2
16 files changed, 1019 insertions, 48 deletions
diff --git a/doc/status.html b/doc/status.html
index 1048adc4..c8366488 100644
--- a/doc/status.html
+++ b/doc/status.html
@@ -114,11 +114,6 @@ hooks for non-Lua functions) and shows slightly different behavior
114(no per-coroutine hooks, no tail call counting). 114(no per-coroutine hooks, no tail call counting).
115</li> 115</li>
116<li> 116<li>
117<b>Bytecode</b> currently cannot be loaded or dumped. Note that
118the bytecode format differs from Lua&nbsp;5.1 &mdash; loading foreign
119bytecode is not supported at all.
120</li>
121<li>
122Some of the <b>configuration options</b> of Lua&nbsp;5.1 are not supported: 117Some of the <b>configuration options</b> of Lua&nbsp;5.1 are not supported:
123<ul> 118<ul>
124<li>The <b>number type</b> cannot be changed (it's always a <tt>double</tt>).</li> 119<li>The <b>number type</b> cannot be changed (it's always a <tt>double</tt>).</li>
diff --git a/src/Makefile b/src/Makefile
index 84f9d42f..e670953b 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -360,7 +360,7 @@ LJLIB_C= $(LJLIB_O:.o=.c)
360LJCORE_O= lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o \ 360LJCORE_O= lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o \
361 lj_str.o lj_tab.o lj_func.o lj_udata.o lj_meta.o lj_debug.o \ 361 lj_str.o lj_tab.o lj_func.o lj_udata.o lj_meta.o lj_debug.o \
362 lj_state.o lj_dispatch.o lj_vmevent.o lj_vmmath.o lj_api.o \ 362 lj_state.o lj_dispatch.o lj_vmevent.o lj_vmmath.o lj_api.o \
363 lj_lex.o lj_parse.o \ 363 lj_lex.o lj_parse.o lj_bcread.o lj_bcwrite.o \
364 lj_ir.o lj_opt_mem.o lj_opt_fold.o lj_opt_narrow.o \ 364 lj_ir.o lj_opt_mem.o lj_opt_fold.o lj_opt_narrow.o \
365 lj_opt_dce.o lj_opt_loop.o lj_opt_split.o \ 365 lj_opt_dce.o lj_opt_loop.o lj_opt_split.o \
366 lj_mcode.o lj_snap.o lj_record.o lj_crecord.o lj_ffrecord.o \ 366 lj_mcode.o lj_snap.o lj_record.o lj_crecord.o lj_ffrecord.o \
diff --git a/src/Makefile.dep b/src/Makefile.dep
index 937fd67f..3a5667bc 100644
--- a/src/Makefile.dep
+++ b/src/Makefile.dep
@@ -42,7 +42,8 @@ lib_package.o: lib_package.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
42 lj_def.h lj_arch.h lj_err.h lj_errmsg.h lj_lib.h 42 lj_def.h lj_arch.h lj_err.h lj_errmsg.h lj_lib.h
43lib_string.o: lib_string.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \ 43lib_string.o: lib_string.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
44 lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h \ 44 lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h \
45 lj_state.h lj_ff.h lj_ffdef.h lj_char.h lj_lib.h lj_libdef.h 45 lj_state.h lj_ff.h lj_ffdef.h lj_bcdump.h lj_lex.h lj_char.h lj_lib.h \
46 lj_libdef.h
46lib_table.o: lib_table.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \ 47lib_table.o: lib_table.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
47 lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_lib.h \ 48 lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_lib.h \
48 lj_libdef.h 49 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
50lj_api.o: lj_api.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ 51lj_api.o: lj_api.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
51 lj_err.h lj_errmsg.h lj_debug.h lj_str.h lj_tab.h lj_func.h lj_udata.h \ 52 lj_err.h lj_errmsg.h lj_debug.h lj_str.h lj_tab.h lj_func.h lj_udata.h \
52 lj_meta.h lj_state.h lj_bc.h lj_frame.h lj_trace.h lj_jit.h lj_ir.h \ 53 lj_meta.h lj_state.h lj_bc.h lj_frame.h lj_trace.h lj_jit.h lj_ir.h \
53 lj_dispatch.h lj_traceerr.h lj_vm.h lj_lex.h lj_parse.h 54 lj_dispatch.h lj_traceerr.h lj_vm.h lj_lex.h lj_bcdump.h lj_parse.h
54lj_asm.o: lj_asm.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ 55lj_asm.o: lj_asm.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
55 lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h lj_ir.h lj_jit.h \ 56 lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h lj_ir.h lj_jit.h \
56 lj_ircall.h lj_iropt.h lj_mcode.h lj_trace.h lj_dispatch.h lj_traceerr.h \ 57 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 \
58 lj_asm_*.h 59 lj_asm_*.h
59lj_bc.o: lj_bc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_bc.h \ 60lj_bc.o: lj_bc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_bc.h \
60 lj_bcdef.h 61 lj_bcdef.h
62lj_bcread.o: lj_bcread.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
63 lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_bc.h lj_ctype.h \
64 lj_cdata.h lj_lex.h lj_bcdump.h lj_state.h
65lj_bcwrite.o: lj_bcwrite.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
66 lj_gc.h lj_str.h lj_bc.h lj_ctype.h lj_dispatch.h lj_jit.h lj_ir.h \
67 lj_bcdump.h lj_lex.h lj_err.h lj_errmsg.h lj_vm.h
61lj_carith.o: lj_carith.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 68lj_carith.o: lj_carith.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
62 lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_meta.h lj_ctype.h lj_cconv.h \ 69 lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_meta.h lj_ctype.h lj_cconv.h \
63 lj_cdata.h lj_carith.h 70 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 \
180 lj_debug.h lj_ff.h lj_ffdef.h lj_char.c lj_char.h lj_bc.c lj_bcdef.h \ 187 lj_debug.h lj_ff.h lj_ffdef.h lj_char.c lj_char.h lj_bc.c lj_bcdef.h \
181 lj_obj.c lj_str.c lj_tab.c lj_func.c lj_udata.c lj_meta.c lj_debug.c \ 188 lj_obj.c lj_str.c lj_tab.c lj_func.c lj_udata.c lj_meta.c lj_debug.c \
182 lj_state.c lj_lex.h lj_alloc.h lj_dispatch.c luajit.h lj_vmevent.c \ 189 lj_state.c lj_lex.h lj_alloc.h lj_dispatch.c luajit.h lj_vmevent.c \
183 lj_vmevent.h lj_vmmath.c lj_api.c lj_parse.h lj_lex.c lualib.h \ 190 lj_vmevent.h lj_vmmath.c lj_api.c lj_bcdump.h lj_parse.h lj_lex.c \
184 lj_parse.c lj_ctype.c lj_cdata.c lj_cconv.h lj_cconv.c lj_ccall.c \ 191 lualib.h lj_parse.c lj_bcread.c lj_bcwrite.c lj_ctype.c lj_cdata.c \
185 lj_ccall.h lj_carith.c lj_carith.h lj_clib.c lj_clib.h lj_cparse.c \ 192 lj_cconv.h lj_cconv.c lj_ccall.c lj_ccall.h lj_carith.c lj_carith.h \
186 lj_cparse.h lj_lib.c lj_lib.h lj_ir.c lj_ircall.h lj_iropt.h \ 193 lj_clib.c lj_clib.h lj_cparse.c lj_cparse.h lj_lib.c lj_lib.h lj_ir.c \
187 lj_opt_mem.c lj_opt_fold.c lj_folddef.h lj_opt_narrow.c lj_opt_dce.c \ 194 lj_ircall.h lj_iropt.h lj_opt_mem.c lj_opt_fold.c lj_folddef.h \
188 lj_opt_loop.c lj_snap.h lj_opt_split.c lj_mcode.c lj_mcode.h lj_snap.c \ 195 lj_opt_narrow.c lj_opt_dce.c lj_opt_loop.c lj_snap.h lj_opt_split.c \
189 lj_target.h lj_target_*.h lj_record.c lj_record.h lj_ffrecord.h \ 196 lj_mcode.c lj_mcode.h lj_snap.c lj_target.h lj_target_*.h lj_record.c \
190 lj_crecord.c lj_crecord.h lj_ffrecord.c lj_recdef.h lj_asm.c lj_asm.h \ 197 lj_record.h lj_ffrecord.h lj_crecord.c lj_crecord.h lj_ffrecord.c \
191 lj_emit_*.h lj_asm_*.h lj_trace.c lj_gdbjit.h lj_gdbjit.c lj_alloc.c \ 198 lj_recdef.h lj_asm.c lj_asm.h lj_emit_*.h lj_asm_*.h lj_trace.c \
192 lib_aux.c lib_base.c lj_libdef.h lib_math.c lib_string.c lib_table.c \ 199 lj_gdbjit.h lj_gdbjit.c lj_alloc.c lib_aux.c lib_base.c lj_libdef.h \
193 lib_io.c lib_os.c lib_package.c lib_debug.c lib_bit.c lib_jit.c \ 200 lib_math.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c \
194 lib_ffi.c lib_init.c 201 lib_debug.c lib_bit.c lib_jit.c lib_ffi.c lib_init.c
195luajit.o: luajit.c lua.h luaconf.h lauxlib.h lualib.h luajit.h lj_arch.h 202luajit.o: luajit.c lua.h luaconf.h lauxlib.h lualib.h luajit.h lj_arch.h
diff --git a/src/lib_string.c b/src/lib_string.c
index e54b2d50..5cbe6e4d 100644
--- a/src/lib_string.c
+++ b/src/lib_string.c
@@ -22,6 +22,7 @@
22#include "lj_tab.h" 22#include "lj_tab.h"
23#include "lj_state.h" 23#include "lj_state.h"
24#include "lj_ff.h" 24#include "lj_ff.h"
25#include "lj_bcdump.h"
25#include "lj_char.h" 26#include "lj_char.h"
26#include "lj_lib.h" 27#include "lj_lib.h"
27 28
@@ -114,10 +115,24 @@ LJLIB_ASM_(string_upper)
114 115
115/* ------------------------------------------------------------------------ */ 116/* ------------------------------------------------------------------------ */
116 117
118static int writer_buf(lua_State *L, const void *p, size_t size, void *b)
119{
120 luaL_addlstring((luaL_Buffer *)b, (const char *)p, size);
121 UNUSED(L);
122 return 0;
123}
124
117LJLIB_CF(string_dump) 125LJLIB_CF(string_dump)
118{ 126{
119 lj_err_caller(L, LJ_ERR_STRDUMP); 127 GCfunc *fn = lj_lib_checkfunc(L, 1);
120 return 0; /* unreachable */ 128 int strip = L->base+1 < L->top && tvistruecond(L->base+1);
129 luaL_Buffer b;
130 L->top = L->base+1;
131 luaL_buffinit(L, &b);
132 if (!isluafunc(fn) || lj_bcwrite(L, funcproto(fn), writer_buf, &b, strip))
133 lj_err_caller(L, LJ_ERR_STRDUMP);
134 luaL_pushresult(&b);
135 return 1;
121} 136}
122 137
123/* ------------------------------------------------------------------------ */ 138/* ------------------------------------------------------------------------ */
diff --git a/src/lj_api.c b/src/lj_api.c
index 34c57806..a6fbb1c6 100644
--- a/src/lj_api.c
+++ b/src/lj_api.c
@@ -24,6 +24,7 @@
24#include "lj_trace.h" 24#include "lj_trace.h"
25#include "lj_vm.h" 25#include "lj_vm.h"
26#include "lj_lex.h" 26#include "lj_lex.h"
27#include "lj_bcdump.h"
27#include "lj_parse.h" 28#include "lj_parse.h"
28 29
29/* -- Common helper functions --------------------------------------------- */ 30/* -- Common helper functions --------------------------------------------- */
@@ -1115,12 +1116,13 @@ LUA_API int lua_resume(lua_State *L, int nargs)
1115static TValue *cpparser(lua_State *L, lua_CFunction dummy, void *ud) 1116static TValue *cpparser(lua_State *L, lua_CFunction dummy, void *ud)
1116{ 1117{
1117 LexState *ls = (LexState *)ud; 1118 LexState *ls = (LexState *)ud;
1119 GCproto *pt;
1118 GCfunc *fn; 1120 GCfunc *fn;
1119 UNUSED(dummy); 1121 UNUSED(dummy);
1120 cframe_errfunc(L->cframe) = -1; /* Inherit error function. */ 1122 cframe_errfunc(L->cframe) = -1; /* Inherit error function. */
1121 lj_lex_setup(L, ls); 1123 pt = lj_lex_setup(L, ls) ? lj_bcread(ls) : lj_parse(ls);
1122 fn = lj_func_newL(L, lj_parse(ls), tabref(L->env)); 1124 fn = lj_func_newL_empty(L, pt, tabref(L->env));
1123 /* Parser may realloc stack. Don't combine above/below into one statement. */ 1125 /* Don't combine above/below into one statement. */
1124 setfuncV(L, L->top++, fn); 1126 setfuncV(L, L->top++, fn);
1125 return NULL; 1127 return NULL;
1126} 1128}
@@ -1142,9 +1144,12 @@ LUA_API int lua_load(lua_State *L, lua_Reader reader, void *data,
1142 1144
1143LUA_API int lua_dump(lua_State *L, lua_Writer writer, void *data) 1145LUA_API int lua_dump(lua_State *L, lua_Writer writer, void *data)
1144{ 1146{
1147 cTValue *o = L->top-1;
1145 api_checknelems(L, 1); 1148 api_checknelems(L, 1);
1146 UNUSED(L); UNUSED(writer); UNUSED(data); 1149 if (tvisfunc(o) && isluafunc(funcV(o)))
1147 return 1; /* Error, not supported. */ 1150 return lj_bcwrite(L, funcproto(funcV(o)), writer, data, 0);
1151 else
1152 return 1;
1148} 1153}
1149 1154
1150/* -- GC and memory management -------------------------------------------- */ 1155/* -- GC and memory management -------------------------------------------- */
diff --git a/src/lj_bcdump.h b/src/lj_bcdump.h
new file mode 100644
index 00000000..49b59e85
--- /dev/null
+++ b/src/lj_bcdump.h
@@ -0,0 +1,66 @@
1/*
2** Bytecode dump definitions.
3** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h
4*/
5
6#ifndef _LJ_BCDUMP_H
7#define _LJ_BCDUMP_H
8
9#include "lj_obj.h"
10#include "lj_lex.h"
11
12/* -- Bytecode dump format ------------------------------------------------ */
13
14/*
15** dump = header proto+ 0U
16** header = ESC 'L' 'J' versionB flagsU [namelenU nameB*]
17** proto = lengthU pdata
18** pdata = phead bcinsW* uvdataH* kgc* knum* [debugB*]
19** phead = flagsB numparamsB framesizeB numuvB numkgcU numknU numbcU
20** [debuglenU [firstlineU numlineU]]
21** kgc = kgctypeU { ktab | (loU hiU) | (rloU rhiU iloU ihiU) | strB* }
22** knum = intU0 | (loU1 hiU)
23** ktab = narrayU nhashU karray* khash*
24** karray = ktabk
25** khash = ktabk ktabk
26** ktabk = ktabtypeU { intU | (loU hiU) | strB* }
27**
28** B = 8 bit, H = 16 bit, W = 32 bit, U = ULEB128 of W, U0/U1 = ULEB128 of W+1
29*/
30
31/* Bytecode dump header. */
32#define BCDUMP_HEAD1 0x1b
33#define BCDUMP_HEAD2 0x4c
34#define BCDUMP_HEAD3 0x4a
35
36/* If you perform *any* kind of private modifications to the bytecode itself
37** or to the dump format, you *must* set BCDUMP_VERSION to 0x80 or higher.
38*/
39#define BCDUMP_VERSION 1
40
41/* Compatibility flags. */
42#define BCDUMP_F_BE 0x01
43#define BCDUMP_F_STRIP 0x02
44#define BCDUMP_F_FFI 0x04
45
46#define BCDUMP_F_KNOWN (BCDUMP_F_FFI*2-1)
47
48/* Type codes for the GC constants of a prototype. Plus length for strings. */
49enum {
50 BCDUMP_KGC_CHILD, BCDUMP_KGC_TAB, BCDUMP_KGC_I64, BCDUMP_KGC_U64,
51 BCDUMP_KGC_COMPLEX, BCDUMP_KGC_STR
52};
53
54/* Type codes for the keys/values of a constant table. */
55enum {
56 BCDUMP_KTAB_NIL, BCDUMP_KTAB_FALSE, BCDUMP_KTAB_TRUE,
57 BCDUMP_KTAB_INT, BCDUMP_KTAB_NUM, BCDUMP_KTAB_STR
58};
59
60/* -- Bytecode reader/writer ---------------------------------------------- */
61
62LJ_FUNC int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer,
63 void *data, int strip);
64LJ_FUNC GCproto *lj_bcread(LexState *ls);
65
66#endif
diff --git a/src/lj_bcread.c b/src/lj_bcread.c
new file mode 100644
index 00000000..c5d4cd9d
--- /dev/null
+++ b/src/lj_bcread.c
@@ -0,0 +1,466 @@
1/*
2** Bytecode reader.
3** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h
4*/
5
6#define lj_bcread_c
7#define LUA_CORE
8
9#include "lj_obj.h"
10#include "lj_gc.h"
11#include "lj_err.h"
12#include "lj_str.h"
13#include "lj_tab.h"
14#include "lj_bc.h"
15#if LJ_HASFFI
16#include "lj_ctype.h"
17#include "lj_cdata.h"
18#endif
19#include "lj_lex.h"
20#include "lj_bcdump.h"
21#include "lj_state.h"
22
23/* Reuse some lexer fields for our own purposes. */
24#define bcread_flags(ls) ls->level
25#define bcread_swap(ls) \
26 ((bcread_flags(ls) & BCDUMP_F_BE) != LJ_BE*BCDUMP_F_BE)
27#define bcread_oldtop(L, ls) restorestack(L, ls->lastline)
28#define bcread_savetop(L, ls, top) \
29 ls->lastline = (BCLine)savestack(L, (top))
30
31/* -- Input buffer handling ----------------------------------------------- */
32
33/* Throw reader error. */
34static LJ_NOINLINE void bcread_error(LexState *ls, ErrMsg em)
35{
36 lua_State *L = ls->L;
37 const char *name = ls->chunkarg;
38 if (*name == BCDUMP_HEAD1) name = "(binary)";
39 else if (*name == '@' || *name == '=') name++;
40 lj_str_pushf(L, "%s: %s", name, err2msg(em));
41 lj_err_throw(L, LUA_ERRSYNTAX);
42}
43
44/* Resize input buffer. */
45static void bcread_resize(LexState *ls, MSize len)
46{
47 if (ls->sb.sz < len) {
48 MSize sz = ls->sb.sz * 2;
49 while (len > sz) sz = sz * 2;
50 lj_str_resizebuf(ls->L, &ls->sb, sz);
51 /* Caveat: this may change ls->sb.buf which may affect ls->p. */
52 }
53}
54
55/* Refill buffer if needed. */
56static LJ_NOINLINE void bcread_fill(LexState *ls, MSize len, int need)
57{
58 lua_assert(len != 0);
59 if (len > LJ_MAX_MEM || ls->current < 0)
60 bcread_error(ls, LJ_ERR_BCBAD);
61 do {
62 const char *buf;
63 size_t size;
64 if (ls->n) { /* Copy remainder to buffer. */
65 if (ls->sb.n) { /* Move down in buffer. */
66 lua_assert(ls->p + ls->n == ls->sb.buf + ls->sb.n);
67 if (ls->n != ls->sb.n)
68 memmove(ls->sb.buf, ls->p, ls->n);
69 } else { /* Copy from buffer provided by reader. */
70 bcread_resize(ls, len);
71 memcpy(ls->sb.buf, ls->p, ls->n);
72 }
73 ls->p = ls->sb.buf;
74 }
75 ls->sb.n = ls->n;
76 buf = ls->rfunc(ls->L, ls->rdata, &size); /* Get more data from reader. */
77 if (buf == NULL || size == 0) { /* EOF? */
78 if (need) bcread_error(ls, LJ_ERR_BCBAD);
79 ls->current = -1; /* Only bad if we get called again. */
80 break;
81 }
82 if (ls->sb.n) { /* Append to buffer. */
83 MSize n = ls->sb.n + (MSize)size;
84 bcread_resize(ls, n < len ? len : n);
85 memcpy(ls->sb.buf + ls->sb.n, buf, size);
86 ls->n = ls->sb.n = n;
87 ls->p = ls->sb.buf;
88 } else { /* Return buffer provided by reader. */
89 ls->n = (MSize)size;
90 ls->p = buf;
91 }
92 } while (ls->n < len);
93}
94
95/* Need a certain number of bytes. */
96static LJ_AINLINE void bcread_need(LexState *ls, MSize len)
97{
98 if (LJ_UNLIKELY(ls->n < len))
99 bcread_fill(ls, len, 1);
100}
101
102/* Want to read up to a certain number of bytes, but may need less. */
103static LJ_AINLINE void bcread_want(LexState *ls, MSize len)
104{
105 if (LJ_UNLIKELY(ls->n < len))
106 bcread_fill(ls, len, 0);
107}
108
109#define bcread_dec(ls) check_exp(ls->n > 0, ls->n--)
110#define bcread_consume(ls, len) check_exp(ls->n >= (len), ls->n -= (len))
111
112/* Return memory block from buffer. */
113static uint8_t *bcread_mem(LexState *ls, MSize len)
114{
115 uint8_t *p = (uint8_t *)ls->p;
116 bcread_consume(ls, len);
117 ls->p = (char *)p + len;
118 return p;
119}
120
121/* Copy memory block from buffer. */
122static void bcread_block(LexState *ls, void *q, MSize len)
123{
124 memcpy(q, bcread_mem(ls, len), len);
125}
126
127/* Read byte from buffer. */
128static LJ_AINLINE uint32_t bcread_byte(LexState *ls)
129{
130 bcread_dec(ls);
131 return (uint32_t)(uint8_t)*ls->p++;
132}
133
134/* Read ULEB128 value from buffer. */
135static uint32_t bcread_uleb128(LexState *ls)
136{
137 const uint8_t *p = (const uint8_t *)ls->p;
138 uint32_t v = *p++;
139 if (LJ_UNLIKELY(v >= 0x80)) {
140 int sh = 0;
141 v &= 0x7f;
142 do {
143 v |= ((*p & 0x7f) << (sh += 7));
144 bcread_dec(ls);
145 } while (*p++ >= 0x80);
146 }
147 bcread_dec(ls);
148 ls->p = (char *)p;
149 return v;
150}
151
152/* Read top 32 bits of 33 bit ULEB128 value from buffer. */
153static uint32_t bcread_uleb128_33(LexState *ls)
154{
155 const uint8_t *p = (const uint8_t *)ls->p;
156 uint32_t v = (*p++ >> 1);
157 if (LJ_UNLIKELY(v >= 0x40)) {
158 int sh = -1;
159 v &= 0x3f;
160 do {
161 v |= ((*p & 0x7f) << (sh += 7));
162 bcread_dec(ls);
163 } while (*p++ >= 0x80);
164 }
165 bcread_dec(ls);
166 ls->p = (char *)p;
167 return v;
168}
169
170/* -- Bytecode reader ----------------------------------------------------- */
171
172/* Read debug info of a prototype. */
173static void bcread_dbg(LexState *ls, GCproto *pt, MSize sizedbg)
174{
175 void *lineinfo = (void *)proto_lineinfo(pt);
176 bcread_block(ls, lineinfo, sizedbg);
177 /* Swap lineinfo if the endianess differs. */
178 if (bcread_swap(ls) && pt->numline >= 256) {
179 MSize i, n = pt->sizebc-1;
180 if (pt->numline < 65536) {
181 uint16_t *p = (uint16_t *)lineinfo;
182 for (i = 0; i < n; i++) p[i] = (uint16_t)((p[i] >> 8)|(p[i] << 8));
183 } else {
184 uint32_t *p = (uint32_t *)lineinfo;
185 for (i = 0; i < n; i++) p[i] = lj_bswap(p[i]);
186 }
187 }
188}
189
190/* Find pointer to varinfo. */
191static const void *bcread_varinfo(GCproto *pt)
192{
193 const uint8_t *p = proto_uvinfo(pt);
194 MSize n = pt->sizeuv;
195 if (n) while (*p++ || --n) ;
196 return p;
197}
198
199/* Read a single constant key/value of a template table. */
200static void bcread_ktabk(LexState *ls, TValue *o)
201{
202 MSize tp = bcread_uleb128(ls);
203 if (tp >= BCDUMP_KTAB_STR) {
204 MSize len = tp - BCDUMP_KTAB_STR;
205 const char *p = (const char *)bcread_mem(ls, len);
206 setstrV(ls->L, o, lj_str_new(ls->L, p, len));
207 } else if (tp == BCDUMP_KTAB_INT) {
208 setintV(o, (int32_t)bcread_uleb128(ls));
209 } else if (tp == BCDUMP_KTAB_NUM) {
210 o->u32.lo = bcread_uleb128(ls);
211 o->u32.hi = bcread_uleb128(ls);
212 } else {
213 lua_assert(tp <= BCDUMP_KTAB_TRUE);
214 setitype(o, ~tp);
215 }
216}
217
218/* Read a template table. */
219static GCtab *bcread_ktab(LexState *ls)
220{
221 MSize narray = bcread_uleb128(ls);
222 MSize nhash = bcread_uleb128(ls);
223 GCtab *t = lj_tab_new(ls->L, narray, hsize2hbits(nhash));
224 if (narray) { /* Read array entries. */
225 MSize i;
226 TValue *o = tvref(t->array);
227 for (i = 0; i < narray; i++, o++)
228 bcread_ktabk(ls, o);
229 }
230 if (nhash) { /* Read hash entries. */
231 MSize i;
232 for (i = 0; i < nhash; i++) {
233 TValue key;
234 bcread_ktabk(ls, &key);
235 lua_assert(!tvisnil(&key));
236 bcread_ktabk(ls, lj_tab_set(ls->L, t, &key));
237 }
238 }
239 return t;
240}
241
242/* Read GC constants of a prototype. */
243static void bcread_kgc(LexState *ls, GCproto *pt, MSize sizekgc)
244{
245 MSize i;
246 GCRef *kr = mref(pt->k, GCRef) - (ptrdiff_t)sizekgc;
247 for (i = 0; i < sizekgc; i++, kr++) {
248 MSize tp = bcread_uleb128(ls);
249 if (tp >= BCDUMP_KGC_STR) {
250 MSize len = tp - BCDUMP_KGC_STR;
251 const char *p = (const char *)bcread_mem(ls, len);
252 setgcref(*kr, obj2gco(lj_str_new(ls->L, p, len)));
253 } else if (tp == BCDUMP_KGC_TAB) {
254 setgcref(*kr, obj2gco(bcread_ktab(ls)));
255#if LJ_HASFFI
256 } else if (tp != BCDUMP_KGC_CHILD) {
257 CTypeID id = tp == BCDUMP_KGC_COMPLEX ? CTID_COMPLEX_DOUBLE :
258 tp == BCDUMP_KGC_I64 ? CTID_INT64 : CTID_UINT64;
259 CTSize sz = tp == BCDUMP_KGC_COMPLEX ? 16 : 8;
260 GCcdata *cd = lj_cdata_new_(ls->L, id, sz);
261 TValue *p = (TValue *)cdataptr(cd);
262 setgcref(*kr, obj2gco(cd));
263 p[0].u32.lo = bcread_uleb128(ls);
264 p[0].u32.hi = bcread_uleb128(ls);
265 if (tp == BCDUMP_KGC_COMPLEX) {
266 p[1].u32.lo = bcread_uleb128(ls);
267 p[1].u32.hi = bcread_uleb128(ls);
268 }
269#endif
270 } else {
271 lua_State *L = ls->L;
272 lua_assert(tp == BCDUMP_KGC_CHILD);
273 if (L->top <= bcread_oldtop(L, ls)) /* Stack underflow? */
274 bcread_error(ls, LJ_ERR_BCBAD);
275 L->top--;
276 setgcref(*kr, obj2gco(protoV(L->top)));
277 }
278 }
279}
280
281/* Read number constants of a prototype. */
282static void bcread_knum(LexState *ls, GCproto *pt, MSize sizekn)
283{
284 MSize i;
285 TValue *o = mref(pt->k, TValue);
286 for (i = 0; i < sizekn; i++, o++) {
287 int isnum = (ls->p[0] & 1);
288 uint32_t lo = bcread_uleb128_33(ls);
289 if (isnum) {
290 o->u32.lo = lo;
291 o->u32.hi = bcread_uleb128(ls);
292 } else {
293 setintV(o, lo);
294 }
295 }
296}
297
298/* Read bytecode instructions. */
299static void bcread_bytecode(LexState *ls, GCproto *pt, MSize sizebc)
300{
301 BCIns *bc = proto_bc(pt);
302 bc[0] = BCINS_AD((pt->flags & PROTO_VARARG) ? BC_FUNCV : BC_FUNCF,
303 pt->framesize, 0);
304 bcread_block(ls, bc+1, (sizebc-1)*(MSize)sizeof(BCIns));
305 /* Swap bytecode instructions if the endianess differs. */
306 if (bcread_swap(ls)) {
307 MSize i;
308 for (i = 1; i < sizebc; i++) bc[i] = lj_bswap(bc[i]);
309 }
310}
311
312/* Read upvalue refs. */
313static void bcread_uv(LexState *ls, GCproto *pt, MSize sizeuv)
314{
315 if (sizeuv) {
316 uint16_t *uv = proto_uv(pt);
317 bcread_block(ls, uv, sizeuv*2);
318 /* Swap upvalue refs if the endianess differs. */
319 if (bcread_swap(ls)) {
320 MSize i;
321 for (i = 0; i < sizeuv; i++)
322 uv[i] = (uint16_t)((uv[i] >> 8)|(uv[i] << 8));
323 }
324 }
325}
326
327/* Read a prototype. */
328static GCproto *bcread_proto(LexState *ls)
329{
330 GCproto *pt;
331 MSize framesize, numparams, flags, sizeuv, sizekgc, sizekn, sizebc, sizept;
332 MSize ofsk, ofsuv, ofsdbg;
333 MSize sizedbg = 0;
334 BCLine firstline = 0, numline = 0;
335 MSize len, startn;
336
337 /* Read length. */
338 if (ls->n > 0 && ls->p[0] == 0) { /* Shortcut EOF. */
339 ls->n--; ls->p++;
340 return NULL;
341 }
342 bcread_want(ls, 5);
343 len = bcread_uleb128(ls);
344 if (!len) return NULL; /* EOF */
345 bcread_need(ls, len);
346 startn = ls->n;
347
348 /* Read prototype header. */
349 flags = bcread_byte(ls);
350 numparams = bcread_byte(ls);
351 framesize = bcread_byte(ls);
352 sizeuv = bcread_byte(ls);
353 sizekgc = bcread_uleb128(ls);
354 sizekn = bcread_uleb128(ls);
355 sizebc = bcread_uleb128(ls) + 1;
356 if (!(bcread_flags(ls) & BCDUMP_F_STRIP)) {
357 sizedbg = bcread_uleb128(ls);
358 if (sizedbg) {
359 firstline = bcread_uleb128(ls);
360 numline = bcread_uleb128(ls);
361 }
362 }
363
364 /* Calculate total size of prototype including all colocated arrays. */
365 sizept = (MSize)sizeof(GCproto) +
366 sizebc*(MSize)sizeof(BCIns) +
367 sizekgc*(MSize)sizeof(GCRef);
368 sizept = (sizept + (MSize)sizeof(TValue)-1) & ~((MSize)sizeof(TValue)-1);
369 ofsk = sizept; sizept += sizekn*(MSize)sizeof(TValue);
370 ofsuv = sizept; sizept += ((sizeuv+1)&~1)*2;
371 ofsdbg = sizept; sizept += sizedbg;
372
373 /* Allocate prototype object and initialize its fields. */
374 pt = (GCproto *)lj_mem_newgco(ls->L, (MSize)sizept);
375 pt->gct = ~LJ_TPROTO;
376 pt->numparams = (uint8_t)numparams;
377 pt->framesize = (uint8_t)framesize;
378 pt->sizebc = sizebc;
379 setmref(pt->k, (char *)pt + ofsk);
380 setmref(pt->uv, (char *)pt + ofsuv);
381 pt->sizekgc = 0; /* Set to zero until fully initialized. */
382 pt->sizekn = sizekn;
383 pt->sizept = sizept;
384 pt->sizeuv = (uint8_t)sizeuv;
385 pt->flags = (uint8_t)flags;
386 pt->trace = 0;
387 setgcref(pt->chunkname, obj2gco(ls->chunkname));
388
389 /* Close potentially uninitialized gap between bc and kgc. */
390 *(uint32_t *)((char *)pt + ofsk - sizeof(GCRef)*(sizekgc+1)) = 0;
391
392 /* Read bytecode instructions and upvalue refs. */
393 bcread_bytecode(ls, pt, sizebc);
394 bcread_uv(ls, pt, sizeuv);
395
396 /* Read constants. */
397 bcread_kgc(ls, pt, sizekgc);
398 pt->sizekgc = sizekgc;
399 bcread_knum(ls, pt, sizekn);
400
401 /* Read and initialize debug info. */
402 pt->firstline = firstline;
403 pt->numline = numline;
404 if (sizedbg) {
405 MSize sizeli = (sizebc-1) << (numline < 256 ? 0 : numline < 65536 ? 1 : 2);
406 setmref(pt->lineinfo, (char *)pt + ofsdbg);
407 setmref(pt->uvinfo, (char *)pt + ofsdbg + sizeli);
408 bcread_dbg(ls, pt, sizedbg);
409 setmref(pt->varinfo, bcread_varinfo(pt));
410 } else {
411 setmref(pt->lineinfo, NULL);
412 setmref(pt->uvinfo, NULL);
413 setmref(pt->varinfo, NULL);
414 }
415
416 if (len != startn - ls->n)
417 bcread_error(ls, LJ_ERR_BCBAD);
418 return pt;
419}
420
421/* Read and check header of bytecode dump. */
422static int bcread_header(LexState *ls)
423{
424 uint32_t flags;
425 bcread_want(ls, 3+5+5);
426 if (bcread_byte(ls) != BCDUMP_HEAD2 ||
427 bcread_byte(ls) != BCDUMP_HEAD3 ||
428 bcread_byte(ls) != BCDUMP_VERSION) return 0;
429 bcread_flags(ls) = flags = bcread_uleb128(ls);
430 if ((flags & ~(BCDUMP_F_KNOWN)) != 0) return 0;
431#if !LJ_HASFFI
432 if ((flags & BCDUMP_F_FFI)) return 0;
433#endif
434 if ((flags & BCDUMP_F_STRIP)) {
435 ls->chunkname = lj_str_newz(ls->L, ls->chunkarg);
436 } else {
437 MSize len = bcread_uleb128(ls);
438 bcread_need(ls, len);
439 ls->chunkname = lj_str_new(ls->L, (const char *)bcread_mem(ls, len), len);
440 }
441 return 1; /* Ok. */
442}
443
444/* Read a bytecode dump. */
445GCproto *lj_bcread(LexState *ls)
446{
447 lua_State *L = ls->L;
448 lua_assert(ls->current == BCDUMP_HEAD1);
449 bcread_savetop(L, ls, L->top);
450 lj_str_resetbuf(&ls->sb);
451 /* Check for a valid bytecode dump header. */
452 if (!bcread_header(ls))
453 bcread_error(ls, LJ_ERR_BCFMT);
454 for (;;) { /* Process all prototypes in the bytecode dump. */
455 GCproto *pt = bcread_proto(ls);
456 if (!pt) break;
457 setprotoV(L, L->top, pt);
458 incr_top(L);
459 }
460 if (ls->n != 0 || L->top-1 != bcread_oldtop(L, ls))
461 bcread_error(ls, LJ_ERR_BCBAD);
462 /* Pop off last prototype. */
463 L->top--;
464 return protoV(L->top);
465}
466
diff --git a/src/lj_bcwrite.c b/src/lj_bcwrite.c
new file mode 100644
index 00000000..b90f7850
--- /dev/null
+++ b/src/lj_bcwrite.c
@@ -0,0 +1,388 @@
1/*
2** Bytecode writer.
3** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h
4*/
5
6#define lj_bcwrite_c
7#define LUA_CORE
8
9#include "lj_obj.h"
10#include "lj_gc.h"
11#include "lj_str.h"
12#include "lj_bc.h"
13#if LJ_HASFFI
14#include "lj_ctype.h"
15#endif
16#if LJ_HASJIT
17#include "lj_dispatch.h"
18#include "lj_jit.h"
19#endif
20#include "lj_bcdump.h"
21#include "lj_vm.h"
22
23/* Context for bytecode writer. */
24typedef struct BCWriteCtx {
25 SBuf sb; /* Output buffer. */
26 lua_State *L; /* Lua state. */
27 GCproto *pt; /* Root prototype. */
28 lua_Writer wfunc; /* Writer callback. */
29 void *wdata; /* Writer callback data. */
30 int strip; /* Strip debug info. */
31 int status; /* Status from writer callback. */
32} BCWriteCtx;
33
34/* -- Output buffer handling ---------------------------------------------- */
35
36/* Resize buffer if needed. */
37static LJ_NOINLINE void bcwrite_resize(BCWriteCtx *ctx, MSize len)
38{
39 MSize sz = ctx->sb.sz * 2;
40 while (ctx->sb.n + len > sz) sz = sz * 2;
41 lj_str_resizebuf(ctx->L, &ctx->sb, sz);
42}
43
44/* Need a certain amount of buffer space. */
45static LJ_AINLINE void bcwrite_need(BCWriteCtx *ctx, MSize len)
46{
47 if (LJ_UNLIKELY(ctx->sb.n + len > ctx->sb.sz))
48 bcwrite_resize(ctx, len);
49}
50
51/* Add memory block to buffer. */
52static void bcwrite_block(BCWriteCtx *ctx, const void *p, MSize len)
53{
54 uint8_t *q = (uint8_t *)(ctx->sb.buf + ctx->sb.n);
55 MSize i;
56 ctx->sb.n += len;
57 for (i = 0; i < len; i++) q[i] = ((uint8_t *)p)[i];
58}
59
60/* Add byte to buffer. */
61static LJ_AINLINE void bcwrite_byte(BCWriteCtx *ctx, uint8_t b)
62{
63 ctx->sb.buf[ctx->sb.n++] = b;
64}
65
66/* Add ULEB128 value to buffer. */
67static void bcwrite_uleb128(BCWriteCtx *ctx, uint32_t v)
68{
69 MSize n = ctx->sb.n;
70 uint8_t *p = (uint8_t *)ctx->sb.buf;
71 for (; v >= 0x80; v >>= 7)
72 p[n++] = (uint8_t)((v & 0x7f) | 0x80);
73 p[n++] = (uint8_t)v;
74 ctx->sb.n = n;
75}
76
77/* -- Bytecode writer ----------------------------------------------------- */
78
79/* Write a single constant key/value of a template table. */
80static void bcwrite_ktabk(BCWriteCtx *ctx, cTValue *o, int narrow)
81{
82 bcwrite_need(ctx, 1+10);
83 if (tvisstr(o)) {
84 const GCstr *str = strV(o);
85 MSize len = str->len;
86 bcwrite_need(ctx, 5+len);
87 bcwrite_uleb128(ctx, BCDUMP_KTAB_STR+len);
88 bcwrite_block(ctx, strdata(str), len);
89 } else if (tvisint(o)) {
90 bcwrite_byte(ctx, BCDUMP_KTAB_INT);
91 bcwrite_uleb128(ctx, intV(o));
92 } else if (tvisnum(o)) {
93 if (!LJ_DUALNUM && narrow) { /* Narrow number constants to integers. */
94 lua_Number num = numV(o);
95 int32_t k = lj_num2int(num);
96 if (num == (lua_Number)k) { /* -0 is never a constant. */
97 bcwrite_byte(ctx, BCDUMP_KTAB_INT);
98 bcwrite_uleb128(ctx, k);
99 return;
100 }
101 }
102 bcwrite_byte(ctx, BCDUMP_KTAB_NUM);
103 bcwrite_uleb128(ctx, o->u32.lo);
104 bcwrite_uleb128(ctx, o->u32.hi);
105 } else {
106 lua_assert(tvispri(o));
107 bcwrite_byte(ctx, BCDUMP_KTAB_NIL+~itype(o));
108 }
109}
110
111/* Write a template table. */
112static void bcwrite_ktab(BCWriteCtx *ctx, const GCtab *t)
113{
114 MSize narray = 0, nhash = 0;
115 if (t->asize > 0) { /* Determine max. length of array part. */
116 ptrdiff_t i;
117 TValue *array = tvref(t->array);
118 for (i = (ptrdiff_t)t->asize-1; i >= 0; i--)
119 if (!tvisnil(&array[i]))
120 break;
121 narray = (MSize)(i+1);
122 }
123 if (t->hmask > 0) { /* Count number of used hash slots. */
124 MSize i, hmask = t->hmask;
125 Node *node = noderef(t->node);
126 for (i = 0; i <= hmask; i++)
127 nhash += !tvisnil(&node[i].val);
128 }
129 /* Write number of array slots and hash slots. */
130 bcwrite_uleb128(ctx, narray);
131 bcwrite_uleb128(ctx, nhash);
132 if (narray) { /* Write array entries (may contain nil). */
133 MSize i;
134 TValue *o = tvref(t->array);
135 for (i = 0; i < narray; i++, o++)
136 bcwrite_ktabk(ctx, o, 1);
137 }
138 if (nhash) { /* Write hash entries. */
139 MSize i = nhash;
140 Node *node = noderef(t->node) + t->hmask;
141 for (;; node--)
142 if (!tvisnil(&node->val)) {
143 bcwrite_ktabk(ctx, &node->key, 0);
144 bcwrite_ktabk(ctx, &node->val, 1);
145 if (--i == 0) break;
146 }
147 }
148}
149
150/* Write GC constants of a prototype. */
151static void bcwrite_kgc(BCWriteCtx *ctx, GCproto *pt)
152{
153 MSize i, sizekgc = pt->sizekgc;
154 GCRef *kr = mref(pt->k, GCRef) - (ptrdiff_t)sizekgc;
155 for (i = 0; i < sizekgc; i++, kr++) {
156 GCobj *o = gcref(*kr);
157 MSize tp, need = 1;
158 /* Determine constant type and needed size. */
159 if (o->gch.gct == ~LJ_TSTR) {
160 tp = BCDUMP_KGC_STR + gco2str(o)->len;
161 need = 5+gco2str(o)->len;
162 } else if (o->gch.gct == ~LJ_TPROTO) {
163 lua_assert((pt->flags & PROTO_CHILD));
164 tp = BCDUMP_KGC_CHILD;
165#if LJ_HASFFI
166 } else if (o->gch.gct == ~LJ_TCDATA) {
167 CTypeID id = gco2cd(o)->typeid;
168 need = 1+4*5;
169 if (id == CTID_INT64) {
170 tp = BCDUMP_KGC_I64;
171 } else if (id == CTID_UINT64) {
172 tp = BCDUMP_KGC_U64;
173 } else {
174 lua_assert(id == CTID_COMPLEX_DOUBLE);
175 tp = BCDUMP_KGC_COMPLEX;
176 }
177#endif
178 } else {
179 lua_assert(o->gch.gct == ~LJ_TTAB);
180 tp = BCDUMP_KGC_TAB;
181 }
182 /* Write constant type. */
183 bcwrite_need(ctx, need);
184 bcwrite_uleb128(ctx, tp);
185 /* Write constant data (if any). */
186 if (tp >= BCDUMP_KGC_STR) {
187 bcwrite_block(ctx, strdata(gco2str(o)), gco2str(o)->len);
188 } else if (tp == BCDUMP_KGC_TAB) {
189 bcwrite_ktab(ctx, gco2tab(o));
190#if LJ_HASFFI
191 } else if (tp != BCDUMP_KGC_CHILD) {
192 cTValue *p = (TValue *)cdataptr(gco2cd(o));
193 bcwrite_uleb128(ctx, p[0].u32.lo);
194 bcwrite_uleb128(ctx, p[0].u32.hi);
195 if (tp == BCDUMP_KGC_COMPLEX) {
196 bcwrite_uleb128(ctx, p[1].u32.lo);
197 bcwrite_uleb128(ctx, p[1].u32.hi);
198 }
199#endif
200 }
201 }
202}
203
204/* Write number constants of a prototype. */
205static void bcwrite_knum(BCWriteCtx *ctx, GCproto *pt)
206{
207 MSize i, sizekn = pt->sizekn;
208 cTValue *o = mref(pt->k, TValue);
209 bcwrite_need(ctx, 10*sizekn);
210 for (i = 0; i < sizekn; i++, o++) {
211 int32_t k;
212 if (tvisint(o)) {
213 k = intV(o);
214 goto save_int;
215 } else {
216 /* Write a 33 bit ULEB128 for the int (lsb=0) or loword (lsb=1). */
217 if (!LJ_DUALNUM) { /* Narrow number constants to integers. */
218 lua_Number num = numV(o);
219 k = lj_num2int(num);
220 if (num == (lua_Number)k) { /* -0 is never a constant. */
221 save_int:
222 bcwrite_uleb128(ctx, 2*(uint32_t)k);
223 if (k < 0) ctx->sb.buf[ctx->sb.n-1] |= 0x10;
224 continue;
225 }
226 }
227 bcwrite_uleb128(ctx, 1+2*o->u32.lo);
228 if (o->u32.lo >= 0x80000000u) ctx->sb.buf[ctx->sb.n-1] |= 0x10;
229 bcwrite_uleb128(ctx, o->u32.hi);
230 }
231 }
232}
233
234/* Write bytecode instructions. */
235static void bcwrite_bytecode(BCWriteCtx *ctx, GCproto *pt)
236{
237 MSize nbc = pt->sizebc-1; /* Omit the [JI]FUNC* header. */
238#if LJ_HASJIT
239 uint8_t *p = (uint8_t *)&ctx->sb.buf[ctx->sb.n];
240#endif
241 bcwrite_block(ctx, proto_bc(pt)+1, nbc*(MSize)sizeof(BCIns));
242#if LJ_HASJIT
243 /* Unpatch modified bytecode containing ILOOP/JLOOP etc. */
244 if ((pt->flags & PROTO_ILOOP) || pt->trace) {
245 jit_State *J = L2J(ctx->L);
246 MSize i;
247 for (i = 0; i < nbc; i++, p += sizeof(BCIns)) {
248 BCOp op = (BCOp)p[LJ_ENDIAN_SELECT(0, 3)];
249 if (op == BC_IFORL || op == BC_IITERL || op == BC_ILOOP ||
250 op == BC_JFORI) {
251 p[LJ_ENDIAN_SELECT(0, 3)] = (uint8_t)(op-BC_IFORL+BC_FORL);
252 } else if (op == BC_JFORL || op == BC_JITERL || op == BC_JLOOP) {
253 BCReg rd = p[LJ_ENDIAN_SELECT(2, 1)] + (p[LJ_ENDIAN_SELECT(3, 0)] << 8);
254 BCIns ins = traceref(J, rd)->startins;
255 p[LJ_ENDIAN_SELECT(0, 3)] = (uint8_t)(op-BC_JFORL+BC_FORL);
256 p[LJ_ENDIAN_SELECT(2, 1)] = bc_c(ins);
257 p[LJ_ENDIAN_SELECT(3, 0)] = bc_b(ins);
258 }
259 }
260 }
261#endif
262}
263
264/* Write prototype. */
265static void bcwrite_proto(BCWriteCtx *ctx, GCproto *pt)
266{
267 MSize sizedbg = 0;
268
269 /* Recursively write children of prototype. */
270 if ((pt->flags & PROTO_CHILD)) {
271 ptrdiff_t i, n = pt->sizekgc;
272 GCRef *kr = mref(pt->k, GCRef) - 1;
273 for (i = 0; i < n; i++, kr--) {
274 GCobj *o = gcref(*kr);
275 if (o->gch.gct == ~LJ_TPROTO)
276 bcwrite_proto(ctx, gco2pt(o));
277 }
278 }
279
280 /* Start writing the prototype info to a buffer. */
281 lj_str_resetbuf(&ctx->sb);
282 ctx->sb.n = 5; /* Leave room for final size. */
283 bcwrite_need(ctx, 4+6*5+(pt->sizebc-1)*(MSize)sizeof(BCIns)+pt->sizeuv*2);
284
285 /* Write prototype header. */
286 bcwrite_byte(ctx, (pt->flags & (PROTO_CHILD|PROTO_VARARG|PROTO_FFI)));
287 bcwrite_byte(ctx, pt->numparams);
288 bcwrite_byte(ctx, pt->framesize);
289 bcwrite_byte(ctx, pt->sizeuv);
290 bcwrite_uleb128(ctx, pt->sizekgc);
291 bcwrite_uleb128(ctx, pt->sizekn);
292 bcwrite_uleb128(ctx, pt->sizebc-1);
293 if (!ctx->strip) {
294 sizedbg = pt->sizept - (MSize)((char *)proto_lineinfo(pt) - (char *)pt);
295 bcwrite_uleb128(ctx, sizedbg);
296 if (sizedbg) {
297 bcwrite_uleb128(ctx, pt->firstline);
298 bcwrite_uleb128(ctx, pt->numline);
299 }
300 }
301
302 /* Write bytecode instructions and upvalue refs. */
303 bcwrite_bytecode(ctx, pt);
304 bcwrite_block(ctx, proto_uv(pt), pt->sizeuv*2);
305
306 /* Write constants. */
307 bcwrite_kgc(ctx, pt);
308 bcwrite_knum(ctx, pt);
309
310 /* Write debug info, if not stripped. */
311 if (sizedbg) {
312 bcwrite_need(ctx, sizedbg);
313 bcwrite_block(ctx, proto_lineinfo(pt), sizedbg);
314 }
315
316 /* Pass buffer to writer function. */
317 if (ctx->status == 0) {
318 MSize n = ctx->sb.n - 5;
319 MSize nn = 1 + lj_fls(n)/7;
320 ctx->sb.n = 5 - nn;
321 bcwrite_uleb128(ctx, n); /* Fill in final size. */
322 lua_assert(ctx->sb.n == 5);
323 ctx->status = ctx->wfunc(ctx->L, ctx->sb.buf+5-nn, nn+n, ctx->wdata);
324 }
325}
326
327/* Write header of bytecode dump. */
328static void bcwrite_header(BCWriteCtx *ctx)
329{
330 GCstr *chunkname = proto_chunkname(ctx->pt);
331 const char *name = strdata(chunkname);
332 MSize len = chunkname->len;
333 lj_str_resetbuf(&ctx->sb);
334 bcwrite_need(ctx, 5+5+len);
335 bcwrite_byte(ctx, BCDUMP_HEAD1);
336 bcwrite_byte(ctx, BCDUMP_HEAD2);
337 bcwrite_byte(ctx, BCDUMP_HEAD3);
338 bcwrite_byte(ctx, BCDUMP_VERSION);
339 bcwrite_byte(ctx, (ctx->strip ? BCDUMP_F_STRIP : 0) +
340 (LJ_BE ? BCDUMP_F_BE : 0) +
341 ((ctx->pt->flags & PROTO_FFI) ? BCDUMP_F_FFI : 0));
342 if (!ctx->strip) {
343 bcwrite_uleb128(ctx, len);
344 bcwrite_block(ctx, name, len);
345 }
346 ctx->status = ctx->wfunc(ctx->L, ctx->sb.buf, ctx->sb.n, ctx->wdata);
347}
348
349/* Write footer of bytecode dump. */
350static void bcwrite_footer(BCWriteCtx *ctx)
351{
352 if (ctx->status == 0) {
353 uint8_t zero = 0;
354 ctx->status = ctx->wfunc(ctx->L, &zero, 1, ctx->wdata);
355 }
356}
357
358/* Protected callback for bytecode writer. */
359static TValue *cpwriter(lua_State *L, lua_CFunction dummy, void *ud)
360{
361 BCWriteCtx *ctx = (BCWriteCtx *)ud;
362 UNUSED(dummy);
363 lj_str_resizebuf(L, &ctx->sb, 1024); /* Avoids resize for most prototypes. */
364 bcwrite_header(ctx);
365 bcwrite_proto(ctx, ctx->pt);
366 bcwrite_footer(ctx);
367 return NULL;
368}
369
370/* Write bytecode for a prototype. */
371int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, void *data,
372 int strip)
373{
374 BCWriteCtx ctx;
375 int status;
376 ctx.L = L;
377 ctx.pt = pt;
378 ctx.wfunc = writer;
379 ctx.wdata = data;
380 ctx.strip = strip;
381 ctx.status = 0;
382 lj_str_initbuf(&ctx.sb);
383 status = lj_vm_cpcall(L, NULL, &ctx, cpwriter);
384 if (status == 0) status = ctx.status;
385 lj_str_freebuf(G(ctx.L), &ctx.sb);
386 return status;
387}
388
diff --git a/src/lj_errmsg.h b/src/lj_errmsg.h
index 7b0c15cd..dc015ef2 100644
--- a/src/lj_errmsg.h
+++ b/src/lj_errmsg.h
@@ -84,7 +84,7 @@ ERRDEF(IOCLFL, "attempt to use a closed file")
84ERRDEF(IOSTDCL, "standard file is closed") 84ERRDEF(IOSTDCL, "standard file is closed")
85ERRDEF(OSUNIQF, "unable to generate a unique filename") 85ERRDEF(OSUNIQF, "unable to generate a unique filename")
86ERRDEF(OSDATEF, "field " LUA_QS " missing in date table") 86ERRDEF(OSDATEF, "field " LUA_QS " missing in date table")
87ERRDEF(STRDUMP, "cannot dump functions") 87ERRDEF(STRDUMP, "unable to dump given function")
88ERRDEF(STRSLC, "string slice too long") 88ERRDEF(STRSLC, "string slice too long")
89ERRDEF(STRPATB, "missing " LUA_QL("[") " after " LUA_QL("%f") " in pattern") 89ERRDEF(STRPATB, "missing " LUA_QL("[") " after " LUA_QL("%f") " in pattern")
90ERRDEF(STRPATC, "invalid pattern capture") 90ERRDEF(STRPATC, "invalid pattern capture")
@@ -119,7 +119,6 @@ ERRDEF(XLCOM, "unfinished long comment")
119ERRDEF(XSTR, "unfinished string") 119ERRDEF(XSTR, "unfinished string")
120ERRDEF(XESC, "invalid escape sequence") 120ERRDEF(XESC, "invalid escape sequence")
121ERRDEF(XLDELIM, "invalid long string delimiter") 121ERRDEF(XLDELIM, "invalid long string delimiter")
122ERRDEF(XBCLOAD, "cannot load Lua bytecode")
123ERRDEF(XTOKEN, LUA_QS " expected") 122ERRDEF(XTOKEN, LUA_QS " expected")
124ERRDEF(XJUMP, "control structure too long") 123ERRDEF(XJUMP, "control structure too long")
125ERRDEF(XSLOTS, "function or expression too complex") 124ERRDEF(XSLOTS, "function or expression too complex")
@@ -137,6 +136,10 @@ ERRDEF(XSYNTAX, "syntax error")
137ERRDEF(XBREAK, "no loop to break") 136ERRDEF(XBREAK, "no loop to break")
138ERRDEF(XFOR, LUA_QL("=") " or " LUA_QL("in") " expected") 137ERRDEF(XFOR, LUA_QL("=") " or " LUA_QL("in") " expected")
139 138
139/* Bytecode reader errors. */
140ERRDEF(BCFMT, "cannot load incompatible bytecode")
141ERRDEF(BCBAD, "cannot load malformed bytecode")
142
140#if LJ_HASFFI 143#if LJ_HASFFI
141/* FFI errors. */ 144/* FFI errors. */
142ERRDEF(FFI_INVTYPE, "invalid C type") 145ERRDEF(FFI_INVTYPE, "invalid C type")
diff --git a/src/lj_func.c b/src/lj_func.c
index d7d37802..334ba4c8 100644
--- a/src/lj_func.c
+++ b/src/lj_func.c
@@ -65,6 +65,17 @@ static GCupval *func_finduv(lua_State *L, TValue *slot)
65 return uv; 65 return uv;
66} 66}
67 67
68/* Create an empty and closed upvalue. */
69static GCupval *func_emptyuv(lua_State *L)
70{
71 GCupval *uv = (GCupval *)lj_mem_newgco(L, sizeof(GCupval));
72 uv->gct = ~LJ_TUPVAL;
73 uv->closed = 1;
74 setnilV(&uv->tv);
75 setmref(uv->v, &uv->tv);
76 return uv;
77}
78
68/* Close all open upvalues pointing to some stack level or above. */ 79/* Close all open upvalues pointing to some stack level or above. */
69void LJ_FASTCALL lj_func_closeuv(lua_State *L, TValue *level) 80void LJ_FASTCALL lj_func_closeuv(lua_State *L, TValue *level)
70{ 81{
@@ -105,30 +116,45 @@ GCfunc *lj_func_newC(lua_State *L, MSize nelems, GCtab *env)
105 return fn; 116 return fn;
106} 117}
107 118
108GCfunc *lj_func_newL(lua_State *L, GCproto *pt, GCtab *env) 119static GCfunc *func_newL(lua_State *L, GCproto *pt, GCtab *env)
109{ 120{
110 GCfunc *fn = (GCfunc *)lj_mem_newgco(L, sizeLfunc((MSize)pt->sizeuv)); 121 GCfunc *fn = (GCfunc *)lj_mem_newgco(L, sizeLfunc((MSize)pt->sizeuv));
111 fn->l.gct = ~LJ_TFUNC; 122 fn->l.gct = ~LJ_TFUNC;
112 fn->l.ffid = FF_LUA; 123 fn->l.ffid = FF_LUA;
113 fn->l.nupvalues = (uint8_t)pt->sizeuv; 124 fn->l.nupvalues = 0; /* Set to zero until upvalues are initialized. */
114 /* NOBARRIER: Really a setgcref. But the GCfunc is new (marked white). */ 125 /* NOBARRIER: Really a setgcref. But the GCfunc is new (marked white). */
115 setmref(fn->l.pc, proto_bc(pt)); 126 setmref(fn->l.pc, proto_bc(pt));
116 setgcref(fn->l.env, obj2gco(env)); 127 setgcref(fn->l.env, obj2gco(env));
117 return fn; 128 return fn;
118} 129}
119 130
131/* Create a new Lua function with empty upvalues. */
132GCfunc *lj_func_newL_empty(lua_State *L, GCproto *pt, GCtab *env)
133{
134 GCfunc *fn = func_newL(L, pt, env);
135 MSize i, nuv = pt->sizeuv;
136 /* NOBARRIER: The GCfunc is new (marked white). */
137 for (i = 0; i < nuv; i++) {
138 GCupval *uv = func_emptyuv(L);
139 uv->dhash = (uint32_t)(uintptr_t)pt ^ ((uint32_t)proto_uv(pt)[i] << 24);
140 setgcref(fn->l.uvptr[i], obj2gco(uv));
141 }
142 fn->l.nupvalues = (uint8_t)nuv;
143 return fn;
144}
145
120/* Do a GC check and create a new Lua function with inherited upvalues. */ 146/* Do a GC check and create a new Lua function with inherited upvalues. */
121GCfunc *lj_func_newL_gc(lua_State *L, GCproto *pt, GCfuncL *parent) 147GCfunc *lj_func_newL_gc(lua_State *L, GCproto *pt, GCfuncL *parent)
122{ 148{
123 GCfunc *fn; 149 GCfunc *fn;
124 GCRef *puv; 150 GCRef *puv;
125 uint32_t i, nuv; 151 MSize i, nuv;
126 TValue *base; 152 TValue *base;
127 lj_gc_check_fixtop(L); 153 lj_gc_check_fixtop(L);
128 fn = lj_func_newL(L, pt, tabref(parent->env)); 154 fn = func_newL(L, pt, tabref(parent->env));
129 /* NOBARRIER: The GCfunc is new (marked white). */ 155 /* NOBARRIER: The GCfunc is new (marked white). */
130 puv = parent->uvptr; 156 puv = parent->uvptr;
131 nuv = fn->l.nupvalues; 157 nuv = pt->sizeuv;
132 base = L->base; 158 base = L->base;
133 for (i = 0; i < nuv; i++) { 159 for (i = 0; i < nuv; i++) {
134 uint32_t v = proto_uv(pt)[i]; 160 uint32_t v = proto_uv(pt)[i];
@@ -141,6 +167,7 @@ GCfunc *lj_func_newL_gc(lua_State *L, GCproto *pt, GCfuncL *parent)
141 } 167 }
142 setgcref(fn->l.uvptr[i], obj2gco(uv)); 168 setgcref(fn->l.uvptr[i], obj2gco(uv));
143 } 169 }
170 fn->l.nupvalues = (uint8_t)nuv;
144 return fn; 171 return fn;
145} 172}
146 173
diff --git a/src/lj_func.h b/src/lj_func.h
index 7a3a2e3f..6ec4ab95 100644
--- a/src/lj_func.h
+++ b/src/lj_func.h
@@ -17,7 +17,7 @@ LJ_FUNC void LJ_FASTCALL lj_func_freeuv(global_State *g, GCupval *uv);
17 17
18/* Functions (closures). */ 18/* Functions (closures). */
19LJ_FUNC GCfunc *lj_func_newC(lua_State *L, MSize nelems, GCtab *env); 19LJ_FUNC GCfunc *lj_func_newC(lua_State *L, MSize nelems, GCtab *env);
20LJ_FUNC GCfunc *lj_func_newL(lua_State *L, GCproto *pt, GCtab *env); 20LJ_FUNC GCfunc *lj_func_newL_empty(lua_State *L, GCproto *pt, GCtab *env);
21LJ_FUNCA GCfunc *lj_func_newL_gc(lua_State *L, GCproto *pt, GCfuncL *parent); 21LJ_FUNCA GCfunc *lj_func_newL_gc(lua_State *L, GCproto *pt, GCfuncL *parent);
22LJ_FUNC void LJ_FASTCALL lj_func_free(global_State *g, GCfunc *c); 22LJ_FUNC void LJ_FASTCALL lj_func_free(global_State *g, GCfunc *c);
23 23
diff --git a/src/lj_gc.c b/src/lj_gc.c
index b5614ea2..1985abc7 100644
--- a/src/lj_gc.c
+++ b/src/lj_gc.c
@@ -204,7 +204,7 @@ static void gc_traverse_func(global_State *g, GCfunc *fn)
204 gc_markobj(g, tabref(fn->c.env)); 204 gc_markobj(g, tabref(fn->c.env));
205 if (isluafunc(fn)) { 205 if (isluafunc(fn)) {
206 uint32_t i; 206 uint32_t i;
207 lua_assert(fn->l.nupvalues == funcproto(fn)->sizeuv); 207 lua_assert(fn->l.nupvalues <= funcproto(fn)->sizeuv);
208 gc_markobj(g, funcproto(fn)); 208 gc_markobj(g, funcproto(fn));
209 for (i = 0; i < fn->l.nupvalues; i++) /* Mark Lua function upvalues. */ 209 for (i = 0; i < fn->l.nupvalues; i++) /* Mark Lua function upvalues. */
210 gc_markobj(g, &gcref(fn->l.uvptr[i])->uv); 210 gc_markobj(g, &gcref(fn->l.uvptr[i])->uv);
diff --git a/src/lj_lex.c b/src/lj_lex.c
index 3411aa56..01e0c641 100644
--- a/src/lj_lex.c
+++ b/src/lj_lex.c
@@ -408,7 +408,7 @@ static int llex(LexState *ls, TValue *tv)
408/* -- Lexer API ----------------------------------------------------------- */ 408/* -- Lexer API ----------------------------------------------------------- */
409 409
410/* Setup lexer state. */ 410/* Setup lexer state. */
411void lj_lex_setup(lua_State *L, LexState *ls) 411int lj_lex_setup(lua_State *L, LexState *ls)
412{ 412{
413 ls->L = L; 413 ls->L = L;
414 ls->fs = NULL; 414 ls->fs = NULL;
@@ -433,14 +433,11 @@ void lj_lex_setup(lua_State *L, LexState *ls)
433 if (ls->current == '#') { /* Skip POSIX #! header line. */ 433 if (ls->current == '#') { /* Skip POSIX #! header line. */
434 do { 434 do {
435 next(ls); 435 next(ls);
436 if (ls->current == END_OF_STREAM) return; 436 if (ls->current == END_OF_STREAM) return 0;
437 } while (!currIsNewline(ls)); 437 } while (!currIsNewline(ls));
438 inclinenumber(ls); 438 inclinenumber(ls);
439 } 439 }
440 if (ls->current == LUA_SIGNATURE[0]) { 440 return (ls->current == LUA_SIGNATURE[0]); /* Bytecode dump? */
441 setstrV(L, L->top++, lj_err_str(L, LJ_ERR_XBCLOAD));
442 lj_err_throw(L, LUA_ERRSYNTAX);
443 }
444} 441}
445 442
446/* Cleanup lexer state. */ 443/* Cleanup lexer state. */
diff --git a/src/lj_lex.h b/src/lj_lex.h
index 78a7e1a9..1ddf4b59 100644
--- a/src/lj_lex.h
+++ b/src/lj_lex.h
@@ -71,7 +71,7 @@ typedef struct LexState {
71 uint32_t level; /* Syntactical nesting level. */ 71 uint32_t level; /* Syntactical nesting level. */
72} LexState; 72} LexState;
73 73
74LJ_FUNC void lj_lex_setup(lua_State *L, LexState *ls); 74LJ_FUNC int lj_lex_setup(lua_State *L, LexState *ls);
75LJ_FUNC void lj_lex_cleanup(lua_State *L, LexState *ls); 75LJ_FUNC void lj_lex_cleanup(lua_State *L, LexState *ls);
76LJ_FUNC void lj_lex_next(LexState *ls); 76LJ_FUNC void lj_lex_next(LexState *ls);
77LJ_FUNC LexToken lj_lex_lookahead(LexState *ls); 77LJ_FUNC LexToken lj_lex_lookahead(LexState *ls);
diff --git a/src/lj_obj.h b/src/lj_obj.h
index 3442dc0c..7cdc4a1a 100644
--- a/src/lj_obj.h
+++ b/src/lj_obj.h
@@ -310,11 +310,11 @@ typedef struct GCproto {
310} GCproto; 310} GCproto;
311 311
312/* Flags for prototype. */ 312/* Flags for prototype. */
313#define PROTO_VARARG 0x01 /* Vararg function. */ 313#define PROTO_CHILD 0x01 /* Has child prototypes. */
314#define PROTO_CHILD 0x02 /* Has child prototypes. */ 314#define PROTO_VARARG 0x02 /* Vararg function. */
315#define PROTO_NOJIT 0x04 /* JIT disabled for this function. */ 315#define PROTO_FFI 0x04 /* Uses BC_KCDATA for FFI datatypes. */
316#define PROTO_ILOOP 0x08 /* Patched bytecode with ILOOP etc. */ 316#define PROTO_NOJIT 0x08 /* JIT disabled for this function. */
317#define PROTO_FFI 0x10 /* Uses BC_KCDATA for FFI datatypes. */ 317#define PROTO_ILOOP 0x10 /* Patched bytecode with ILOOP etc. */
318/* Only used during parsing. */ 318/* Only used during parsing. */
319#define PROTO_HAS_RETURN 0x20 /* Already emitted a return. */ 319#define PROTO_HAS_RETURN 0x20 /* Already emitted a return. */
320#define PROTO_FIXUP_RETURN 0x40 /* Need to fixup emitted returns. */ 320#define PROTO_FIXUP_RETURN 0x40 /* Need to fixup emitted returns. */
diff --git a/src/ljamalg.c b/src/ljamalg.c
index fcfb77ff..57ad7851 100644
--- a/src/ljamalg.c
+++ b/src/ljamalg.c
@@ -46,6 +46,8 @@
46#include "lj_api.c" 46#include "lj_api.c"
47#include "lj_lex.c" 47#include "lj_lex.c"
48#include "lj_parse.c" 48#include "lj_parse.c"
49#include "lj_bcread.c"
50#include "lj_bcwrite.c"
49#include "lj_ctype.c" 51#include "lj_ctype.c"
50#include "lj_cdata.c" 52#include "lj_cdata.c"
51#include "lj_cconv.c" 53#include "lj_cconv.c"