aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/host/genlibbc.lua91
-rw-r--r--src/jit/bcsave.lua31
-rw-r--r--src/lib_base.c6
-rw-r--r--src/lib_jit.c26
-rw-r--r--src/lib_string.c22
-rw-r--r--src/lj_bcdump.h4
-rw-r--r--src/lj_bcread.c9
-rw-r--r--src/lj_bcwrite.c109
-rw-r--r--src/lj_lex.c1
-rw-r--r--src/lj_lex.h1
-rw-r--r--src/lj_lib.c18
-rw-r--r--src/lj_lib.h1
-rw-r--r--src/lj_load.c29
-rw-r--r--src/lj_parse.c28
14 files changed, 260 insertions, 116 deletions
diff --git a/src/host/genlibbc.lua b/src/host/genlibbc.lua
index 3621c3f5..e697fceb 100644
--- a/src/host/genlibbc.lua
+++ b/src/host/genlibbc.lua
@@ -138,65 +138,73 @@ local function fixup_dump(dump, fixup)
138 return { dump = ndump, startbc = startbc, sizebc = sizebc } 138 return { dump = ndump, startbc = startbc, sizebc = sizebc }
139end 139end
140 140
141local function find_defs(src) 141local function find_defs(src, mode)
142 local defs = {} 142 local defs = {}
143 for name, code in string.gmatch(src, "LJLIB_LUA%(([^)]*)%)%s*/%*(.-)%*/") do 143 for name, code in string.gmatch(src, "LJLIB_LUA%(([^)]*)%)%s*/%*(.-)%*/") do
144 local env = {}
145 local tcode, fixup = transform_lua(code) 144 local tcode, fixup = transform_lua(code)
146 local func = assert(load(tcode, "", nil, env))() 145 local func = assert(load(tcode, "", mode))
147 defs[name] = fixup_dump(string.dump(func, true), fixup) 146 defs[name] = fixup_dump(string.dump(func, mode), fixup)
148 defs[#defs+1] = name 147 defs[#defs+1] = name
149 end 148 end
150 return defs 149 return defs
151end 150end
152 151
153local function gen_header(defs) 152local function gen_header(defs32, defs64)
154 local t = {} 153 local t = {}
155 local function w(x) t[#t+1] = x end 154 local function w(x) t[#t+1] = x end
156 w("/* This is a generated file. DO NOT EDIT! */\n\n") 155 w("/* This is a generated file. DO NOT EDIT! */\n\n")
157 w("static const int libbc_endian = ") w(isbe and 1 or 0) w(";\n\n") 156 w("static const int libbc_endian = ") w(isbe and 1 or 0) w(";\n\n")
158 local s, sb = "", "" 157 for j,defs in ipairs{defs64, defs32} do
159 for i,name in ipairs(defs) do 158 local s, sb = "", ""
160 local d = defs[name] 159 for i,name in ipairs(defs) do
161 s = s .. d.dump 160 local d = defs[name]
162 sb = sb .. string.char(i) .. ("\0"):rep(d.startbc - 1) 161 s = s .. d.dump
163 .. (isbe and "\0\0\0\255" or "\255\0\0\0"):rep(d.sizebc) 162 sb = sb .. string.char(i) .. ("\0"):rep(d.startbc - 1)
164 .. ("\0"):rep(#d.dump - d.startbc - d.sizebc*4) 163 .. (isbe and "\0\0\0\255" or "\255\0\0\0"):rep(d.sizebc)
165 end 164 .. ("\0"):rep(#d.dump - d.startbc - d.sizebc*4)
166 w("static const uint8_t libbc_code[] = {\n") 165 end
167 local n = 0 166 if j == 1 then
168 for i=1,#s do 167 w("static const uint8_t libbc_code[] = {\n#if LJ_FR2\n")
169 local x = string.byte(s, i)
170 local xb = string.byte(sb, i)
171 if xb == 255 then
172 local name = BCN[x]
173 local m = #name + 4
174 if n + m > 78 then n = 0; w("\n") end
175 n = n + m
176 w("BC_"); w(name)
177 else 168 else
178 local m = x < 10 and 2 or (x < 100 and 3 or 4) 169 w("\n#else\n")
179 if xb == 0 then 170 end
171 local n = 0
172 for i=1,#s do
173 local x = string.byte(s, i)
174 local xb = string.byte(sb, i)
175 if xb == 255 then
176 local name = BCN[x]
177 local m = #name + 4
180 if n + m > 78 then n = 0; w("\n") end 178 if n + m > 78 then n = 0; w("\n") end
179 n = n + m
180 w("BC_"); w(name)
181 else 181 else
182 local name = defs[xb]:gsub("_", ".") 182 local m = x < 10 and 2 or (x < 100 and 3 or 4)
183 if n ~= 0 then w("\n") end 183 if xb == 0 then
184 w("/* "); w(name); w(" */ ") 184 if n + m > 78 then n = 0; w("\n") end
185 n = #name + 7 185 else
186 local name = defs[xb]:gsub("_", ".")
187 if n ~= 0 then w("\n") end
188 w("/* "); w(name); w(" */ ")
189 n = #name + 7
190 end
191 n = n + m
192 w(x)
186 end 193 end
187 n = n + m 194 w(",")
188 w(x)
189 end 195 end
190 w(",")
191 end 196 end
192 w("\n0\n};\n\n") 197 w("\n#endif\n0\n};\n\n")
193 w("static const struct { const char *name; int ofs; } libbc_map[] = {\n") 198 w("static const struct { const char *name; int ofs; } libbc_map[] = {\n")
194 local m = 0 199 local m32, m64 = 0, 0
195 for _,name in ipairs(defs) do 200 for i,name in ipairs(defs32) do
196 w('{"'); w(name); w('",'); w(m) w('},\n') 201 assert(name == defs64[i])
197 m = m + #defs[name].dump 202 w('{"'); w(name); w('",'); w(m32) w('},\n')
203 m32 = m32 + #defs32[name].dump
204 m64 = m64 + #defs64[name].dump
205 assert(m32 == m64)
198 end 206 end
199 w("{NULL,"); w(m); w("}\n};\n\n") 207 w("{NULL,"); w(m32); w("}\n};\n\n")
200 return table.concat(t) 208 return table.concat(t)
201end 209end
202 210
@@ -219,7 +227,8 @@ end
219 227
220local outfile = parse_arg(arg) 228local outfile = parse_arg(arg)
221local src = read_files(arg) 229local src = read_files(arg)
222local defs = find_defs(src) 230local defs32 = find_defs(src, "Wdts")
223local hdr = gen_header(defs) 231local defs64 = find_defs(src, "Xdts")
232local hdr = gen_header(defs32, defs64)
224write_file(outfile, hdr) 233write_file(outfile, hdr)
225 234
diff --git a/src/jit/bcsave.lua b/src/jit/bcsave.lua
index 390d297c..131bf39b 100644
--- a/src/jit/bcsave.lua
+++ b/src/jit/bcsave.lua
@@ -29,6 +29,9 @@ Save LuaJIT bytecode: luajit -b[options] input output
29 -l Only list bytecode. 29 -l Only list bytecode.
30 -s Strip debug info (default). 30 -s Strip debug info (default).
31 -g Keep debug info. 31 -g Keep debug info.
32 -W Generate 32 bit (non-GC64) bytecode.
33 -X Generate 64 bit (GC64) bytecode.
34 -d Generate bytecode in deterministic manner.
32 -n name Set module name (default: auto-detect from input name). 35 -n name Set module name (default: auto-detect from input name).
33 -t type Set output file type (default: auto-detect from output name). 36 -t type Set output file type (default: auto-detect from output name).
34 -a arch Override architecture for object files (default: native). 37 -a arch Override architecture for object files (default: native).
@@ -51,8 +54,9 @@ local function check(ok, ...)
51end 54end
52 55
53local function readfile(ctx, input) 56local function readfile(ctx, input)
54 if type(input) == "function" then return input end 57 if ctx.string then
55 if ctx.filename then 58 return check(loadstring(input, nil, ctx.mode))
59 elseif ctx.filename then
56 local data 60 local data
57 if input == "-" then 61 if input == "-" then
58 data = io.stdin:read("*a") 62 data = io.stdin:read("*a")
@@ -61,10 +65,10 @@ local function readfile(ctx, input)
61 data = assert(fp:read("*a")) 65 data = assert(fp:read("*a"))
62 assert(fp:close()) 66 assert(fp:close())
63 end 67 end
64 return check(load(data, ctx.filename)) 68 return check(load(data, ctx.filename, ctx.mode))
65 else 69 else
66 if input == "-" then input = nil end 70 if input == "-" then input = nil end
67 return check(loadfile(input)) 71 return check(loadfile(input, ctx.mode))
68 end 72 end
69end 73end
70 74
@@ -624,7 +628,7 @@ end
624 628
625local function bcsave(ctx, input, output) 629local function bcsave(ctx, input, output)
626 local f = readfile(ctx, input) 630 local f = readfile(ctx, input)
627 local s = string.dump(f, ctx.strip) 631 local s = string.dump(f, ctx.mode)
628 local t = ctx.type 632 local t = ctx.type
629 if not t then 633 if not t then
630 t = detecttype(output) 634 t = detecttype(output)
@@ -647,9 +651,11 @@ local function docmd(...)
647 local n = 1 651 local n = 1
648 local list = false 652 local list = false
649 local ctx = { 653 local ctx = {
650 strip = true, arch = jit.arch, os = jit.os:lower(), 654 mode = "bt", arch = jit.arch, os = jit.os:lower(),
651 type = false, modname = false, 655 type = false, modname = false, string = false,
652 } 656 }
657 local strip = "s"
658 local gc64 = ""
653 while n <= #arg do 659 while n <= #arg do
654 local a = arg[n] 660 local a = arg[n]
655 if type(a) == "string" and a:sub(1, 1) == "-" and a ~= "-" then 661 if type(a) == "string" and a:sub(1, 1) == "-" and a ~= "-" then
@@ -660,14 +666,18 @@ local function docmd(...)
660 if opt == "l" then 666 if opt == "l" then
661 list = true 667 list = true
662 elseif opt == "s" then 668 elseif opt == "s" then
663 ctx.strip = true 669 strip = "s"
664 elseif opt == "g" then 670 elseif opt == "g" then
665 ctx.strip = false 671 strip = ""
672 elseif opt == "W" or opt == "X" then
673 gc64 = opt
674 elseif opt == "d" then
675 ctx.mode = ctx.mode .. opt
666 else 676 else
667 if arg[n] == nil or m ~= #a then usage() end 677 if arg[n] == nil or m ~= #a then usage() end
668 if opt == "e" then 678 if opt == "e" then
669 if n ~= 1 then usage() end 679 if n ~= 1 then usage() end
670 arg[1] = check(loadstring(arg[1])) 680 ctx.string = true
671 elseif opt == "n" then 681 elseif opt == "n" then
672 ctx.modname = checkmodname(tremove(arg, n)) 682 ctx.modname = checkmodname(tremove(arg, n))
673 elseif opt == "t" then 683 elseif opt == "t" then
@@ -687,6 +697,7 @@ local function docmd(...)
687 n = n + 1 697 n = n + 1
688 end 698 end
689 end 699 end
700 ctx.mode = ctx.mode .. strip .. gc64
690 if list then 701 if list then
691 if #arg == 0 or #arg > 2 then usage() end 702 if #arg == 0 or #arg > 2 then usage() end
692 bclist(ctx, arg[1], arg[2] or "-") 703 bclist(ctx, arg[1], arg[2] or "-")
diff --git a/src/lib_base.c b/src/lib_base.c
index 4e6f8a30..d644b4f2 100644
--- a/src/lib_base.c
+++ b/src/lib_base.c
@@ -360,7 +360,11 @@ LJLIB_ASM_(xpcall) LJLIB_REC(.)
360static int load_aux(lua_State *L, int status, int envarg) 360static int load_aux(lua_State *L, int status, int envarg)
361{ 361{
362 if (status == LUA_OK) { 362 if (status == LUA_OK) {
363 if (tvistab(L->base+envarg-1)) { 363 /*
364 ** Set environment table for top-level function.
365 ** Don't do this for non-native bytecode, which returns a prototype.
366 */
367 if (tvistab(L->base+envarg-1) && tvisfunc(L->top-1)) {
364 GCfunc *fn = funcV(L->top-1); 368 GCfunc *fn = funcV(L->top-1);
365 GCtab *t = tabV(L->base+envarg-1); 369 GCtab *t = tabV(L->base+envarg-1);
366 setgcref(fn->c.env, obj2gco(t)); 370 setgcref(fn->c.env, obj2gco(t));
diff --git a/src/lib_jit.c b/src/lib_jit.c
index c0294927..b83c865a 100644
--- a/src/lib_jit.c
+++ b/src/lib_jit.c
@@ -161,24 +161,6 @@ LJLIB_PUSH(top-2) LJLIB_SET(version)
161 161
162/* -- Reflection API for Lua functions ------------------------------------ */ 162/* -- Reflection API for Lua functions ------------------------------------ */
163 163
164/* Return prototype of first argument (Lua function or prototype object) */
165static GCproto *check_Lproto(lua_State *L, int nolua)
166{
167 TValue *o = L->base;
168 if (L->top > o) {
169 if (tvisproto(o)) {
170 return protoV(o);
171 } else if (tvisfunc(o)) {
172 if (isluafunc(funcV(o)))
173 return funcproto(funcV(o));
174 else if (nolua)
175 return NULL;
176 }
177 }
178 lj_err_argt(L, 1, LUA_TFUNCTION);
179 return NULL; /* unreachable */
180}
181
182static void setintfield(lua_State *L, GCtab *t, const char *name, int32_t val) 164static void setintfield(lua_State *L, GCtab *t, const char *name, int32_t val)
183{ 165{
184 setintV(lj_tab_setstr(L, t, lj_str_newz(L, name)), val); 166 setintV(lj_tab_setstr(L, t, lj_str_newz(L, name)), val);
@@ -187,7 +169,7 @@ static void setintfield(lua_State *L, GCtab *t, const char *name, int32_t val)
187/* local info = jit.util.funcinfo(func [,pc]) */ 169/* local info = jit.util.funcinfo(func [,pc]) */
188LJLIB_CF(jit_util_funcinfo) 170LJLIB_CF(jit_util_funcinfo)
189{ 171{
190 GCproto *pt = check_Lproto(L, 1); 172 GCproto *pt = lj_lib_checkLproto(L, 1, 1);
191 if (pt) { 173 if (pt) {
192 BCPos pc = (BCPos)lj_lib_optint(L, 2, 0); 174 BCPos pc = (BCPos)lj_lib_optint(L, 2, 0);
193 GCtab *t; 175 GCtab *t;
@@ -229,7 +211,7 @@ LJLIB_CF(jit_util_funcinfo)
229/* local ins, m = jit.util.funcbc(func, pc) */ 211/* local ins, m = jit.util.funcbc(func, pc) */
230LJLIB_CF(jit_util_funcbc) 212LJLIB_CF(jit_util_funcbc)
231{ 213{
232 GCproto *pt = check_Lproto(L, 0); 214 GCproto *pt = lj_lib_checkLproto(L, 1, 0);
233 BCPos pc = (BCPos)lj_lib_checkint(L, 2); 215 BCPos pc = (BCPos)lj_lib_checkint(L, 2);
234 if (pc < pt->sizebc) { 216 if (pc < pt->sizebc) {
235 BCIns ins = proto_bc(pt)[pc]; 217 BCIns ins = proto_bc(pt)[pc];
@@ -246,7 +228,7 @@ LJLIB_CF(jit_util_funcbc)
246/* local k = jit.util.funck(func, idx) */ 228/* local k = jit.util.funck(func, idx) */
247LJLIB_CF(jit_util_funck) 229LJLIB_CF(jit_util_funck)
248{ 230{
249 GCproto *pt = check_Lproto(L, 0); 231 GCproto *pt = lj_lib_checkLproto(L, 1, 0);
250 ptrdiff_t idx = (ptrdiff_t)lj_lib_checkint(L, 2); 232 ptrdiff_t idx = (ptrdiff_t)lj_lib_checkint(L, 2);
251 if (idx >= 0) { 233 if (idx >= 0) {
252 if (idx < (ptrdiff_t)pt->sizekn) { 234 if (idx < (ptrdiff_t)pt->sizekn) {
@@ -266,7 +248,7 @@ LJLIB_CF(jit_util_funck)
266/* local name = jit.util.funcuvname(func, idx) */ 248/* local name = jit.util.funcuvname(func, idx) */
267LJLIB_CF(jit_util_funcuvname) 249LJLIB_CF(jit_util_funcuvname)
268{ 250{
269 GCproto *pt = check_Lproto(L, 0); 251 GCproto *pt = lj_lib_checkLproto(L, 1, 0);
270 uint32_t idx = (uint32_t)lj_lib_checkint(L, 2); 252 uint32_t idx = (uint32_t)lj_lib_checkint(L, 2);
271 if (idx < pt->sizeuv) { 253 if (idx < pt->sizeuv) {
272 setstrV(L, L->top-1, lj_str_newz(L, lj_debug_uvname(pt, idx))); 254 setstrV(L, L->top-1, lj_str_newz(L, lj_debug_uvname(pt, idx)));
diff --git a/src/lib_string.c b/src/lib_string.c
index 29bcb8fe..255689ce 100644
--- a/src/lib_string.c
+++ b/src/lib_string.c
@@ -122,11 +122,25 @@ static int writer_buf(lua_State *L, const void *p, size_t size, void *sb)
122 122
123LJLIB_CF(string_dump) 123LJLIB_CF(string_dump)
124{ 124{
125 GCfunc *fn = lj_lib_checkfunc(L, 1); 125 GCproto *pt = lj_lib_checkLproto(L, 1, 1);
126 int strip = L->base+1 < L->top && tvistruecond(L->base+1); 126 uint32_t flags = 0;
127 SBuf *sb = lj_buf_tmp_(L); /* Assumes lj_bcwrite() doesn't use tmpbuf. */ 127 SBuf *sb;
128 TValue *o = L->base+1;
129 if (o < L->top) {
130 if (tvisstr(o)) {
131 const char *mode = strVdata(o);
132 char c;
133 while ((c = *mode++)) {
134 if (c == 's') flags |= BCDUMP_F_STRIP;
135 if (c == 'd') flags |= BCDUMP_F_DETERMINISTIC;
136 }
137 } else if (tvistruecond(o)) {
138 flags |= BCDUMP_F_STRIP;
139 }
140 }
141 sb = lj_buf_tmp_(L); /* Assumes lj_bcwrite() doesn't use tmpbuf. */
128 L->top = L->base+1; 142 L->top = L->base+1;
129 if (!isluafunc(fn) || lj_bcwrite(L, funcproto(fn), writer_buf, sb, strip)) 143 if (!pt || lj_bcwrite(L, pt, writer_buf, sb, flags))
130 lj_err_caller(L, LJ_ERR_STRDUMP); 144 lj_err_caller(L, LJ_ERR_STRDUMP);
131 setstrV(L, L->top-1, lj_buf_str(L, sb)); 145 setstrV(L, L->top-1, lj_buf_str(L, sb));
132 lj_gc_check(L); 146 lj_gc_check(L);
diff --git a/src/lj_bcdump.h b/src/lj_bcdump.h
index 6ba71e25..3e56e39c 100644
--- a/src/lj_bcdump.h
+++ b/src/lj_bcdump.h
@@ -46,6 +46,8 @@
46 46
47#define BCDUMP_F_KNOWN (BCDUMP_F_FR2*2-1) 47#define BCDUMP_F_KNOWN (BCDUMP_F_FR2*2-1)
48 48
49#define BCDUMP_F_DETERMINISTIC 0x80000000
50
49/* Type codes for the GC constants of a prototype. Plus length for strings. */ 51/* Type codes for the GC constants of a prototype. Plus length for strings. */
50enum { 52enum {
51 BCDUMP_KGC_CHILD, BCDUMP_KGC_TAB, BCDUMP_KGC_I64, BCDUMP_KGC_U64, 53 BCDUMP_KGC_CHILD, BCDUMP_KGC_TAB, BCDUMP_KGC_I64, BCDUMP_KGC_U64,
@@ -61,7 +63,7 @@ enum {
61/* -- Bytecode reader/writer ---------------------------------------------- */ 63/* -- Bytecode reader/writer ---------------------------------------------- */
62 64
63LJ_FUNC int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, 65LJ_FUNC int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer,
64 void *data, int strip); 66 void *data, uint32_t flags);
65LJ_FUNC GCproto *lj_bcread_proto(LexState *ls); 67LJ_FUNC GCproto *lj_bcread_proto(LexState *ls);
66LJ_FUNC GCproto *lj_bcread(LexState *ls); 68LJ_FUNC GCproto *lj_bcread(LexState *ls);
67 69
diff --git a/src/lj_bcread.c b/src/lj_bcread.c
index c98c0d42..637ef067 100644
--- a/src/lj_bcread.c
+++ b/src/lj_bcread.c
@@ -281,8 +281,11 @@ static void bcread_knum(LexState *ls, GCproto *pt, MSize sizekn)
281static void bcread_bytecode(LexState *ls, GCproto *pt, MSize sizebc) 281static void bcread_bytecode(LexState *ls, GCproto *pt, MSize sizebc)
282{ 282{
283 BCIns *bc = proto_bc(pt); 283 BCIns *bc = proto_bc(pt);
284 bc[0] = BCINS_AD((pt->flags & PROTO_VARARG) ? BC_FUNCV : BC_FUNCF, 284 BCIns op;
285 pt->framesize, 0); 285 if (ls->fr2 != LJ_FR2) op = BC_NOT; /* Mark non-native prototype. */
286 else if ((pt->flags & PROTO_VARARG)) op = BC_FUNCV;
287 else op = BC_FUNCF;
288 bc[0] = BCINS_AD(op, pt->framesize, 0);
286 bcread_block(ls, bc+1, (sizebc-1)*(MSize)sizeof(BCIns)); 289 bcread_block(ls, bc+1, (sizebc-1)*(MSize)sizeof(BCIns));
287 /* Swap bytecode instructions if the endianess differs. */ 290 /* Swap bytecode instructions if the endianess differs. */
288 if (bcread_swap(ls)) { 291 if (bcread_swap(ls)) {
@@ -395,7 +398,7 @@ static int bcread_header(LexState *ls)
395 bcread_byte(ls) != BCDUMP_VERSION) return 0; 398 bcread_byte(ls) != BCDUMP_VERSION) return 0;
396 bcread_flags(ls) = flags = bcread_uleb128(ls); 399 bcread_flags(ls) = flags = bcread_uleb128(ls);
397 if ((flags & ~(BCDUMP_F_KNOWN)) != 0) return 0; 400 if ((flags & ~(BCDUMP_F_KNOWN)) != 0) return 0;
398 if ((flags & BCDUMP_F_FR2) != LJ_FR2*BCDUMP_F_FR2) return 0; 401 if ((flags & BCDUMP_F_FR2) != (uint32_t)ls->fr2*BCDUMP_F_FR2) return 0;
399 if ((flags & BCDUMP_F_FFI)) { 402 if ((flags & BCDUMP_F_FFI)) {
400#if LJ_HASFFI 403#if LJ_HASFFI
401 lua_State *L = ls->L; 404 lua_State *L = ls->L;
diff --git a/src/lj_bcwrite.c b/src/lj_bcwrite.c
index dd969413..c062dc49 100644
--- a/src/lj_bcwrite.c
+++ b/src/lj_bcwrite.c
@@ -27,7 +27,9 @@ typedef struct BCWriteCtx {
27 GCproto *pt; /* Root prototype. */ 27 GCproto *pt; /* Root prototype. */
28 lua_Writer wfunc; /* Writer callback. */ 28 lua_Writer wfunc; /* Writer callback. */
29 void *wdata; /* Writer callback data. */ 29 void *wdata; /* Writer callback data. */
30 int strip; /* Strip debug info. */ 30 TValue **heap; /* Heap used for deterministic sorting. */
31 uint32_t heapsz; /* Size of heap. */
32 uint32_t flags; /* BCDUMP_F_* flags. */
31 int status; /* Status from writer callback. */ 33 int status; /* Status from writer callback. */
32#ifdef LUA_USE_ASSERT 34#ifdef LUA_USE_ASSERT
33 global_State *g; 35 global_State *g;
@@ -76,6 +78,75 @@ static void bcwrite_ktabk(BCWriteCtx *ctx, cTValue *o, int narrow)
76 ctx->sb.w = p; 78 ctx->sb.w = p;
77} 79}
78 80
81/* Compare two template table keys. */
82static LJ_AINLINE int bcwrite_ktabk_lt(TValue *a, TValue *b)
83{
84 uint32_t at = itype(a), bt = itype(b);
85 if (at != bt) { /* This also handles false and true keys. */
86 return at < bt;
87 } else if (at == LJ_TSTR) {
88 return lj_str_cmp(strV(a), strV(b)) < 0;
89 } else {
90 return a->u64 < b->u64; /* This works for numbers and integers. */
91 }
92}
93
94/* Insert key into a sorted heap. */
95static void bcwrite_ktabk_heap_insert(TValue **heap, MSize idx, MSize end,
96 TValue *key)
97{
98 MSize child;
99 while ((child = idx * 2 + 1) < end) {
100 /* Find lower of the two children. */
101 TValue *c0 = heap[child];
102 if (child + 1 < end) {
103 TValue *c1 = heap[child + 1];
104 if (bcwrite_ktabk_lt(c1, c0)) {
105 c0 = c1;
106 child++;
107 }
108 }
109 if (bcwrite_ktabk_lt(key, c0)) break; /* Key lower? Found our position. */
110 heap[idx] = c0; /* Move lower child up. */
111 idx = child; /* Descend. */
112 }
113 heap[idx] = key; /* Insert key here. */
114}
115
116/* Resize heap, dropping content. */
117static void bcwrite_heap_resize(BCWriteCtx *ctx, uint32_t nsz)
118{
119 lua_State *L = sbufL(&ctx->sb);
120 if (ctx->heapsz) {
121 lj_mem_freevec(G(L), ctx->heap, ctx->heapsz, TValue *);
122 ctx->heapsz = 0;
123 }
124 if (nsz) {
125 ctx->heap = lj_mem_newvec(L, nsz, TValue *);
126 ctx->heapsz = nsz;
127 }
128}
129
130/* Write hash part of template table in sorted order. */
131static void bcwrite_ktab_sorted_hash(BCWriteCtx *ctx, Node *node, MSize nhash)
132{
133 TValue **heap = ctx->heap;
134 MSize i = nhash;
135 for (;; node--) { /* Build heap. */
136 if (!tvisnil(&node->val)) {
137 bcwrite_ktabk_heap_insert(heap, --i, nhash, &node->key);
138 if (i == 0) break;
139 }
140 }
141 do { /* Drain heap. */
142 TValue *key = heap[0]; /* Output lowest key from top. */
143 bcwrite_ktabk(ctx, key, 0);
144 bcwrite_ktabk(ctx, (TValue *)((char *)key - offsetof(Node, key)), 1);
145 key = heap[--nhash]; /* Remove last key. */
146 bcwrite_ktabk_heap_insert(heap, 0, nhash, key); /* Re-insert. */
147 } while (nhash);
148}
149
79/* Write a template table. */ 150/* Write a template table. */
80static void bcwrite_ktab(BCWriteCtx *ctx, char *p, const GCtab *t) 151static void bcwrite_ktab(BCWriteCtx *ctx, char *p, const GCtab *t)
81{ 152{
@@ -105,14 +176,20 @@ static void bcwrite_ktab(BCWriteCtx *ctx, char *p, const GCtab *t)
105 bcwrite_ktabk(ctx, o, 1); 176 bcwrite_ktabk(ctx, o, 1);
106 } 177 }
107 if (nhash) { /* Write hash entries. */ 178 if (nhash) { /* Write hash entries. */
108 MSize i = nhash;
109 Node *node = noderef(t->node) + t->hmask; 179 Node *node = noderef(t->node) + t->hmask;
110 for (;; node--) 180 if ((ctx->flags & BCDUMP_F_DETERMINISTIC) && nhash > 1) {
111 if (!tvisnil(&node->val)) { 181 if (ctx->heapsz < nhash)
112 bcwrite_ktabk(ctx, &node->key, 0); 182 bcwrite_heap_resize(ctx, t->hmask + 1);
113 bcwrite_ktabk(ctx, &node->val, 1); 183 bcwrite_ktab_sorted_hash(ctx, node, nhash);
114 if (--i == 0) break; 184 } else {
115 } 185 MSize i = nhash;
186 for (;; node--)
187 if (!tvisnil(&node->val)) {
188 bcwrite_ktabk(ctx, &node->key, 0);
189 bcwrite_ktabk(ctx, &node->val, 1);
190 if (--i == 0) break;
191 }
192 }
116 } 193 }
117} 194}
118 195
@@ -269,7 +346,7 @@ static void bcwrite_proto(BCWriteCtx *ctx, GCproto *pt)
269 p = lj_strfmt_wuleb128(p, pt->sizekgc); 346 p = lj_strfmt_wuleb128(p, pt->sizekgc);
270 p = lj_strfmt_wuleb128(p, pt->sizekn); 347 p = lj_strfmt_wuleb128(p, pt->sizekn);
271 p = lj_strfmt_wuleb128(p, pt->sizebc-1); 348 p = lj_strfmt_wuleb128(p, pt->sizebc-1);
272 if (!ctx->strip) { 349 if (!(ctx->flags & BCDUMP_F_STRIP)) {
273 if (proto_lineinfo(pt)) 350 if (proto_lineinfo(pt))
274 sizedbg = pt->sizept - (MSize)((char *)proto_lineinfo(pt) - (char *)pt); 351 sizedbg = pt->sizept - (MSize)((char *)proto_lineinfo(pt) - (char *)pt);
275 p = lj_strfmt_wuleb128(p, sizedbg); 352 p = lj_strfmt_wuleb128(p, sizedbg);
@@ -317,11 +394,10 @@ static void bcwrite_header(BCWriteCtx *ctx)
317 *p++ = BCDUMP_HEAD2; 394 *p++ = BCDUMP_HEAD2;
318 *p++ = BCDUMP_HEAD3; 395 *p++ = BCDUMP_HEAD3;
319 *p++ = BCDUMP_VERSION; 396 *p++ = BCDUMP_VERSION;
320 *p++ = (ctx->strip ? BCDUMP_F_STRIP : 0) + 397 *p++ = (ctx->flags & (BCDUMP_F_STRIP | BCDUMP_F_FR2)) +
321 LJ_BE*BCDUMP_F_BE + 398 LJ_BE*BCDUMP_F_BE +
322 ((ctx->pt->flags & PROTO_FFI) ? BCDUMP_F_FFI : 0) + 399 ((ctx->pt->flags & PROTO_FFI) ? BCDUMP_F_FFI : 0);
323 LJ_FR2*BCDUMP_F_FR2; 400 if (!(ctx->flags & BCDUMP_F_STRIP)) {
324 if (!ctx->strip) {
325 p = lj_strfmt_wuleb128(p, len); 401 p = lj_strfmt_wuleb128(p, len);
326 p = lj_buf_wmem(p, name, len); 402 p = lj_buf_wmem(p, name, len);
327 } 403 }
@@ -352,14 +428,16 @@ static TValue *cpwriter(lua_State *L, lua_CFunction dummy, void *ud)
352 428
353/* Write bytecode for a prototype. */ 429/* Write bytecode for a prototype. */
354int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, void *data, 430int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, void *data,
355 int strip) 431 uint32_t flags)
356{ 432{
357 BCWriteCtx ctx; 433 BCWriteCtx ctx;
358 int status; 434 int status;
359 ctx.pt = pt; 435 ctx.pt = pt;
360 ctx.wfunc = writer; 436 ctx.wfunc = writer;
361 ctx.wdata = data; 437 ctx.wdata = data;
362 ctx.strip = strip; 438 ctx.heapsz = 0;
439 if ((bc_op(proto_bc(pt)[0]) != BC_NOT) == LJ_FR2) flags |= BCDUMP_F_FR2;
440 ctx.flags = flags;
363 ctx.status = 0; 441 ctx.status = 0;
364#ifdef LUA_USE_ASSERT 442#ifdef LUA_USE_ASSERT
365 ctx.g = G(L); 443 ctx.g = G(L);
@@ -368,6 +446,7 @@ int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, void *data,
368 status = lj_vm_cpcall(L, NULL, &ctx, cpwriter); 446 status = lj_vm_cpcall(L, NULL, &ctx, cpwriter);
369 if (status == 0) status = ctx.status; 447 if (status == 0) status = ctx.status;
370 lj_buf_free(G(sbufL(&ctx.sb)), &ctx.sb); 448 lj_buf_free(G(sbufL(&ctx.sb)), &ctx.sb);
449 bcwrite_heap_resize(&ctx, 0);
371 return status; 450 return status;
372} 451}
373 452
diff --git a/src/lj_lex.c b/src/lj_lex.c
index 61b04c4b..bd81dc40 100644
--- a/src/lj_lex.c
+++ b/src/lj_lex.c
@@ -411,6 +411,7 @@ int lj_lex_setup(lua_State *L, LexState *ls)
411 ls->linenumber = 1; 411 ls->linenumber = 1;
412 ls->lastline = 1; 412 ls->lastline = 1;
413 ls->endmark = 0; 413 ls->endmark = 0;
414 ls->fr2 = LJ_FR2; /* Generate native bytecode by default. */
414 lex_next(ls); /* Read-ahead first char. */ 415 lex_next(ls); /* Read-ahead first char. */
415 if (ls->c == 0xef && ls->p + 2 <= ls->pe && (uint8_t)ls->p[0] == 0xbb && 416 if (ls->c == 0xef && ls->p + 2 <= ls->pe && (uint8_t)ls->p[0] == 0xbb &&
416 (uint8_t)ls->p[1] == 0xbf) { /* Skip UTF-8 BOM (if buffered). */ 417 (uint8_t)ls->p[1] == 0xbf) { /* Skip UTF-8 BOM (if buffered). */
diff --git a/src/lj_lex.h b/src/lj_lex.h
index e46fbd89..2ef7fc77 100644
--- a/src/lj_lex.h
+++ b/src/lj_lex.h
@@ -74,6 +74,7 @@ typedef struct LexState {
74 MSize sizebcstack; /* Size of bytecode stack. */ 74 MSize sizebcstack; /* Size of bytecode stack. */
75 uint32_t level; /* Syntactical nesting level. */ 75 uint32_t level; /* Syntactical nesting level. */
76 int endmark; /* Trust bytecode end marker, even if not at EOF. */ 76 int endmark; /* Trust bytecode end marker, even if not at EOF. */
77 int fr2; /* Generate bytecode for LJ_FR2 mode. */
77} LexState; 78} LexState;
78 79
79LJ_FUNC int lj_lex_setup(lua_State *L, LexState *ls); 80LJ_FUNC int lj_lex_setup(lua_State *L, LexState *ls);
diff --git a/src/lj_lib.c b/src/lj_lib.c
index ebe0dc78..06ae4fcf 100644
--- a/src/lj_lib.c
+++ b/src/lj_lib.c
@@ -62,6 +62,7 @@ static const uint8_t *lib_read_lfunc(lua_State *L, const uint8_t *p, GCtab *tab)
62 ls.pe = (const char *)~(uintptr_t)0; 62 ls.pe = (const char *)~(uintptr_t)0;
63 ls.c = -1; 63 ls.c = -1;
64 ls.level = (BCDUMP_F_STRIP|(LJ_BE*BCDUMP_F_BE)); 64 ls.level = (BCDUMP_F_STRIP|(LJ_BE*BCDUMP_F_BE));
65 ls.fr2 = LJ_FR2;
65 ls.chunkname = name; 66 ls.chunkname = name;
66 pt = lj_bcread_proto(&ls); 67 pt = lj_bcread_proto(&ls);
67 pt->firstline = ~(BCLine)0; 68 pt->firstline = ~(BCLine)0;
@@ -266,6 +267,23 @@ GCfunc *lj_lib_checkfunc(lua_State *L, int narg)
266 return funcV(o); 267 return funcV(o);
267} 268}
268 269
270GCproto *lj_lib_checkLproto(lua_State *L, int narg, int nolua)
271{
272 TValue *o = L->base + narg-1;
273 if (L->top > o) {
274 if (tvisproto(o)) {
275 return protoV(o);
276 } else if (tvisfunc(o)) {
277 if (isluafunc(funcV(o)))
278 return funcproto(funcV(o));
279 else if (nolua)
280 return NULL;
281 }
282 }
283 lj_err_argt(L, narg, LUA_TFUNCTION);
284 return NULL; /* unreachable */
285}
286
269GCtab *lj_lib_checktab(lua_State *L, int narg) 287GCtab *lj_lib_checktab(lua_State *L, int narg)
270{ 288{
271 TValue *o = L->base + narg-1; 289 TValue *o = L->base + narg-1;
diff --git a/src/lj_lib.h b/src/lj_lib.h
index 6c3a1c83..a48e3c98 100644
--- a/src/lj_lib.h
+++ b/src/lj_lib.h
@@ -42,6 +42,7 @@ LJ_FUNC lua_Number lj_lib_checknum(lua_State *L, int narg);
42LJ_FUNC int32_t lj_lib_checkint(lua_State *L, int narg); 42LJ_FUNC int32_t lj_lib_checkint(lua_State *L, int narg);
43LJ_FUNC int32_t lj_lib_optint(lua_State *L, int narg, int32_t def); 43LJ_FUNC int32_t lj_lib_optint(lua_State *L, int narg, int32_t def);
44LJ_FUNC GCfunc *lj_lib_checkfunc(lua_State *L, int narg); 44LJ_FUNC GCfunc *lj_lib_checkfunc(lua_State *L, int narg);
45LJ_FUNC GCproto *lj_lib_checkLproto(lua_State *L, int narg, int nolua);
45LJ_FUNC GCtab *lj_lib_checktab(lua_State *L, int narg); 46LJ_FUNC GCtab *lj_lib_checktab(lua_State *L, int narg);
46LJ_FUNC GCtab *lj_lib_checktabornil(lua_State *L, int narg); 47LJ_FUNC GCtab *lj_lib_checktabornil(lua_State *L, int narg);
47LJ_FUNC int lj_lib_checkopt(lua_State *L, int narg, int def, const char *lst); 48LJ_FUNC int lj_lib_checkopt(lua_State *L, int narg, int def, const char *lst);
diff --git a/src/lj_load.c b/src/lj_load.c
index 07304487..152ef6da 100644
--- a/src/lj_load.c
+++ b/src/lj_load.c
@@ -34,14 +34,28 @@ static TValue *cpparser(lua_State *L, lua_CFunction dummy, void *ud)
34 UNUSED(dummy); 34 UNUSED(dummy);
35 cframe_errfunc(L->cframe) = -1; /* Inherit error function. */ 35 cframe_errfunc(L->cframe) = -1; /* Inherit error function. */
36 bc = lj_lex_setup(L, ls); 36 bc = lj_lex_setup(L, ls);
37 if (ls->mode && !strchr(ls->mode, bc ? 'b' : 't')) { 37 if (ls->mode) {
38 setstrV(L, L->top++, lj_err_str(L, LJ_ERR_XMODE)); 38 int xmode = 1;
39 lj_err_throw(L, LUA_ERRSYNTAX); 39 const char *mode = ls->mode;
40 char c;
41 while ((c = *mode++)) {
42 if (c == (bc ? 'b' : 't')) xmode = 0;
43 if (c == (LJ_FR2 ? 'W' : 'X')) ls->fr2 = !LJ_FR2;
44 }
45 if (xmode) {
46 setstrV(L, L->top++, lj_err_str(L, LJ_ERR_XMODE));
47 lj_err_throw(L, LUA_ERRSYNTAX);
48 }
40 } 49 }
41 pt = bc ? lj_bcread(ls) : lj_parse(ls); 50 pt = bc ? lj_bcread(ls) : lj_parse(ls);
42 fn = lj_func_newL_empty(L, pt, tabref(L->env)); 51 if (ls->fr2 == LJ_FR2) {
43 /* Don't combine above/below into one statement. */ 52 fn = lj_func_newL_empty(L, pt, tabref(L->env));
44 setfuncV(L, L->top++, fn); 53 /* Don't combine above/below into one statement. */
54 setfuncV(L, L->top++, fn);
55 } else {
56 /* Non-native generation returns a dumpable, but non-runnable prototype. */
57 setprotoV(L, L->top++, pt);
58 }
45 return NULL; 59 return NULL;
46} 60}
47 61
@@ -159,9 +173,10 @@ LUALIB_API int luaL_loadstring(lua_State *L, const char *s)
159LUA_API int lua_dump(lua_State *L, lua_Writer writer, void *data) 173LUA_API int lua_dump(lua_State *L, lua_Writer writer, void *data)
160{ 174{
161 cTValue *o = L->top-1; 175 cTValue *o = L->top-1;
176 uint32_t flags = LJ_FR2*BCDUMP_F_FR2; /* Default mode for legacy C API. */
162 lj_checkapi(L->top > L->base, "top slot empty"); 177 lj_checkapi(L->top > L->base, "top slot empty");
163 if (tvisfunc(o) && isluafunc(funcV(o))) 178 if (tvisfunc(o) && isluafunc(funcV(o)))
164 return lj_bcwrite(L, funcproto(funcV(o)), writer, data, 0); 179 return lj_bcwrite(L, funcproto(funcV(o)), writer, data, flags);
165 else 180 else
166 return 1; 181 return 1;
167} 182}
diff --git a/src/lj_parse.c b/src/lj_parse.c
index a30921af..5a44f8db 100644
--- a/src/lj_parse.c
+++ b/src/lj_parse.c
@@ -667,19 +667,20 @@ static void bcemit_store(FuncState *fs, ExpDesc *var, ExpDesc *e)
667/* Emit method lookup expression. */ 667/* Emit method lookup expression. */
668static void bcemit_method(FuncState *fs, ExpDesc *e, ExpDesc *key) 668static void bcemit_method(FuncState *fs, ExpDesc *e, ExpDesc *key)
669{ 669{
670 BCReg idx, func, obj = expr_toanyreg(fs, e); 670 BCReg idx, func, fr2, obj = expr_toanyreg(fs, e);
671 expr_free(fs, e); 671 expr_free(fs, e);
672 func = fs->freereg; 672 func = fs->freereg;
673 bcemit_AD(fs, BC_MOV, func+1+LJ_FR2, obj); /* Copy object to 1st argument. */ 673 fr2 = fs->ls->fr2;
674 bcemit_AD(fs, BC_MOV, func+1+fr2, obj); /* Copy object to 1st argument. */
674 lj_assertFS(expr_isstrk(key), "bad usage"); 675 lj_assertFS(expr_isstrk(key), "bad usage");
675 idx = const_str(fs, key); 676 idx = const_str(fs, key);
676 if (idx <= BCMAX_C) { 677 if (idx <= BCMAX_C) {
677 bcreg_reserve(fs, 2+LJ_FR2); 678 bcreg_reserve(fs, 2+fr2);
678 bcemit_ABC(fs, BC_TGETS, func, obj, idx); 679 bcemit_ABC(fs, BC_TGETS, func, obj, idx);
679 } else { 680 } else {
680 bcreg_reserve(fs, 3+LJ_FR2); 681 bcreg_reserve(fs, 3+fr2);
681 bcemit_AD(fs, BC_KSTR, func+2+LJ_FR2, idx); 682 bcemit_AD(fs, BC_KSTR, func+2+fr2, idx);
682 bcemit_ABC(fs, BC_TGETV, func, obj, func+2+LJ_FR2); 683 bcemit_ABC(fs, BC_TGETV, func, obj, func+2+fr2);
683 fs->freereg--; 684 fs->freereg--;
684 } 685 }
685 e->u.s.info = func; 686 e->u.s.info = func;
@@ -1326,9 +1327,12 @@ static void fs_fixup_bc(FuncState *fs, GCproto *pt, BCIns *bc, MSize n)
1326{ 1327{
1327 BCInsLine *base = fs->bcbase; 1328 BCInsLine *base = fs->bcbase;
1328 MSize i; 1329 MSize i;
1330 BCIns op;
1329 pt->sizebc = n; 1331 pt->sizebc = n;
1330 bc[0] = BCINS_AD((fs->flags & PROTO_VARARG) ? BC_FUNCV : BC_FUNCF, 1332 if (fs->ls->fr2 != LJ_FR2) op = BC_NOT; /* Mark non-native prototype. */
1331 fs->framesize, 0); 1333 else if ((fs->flags & PROTO_VARARG)) op = BC_FUNCV;
1334 else op = BC_FUNCF;
1335 bc[0] = BCINS_AD(op, fs->framesize, 0);
1332 for (i = 1; i < n; i++) 1336 for (i = 1; i < n; i++)
1333 bc[i] = base[i].ins; 1337 bc[i] = base[i].ins;
1334} 1338}
@@ -1936,11 +1940,11 @@ static void parse_args(LexState *ls, ExpDesc *e)
1936 lj_assertFS(e->k == VNONRELOC, "bad expr type %d", e->k); 1940 lj_assertFS(e->k == VNONRELOC, "bad expr type %d", e->k);
1937 base = e->u.s.info; /* Base register for call. */ 1941 base = e->u.s.info; /* Base register for call. */
1938 if (args.k == VCALL) { 1942 if (args.k == VCALL) {
1939 ins = BCINS_ABC(BC_CALLM, base, 2, args.u.s.aux - base - 1 - LJ_FR2); 1943 ins = BCINS_ABC(BC_CALLM, base, 2, args.u.s.aux - base - 1 - ls->fr2);
1940 } else { 1944 } else {
1941 if (args.k != VVOID) 1945 if (args.k != VVOID)
1942 expr_tonextreg(fs, &args); 1946 expr_tonextreg(fs, &args);
1943 ins = BCINS_ABC(BC_CALL, base, 2, fs->freereg - base - LJ_FR2); 1947 ins = BCINS_ABC(BC_CALL, base, 2, fs->freereg - base - ls->fr2);
1944 } 1948 }
1945 expr_init(e, VCALL, bcemit_INS(fs, ins)); 1949 expr_init(e, VCALL, bcemit_INS(fs, ins));
1946 e->u.s.aux = base; 1950 e->u.s.aux = base;
@@ -1980,7 +1984,7 @@ static void expr_primary(LexState *ls, ExpDesc *v)
1980 parse_args(ls, v); 1984 parse_args(ls, v);
1981 } else if (ls->tok == '(' || ls->tok == TK_string || ls->tok == '{') { 1985 } else if (ls->tok == '(' || ls->tok == TK_string || ls->tok == '{') {
1982 expr_tonextreg(fs, v); 1986 expr_tonextreg(fs, v);
1983 if (LJ_FR2) bcreg_reserve(fs, 1); 1987 if (ls->fr2) bcreg_reserve(fs, 1);
1984 parse_args(ls, v); 1988 parse_args(ls, v);
1985 } else { 1989 } else {
1986 break; 1990 break;
@@ -2565,7 +2569,7 @@ static void parse_for_iter(LexState *ls, GCstr *indexname)
2565 line = ls->linenumber; 2569 line = ls->linenumber;
2566 assign_adjust(ls, 3, expr_list(ls, &e), &e); 2570 assign_adjust(ls, 3, expr_list(ls, &e), &e);
2567 /* The iterator needs another 3 [4] slots (func [pc] | state ctl). */ 2571 /* The iterator needs another 3 [4] slots (func [pc] | state ctl). */
2568 bcreg_bump(fs, 3+LJ_FR2); 2572 bcreg_bump(fs, 3+ls->fr2);
2569 isnext = (nvars <= 5 && predict_next(ls, fs, exprpc)); 2573 isnext = (nvars <= 5 && predict_next(ls, fs, exprpc));
2570 var_add(ls, 3); /* Hidden control variables. */ 2574 var_add(ls, 3); /* Hidden control variables. */
2571 lex_check(ls, TK_do); 2575 lex_check(ls, TK_do);