aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pall <mike>2024-01-22 19:06:36 +0100
committerMike Pall <mike>2024-01-22 19:06:36 +0100
commit4b90f6c4d7420139c135435e1580acb52ea18436 (patch)
tree1c3543b6baa4f8b30a33e8a624b60edc6feb0206
parentc525bcb9024510cad9e170e12b6209aedb330f83 (diff)
downloadluajit-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 '')
-rw-r--r--doc/extensions.html51
-rw-r--r--doc/running.html3
-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
16 files changed, 302 insertions, 128 deletions
diff --git a/doc/extensions.html b/doc/extensions.html
index a4f20841..1d28475c 100644
--- a/doc/extensions.html
+++ b/doc/extensions.html
@@ -160,13 +160,33 @@ passes any arguments after the error function to the function
160which is called in a protected context. 160which is called in a protected context.
161</p> 161</p>
162 162
163<h3 id="load"><tt>loadfile()</tt> etc. handle UTF-8 source code</h3> 163<h3 id="load"><tt>load*()</tt> handle UTF-8 source code</h3>
164<p> 164<p>
165Non-ASCII characters are handled transparently by the Lua source code parser. 165Non-ASCII characters are handled transparently by the Lua source code parser.
166This allows the use of UTF-8 characters in identifiers and strings. 166This allows the use of UTF-8 characters in identifiers and strings.
167A UTF-8 BOM is skipped at the start of the source code. 167A UTF-8 BOM is skipped at the start of the source code.
168</p> 168</p>
169 169
170<h3 id="load_mode"><tt>load*()</tt> add a mode parameter</h3>
171<p>
172As an extension from Lua 5.2, the functions <tt>loadstring()</tt>,
173<tt>loadfile()</tt> and (new) <tt>load()</tt> add an optional
174<tt>mode</tt> parameter.
175</p>
176<p>
177The default mode string is <tt>"bt"</tt>, which allows loading of both
178source code and bytecode. Use <tt>"t"</tt> to allow only source code
179or <tt>"b"</tt> to allow only bytecode to be loaded.
180</p>
181<p>
182By default, the <tt>load*</tt> functions generate the native bytecode format.
183For cross-compilation purposes, add <tt>W</tt> to the mode string to
184force the 32 bit format and <tt>X</tt> to force the 64 bit format.
185Add both to force the opposite format. Note that non-native bytecode
186generated by <tt>load*</tt> cannot be run, but can still be passed
187to <tt>string.dump</tt>.
188</p>
189
170<h3 id="tostring"><tt>tostring()</tt> etc. canonicalize NaN and &plusmn;Inf</h3> 190<h3 id="tostring"><tt>tostring()</tt> etc. canonicalize NaN and &plusmn;Inf</h3>
171<p> 191<p>
172All number-to-string conversions consistently convert non-finite numbers 192All number-to-string conversions consistently convert non-finite numbers
@@ -186,26 +206,33 @@ works independently of the current locale and it supports hex floating-point
186numbers (e.g. <tt>0x1.5p-3</tt>). 206numbers (e.g. <tt>0x1.5p-3</tt>).
187</p> 207</p>
188 208
189<h3 id="string_dump"><tt>string.dump(f [,strip])</tt> generates portable bytecode</h3> 209<h3 id="string_dump"><tt>string.dump(f [,mode])</tt> generates portable bytecode</h3>
190<p> 210<p>
191An extra argument has been added to <tt>string.dump()</tt>. If set to 211An extra argument has been added to <tt>string.dump()</tt>. If set to
192<tt>true</tt>, 'stripped' bytecode without debug information is 212<tt>true</tt> or to a string which contains the character <tt>s</tt>,
193generated. This speeds up later bytecode loading and reduces memory 213'stripped' bytecode without debug information is generated. This speeds
194usage. See also the 214up later bytecode loading and reduces memory usage. See also the
195<a href="running.html#opt_b"><tt>-b</tt> command line option</a>. 215<a href="running.html#opt_b"><tt>-b</tt> command line option</a>.
196</p> 216</p>
197<p> 217<p>
198The generated bytecode is portable and can be loaded on any architecture 218The generated bytecode is portable and can be loaded on any architecture
199that LuaJIT supports, independent of word size or endianess. However, the 219that LuaJIT supports. However, the bytecode compatibility versions must
200bytecode compatibility versions must match. Bytecode stays compatible 220match. Bytecode only stays compatible within a major+minor version
201for dot releases (x.y.0 &rarr; x.y.1), but may change with major or 221(x.y.aaa &rarr; x.y.bbb), except for development branches. Foreign bytecode
202minor releases (2.0 &rarr; 2.1) or between any beta release. Foreign 222(e.g. from Lua 5.1) is incompatible and cannot be loaded.
203bytecode (e.g. from Lua 5.1) is incompatible and cannot be loaded.
204</p> 223</p>
205<p> 224<p>
206Note: <tt>LJ_GC64</tt> mode requires a different frame layout, which implies 225Note: <tt>LJ_GC64</tt> mode requires a different frame layout, which implies
207a different, incompatible bytecode format for all 64 bit ports. This may be 226a different, incompatible bytecode format between 32 bit and 64 bit ports.
208rectified in the future. 227This may be rectified in the future. In the meantime, use the <tt>W</tt>
228and </tt>X</tt> <a href="#load_mode">modes of the <tt>load*</tt> functions</a>
229for cross-compilation purposes.
230</p>
231<p>
232Due to VM hardening, bytecode is not deterministic. Add <tt>d</tt> to the
233mode string to dump it in a deterministic manner: identical source code
234always gives a byte-for-byte identical bytecode dump. This feature is
235mainly useful for reproducible builds.
209</p> 236</p>
210 237
211<h3 id="table_new"><tt>table.new(narray, nhash)</tt> allocates a pre-sized table</h3> 238<h3 id="table_new"><tt>table.new(narray, nhash)</tt> allocates a pre-sized table</h3>
diff --git a/doc/running.html b/doc/running.html
index 9dd2b411..142b810f 100644
--- a/doc/running.html
+++ b/doc/running.html
@@ -106,6 +106,9 @@ are accepted:
106<li><tt>-l</tt> &mdash; Only list bytecode.</li> 106<li><tt>-l</tt> &mdash; Only list bytecode.</li>
107<li><tt>-s</tt> &mdash; Strip debug info (this is the default).</li> 107<li><tt>-s</tt> &mdash; Strip debug info (this is the default).</li>
108<li><tt>-g</tt> &mdash; Keep debug info.</li> 108<li><tt>-g</tt> &mdash; Keep debug info.</li>
109<li><tt>-W</tt> &mdash; Generate 32 bit (non-GC64) bytecode.</li>
110<li><tt>-X</tt> &mdash; Generate 64 bit (GC64) bytecode.</li>
111<li><tt>-d</tt> &mdash; Generate bytecode in deterministic manner.</li>
109<li><tt>-n name</tt> &mdash; Set module name (default: auto-detect from input name)</li> 112<li><tt>-n name</tt> &mdash; Set module name (default: auto-detect from input name)</li>
110<li><tt>-t type</tt> &mdash; Set output file type (default: auto-detect from output name).</li> 113<li><tt>-t type</tt> &mdash; Set output file type (default: auto-detect from output name).</li>
111<li><tt>-a arch</tt> &mdash; Override architecture for object files (default: native).</li> 114<li><tt>-a arch</tt> &mdash; Override architecture for object files (default: native).</li>
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);