diff options
| author | Mike Pall <mike> | 2024-01-22 19:06:36 +0100 |
|---|---|---|
| committer | Mike Pall <mike> | 2024-01-22 19:06:36 +0100 |
| commit | 4b90f6c4d7420139c135435e1580acb52ea18436 (patch) | |
| tree | 1c3543b6baa4f8b30a33e8a624b60edc6feb0206 /src | |
| parent | c525bcb9024510cad9e170e12b6209aedb330f83 (diff) | |
| download | luajit-4b90f6c4d7420139c135435e1580acb52ea18436.tar.gz luajit-4b90f6c4d7420139c135435e1580acb52ea18436.tar.bz2 luajit-4b90f6c4d7420139c135435e1580acb52ea18436.zip | |
Add cross-32/64 bit and deterministic bytecode generation.
Contributed by Peter Cawley. #993 #1008
Diffstat (limited to 'src')
| -rw-r--r-- | src/host/genlibbc.lua | 91 | ||||
| -rw-r--r-- | src/jit/bcsave.lua | 31 | ||||
| -rw-r--r-- | src/lib_base.c | 6 | ||||
| -rw-r--r-- | src/lib_jit.c | 26 | ||||
| -rw-r--r-- | src/lib_string.c | 22 | ||||
| -rw-r--r-- | src/lj_bcdump.h | 4 | ||||
| -rw-r--r-- | src/lj_bcread.c | 9 | ||||
| -rw-r--r-- | src/lj_bcwrite.c | 109 | ||||
| -rw-r--r-- | src/lj_lex.c | 1 | ||||
| -rw-r--r-- | src/lj_lex.h | 1 | ||||
| -rw-r--r-- | src/lj_lib.c | 18 | ||||
| -rw-r--r-- | src/lj_lib.h | 1 | ||||
| -rw-r--r-- | src/lj_load.c | 29 | ||||
| -rw-r--r-- | src/lj_parse.c | 28 |
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 } |
| 139 | end | 139 | end |
| 140 | 140 | ||
| 141 | local function find_defs(src) | 141 | local 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 |
| 151 | end | 150 | end |
| 152 | 151 | ||
| 153 | local function gen_header(defs) | 152 | local 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) |
| 201 | end | 209 | end |
| 202 | 210 | ||
| @@ -219,7 +227,8 @@ end | |||
| 219 | 227 | ||
| 220 | local outfile = parse_arg(arg) | 228 | local outfile = parse_arg(arg) |
| 221 | local src = read_files(arg) | 229 | local src = read_files(arg) |
| 222 | local defs = find_defs(src) | 230 | local defs32 = find_defs(src, "Wdts") |
| 223 | local hdr = gen_header(defs) | 231 | local defs64 = find_defs(src, "Xdts") |
| 232 | local hdr = gen_header(defs32, defs64) | ||
| 224 | write_file(outfile, hdr) | 233 | write_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, ...) | |||
| 51 | end | 54 | end |
| 52 | 55 | ||
| 53 | local function readfile(ctx, input) | 56 | local 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 |
| 69 | end | 73 | end |
| 70 | 74 | ||
| @@ -624,7 +628,7 @@ end | |||
| 624 | 628 | ||
| 625 | local function bcsave(ctx, input, output) | 629 | local 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(.) | |||
| 360 | static int load_aux(lua_State *L, int status, int envarg) | 360 | static 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) */ | ||
| 165 | static 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 | |||
| 182 | static void setintfield(lua_State *L, GCtab *t, const char *name, int32_t val) | 164 | static 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]) */ |
| 188 | LJLIB_CF(jit_util_funcinfo) | 170 | LJLIB_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) */ |
| 230 | LJLIB_CF(jit_util_funcbc) | 212 | LJLIB_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) */ |
| 247 | LJLIB_CF(jit_util_funck) | 229 | LJLIB_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) */ |
| 267 | LJLIB_CF(jit_util_funcuvname) | 249 | LJLIB_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 | ||
| 123 | LJLIB_CF(string_dump) | 123 | LJLIB_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. */ |
| 50 | enum { | 52 | enum { |
| 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 | ||
| 63 | LJ_FUNC int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, | 65 | LJ_FUNC int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, |
| 64 | void *data, int strip); | 66 | void *data, uint32_t flags); |
| 65 | LJ_FUNC GCproto *lj_bcread_proto(LexState *ls); | 67 | LJ_FUNC GCproto *lj_bcread_proto(LexState *ls); |
| 66 | LJ_FUNC GCproto *lj_bcread(LexState *ls); | 68 | LJ_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) | |||
| 281 | static void bcread_bytecode(LexState *ls, GCproto *pt, MSize sizebc) | 281 | static 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. */ | ||
| 82 | static 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. */ | ||
| 95 | static 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. */ | ||
| 117 | static 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. */ | ||
| 131 | static 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. */ |
| 80 | static void bcwrite_ktab(BCWriteCtx *ctx, char *p, const GCtab *t) | 151 | static 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. */ |
| 354 | int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, void *data, | 430 | int 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 | ||
| 79 | LJ_FUNC int lj_lex_setup(lua_State *L, LexState *ls); | 80 | LJ_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 | ||
| 270 | GCproto *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 | |||
| 269 | GCtab *lj_lib_checktab(lua_State *L, int narg) | 287 | GCtab *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); | |||
| 42 | LJ_FUNC int32_t lj_lib_checkint(lua_State *L, int narg); | 42 | LJ_FUNC int32_t lj_lib_checkint(lua_State *L, int narg); |
| 43 | LJ_FUNC int32_t lj_lib_optint(lua_State *L, int narg, int32_t def); | 43 | LJ_FUNC int32_t lj_lib_optint(lua_State *L, int narg, int32_t def); |
| 44 | LJ_FUNC GCfunc *lj_lib_checkfunc(lua_State *L, int narg); | 44 | LJ_FUNC GCfunc *lj_lib_checkfunc(lua_State *L, int narg); |
| 45 | LJ_FUNC GCproto *lj_lib_checkLproto(lua_State *L, int narg, int nolua); | ||
| 45 | LJ_FUNC GCtab *lj_lib_checktab(lua_State *L, int narg); | 46 | LJ_FUNC GCtab *lj_lib_checktab(lua_State *L, int narg); |
| 46 | LJ_FUNC GCtab *lj_lib_checktabornil(lua_State *L, int narg); | 47 | LJ_FUNC GCtab *lj_lib_checktabornil(lua_State *L, int narg); |
| 47 | LJ_FUNC int lj_lib_checkopt(lua_State *L, int narg, int def, const char *lst); | 48 | LJ_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) | |||
| 159 | LUA_API int lua_dump(lua_State *L, lua_Writer writer, void *data) | 173 | LUA_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. */ |
| 668 | static void bcemit_method(FuncState *fs, ExpDesc *e, ExpDesc *key) | 668 | static 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); |
