Add -b command line option to save/list bytecode.

This commit is contained in:
Mike Pall 2011-06-13 01:04:23 +02:00
parent 4994fcc32c
commit 0eee70cd4d
4 changed files with 198 additions and 16 deletions

View File

@ -76,7 +76,7 @@ FILE_SO= libluajit.so
FILE_MAN= luajit.1 FILE_MAN= luajit.1
FILE_PC= luajit.pc FILE_PC= luajit.pc
FILES_INC= lua.h lualib.h lauxlib.h luaconf.h lua.hpp luajit.h FILES_INC= lua.h lualib.h lauxlib.h luaconf.h lua.hpp luajit.h
FILES_JITLIB= bc.lua v.lua dump.lua dis_x86.lua dis_x64.lua vmdef.lua FILES_JITLIB= bc.lua v.lua dump.lua dis_x86.lua dis_x64.lua bcsave.lua vmdef.lua
ifeq (,$(findstring Windows,$(OS))) ifeq (,$(findstring Windows,$(OS)))
ifeq (Darwin,$(shell uname -s)) ifeq (Darwin,$(shell uname -s))

View File

@ -106,9 +106,34 @@ prints a short list of the available options. Please have a look at the
for details. for details.
</p> </p>
<p> <p>
Two additional options control the behavior of LuaJIT: LuaJIT has some additional options:
</p> </p>
<h3 id="opt_b"><tt>-b[options] input output</tt></h3>
<p>
This option saves or lists bytecode. The following additional options
are accepted:
</p>
<ul>
<li><tt>-l</tt> &mdash; Only list bytecode.</li>
<li><tt>-s</tt> &mdash; Strip debug info (this is the default).</li>
<li><tt>-g</tt> &mdash; Keep debug info.</li>
<li><tt>-e chunk</tt> &mdash; Use chunk string as input.</li>
<li><tt>-</tt> (a single minus sign) &mdash; Use stdin as input and/or stdout as output.</li>
</ul>
<p>
Typical usage examples:
</p>
<pre class="code">
luajit -b test.lua test.out # Save to test.out
luajit -bg test.lua test.out # Keep debug info
luajit -be "print('hello world') end" test.out # Save cmdline script
luajit -bl test.lua # List to stdout
luajit -bl test.lua test.txt # List to test.txt
luajit -ble "print('hello world') end" # List cmdline script
</pre>
<h3 id="opt_j"><tt>-j cmd[=arg[,arg...]]</tt></h3> <h3 id="opt_j"><tt>-j cmd[=arg[,arg...]]</tt></h3>
<p> <p>
This option performs a LuaJIT control command or activates one of the This option performs a LuaJIT control command or activates one of the

125
lib/bcsave.lua Normal file
View File

@ -0,0 +1,125 @@
----------------------------------------------------------------------------
-- LuaJIT module to save/list bytecode.
--
-- Copyright (C) 2005-2011 Mike Pall. All rights reserved.
-- Released under the MIT/X license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
--
-- This module saves or lists the bytecode for an input file.
-- It's run by the -b command line option.
--
------------------------------------------------------------------------------
-- Cache some library functions and objects.
local jit = require("jit")
assert(jit.version_num == 20000, "LuaJIT core/library version mismatch")
------------------------------------------------------------------------------
local function usage()
io.stderr:write[[
Save LuaJIT bytecode: luajit -b[options] input output
-l Only list bytecode.
-s Strip debug info (default).
-g Keep debug info.
-e chunk Use chunk string as input.
-- Stop handling options.
- Use stdin as input and/or stdout as output.
]]
os.exit(1)
end
local function readfile(input)
if type(input) == "function" then return input end
if input == "-" then input = nil end
local f, err = loadfile(input)
if not f then
io.stderr:write("luajit: ", err, "\n")
os.exit(1)
end
return f
end
local function readstring(input)
local f, err = loadstring(input)
if not f then
io.stderr:write("luajit: ", err, "\n")
os.exit(1)
end
return f
end
local function savefile(name, mode)
if name == "-" then return io.stdout end
local fp, err = io.open(name, mode)
if not fp then
io.stderr:write("luajit: cannot write ", err, "\n")
os.exit(1)
end
return fp
end
------------------------------------------------------------------------------
local function bclist(input, output)
local f = readfile(input)
require("jit.bc").dump(f, savefile(output, "w"), true)
end
local function bcsave(input, output, strip)
local f = readfile(input)
local s = string.dump(f, strip)
local fp = savefile(output, "wb")
local ok, err = fp:write(s)
if ok and output ~= "-" then ok, err = fp:close() end
if not ok then
io.stderr:write("luajit: cannot write ", arg[2], ": ", err, "\n")
os.exit(1)
end
end
local function docmd(...)
local arg = {...}
local n = 1
local list = false
local strip = true
while n <= #arg do
local a = arg[n]
if type(a) == "string" and string.sub(a, 1, 1) == "-" and a ~= "-" then
if a == "--" then table.remove(arg, n); break end
for m=2,#a do
local opt = string.sub(a, m, m)
if opt == "l" then
list = true
elseif opt == "s" then
strip = true
elseif opt == "g" then
strip = false
elseif opt == "e" then
if n ~= 1 or #arg < 2 or m ~= #a then usage() end
arg[2] = readstring(arg[2])
else
usage()
end
end
table.remove(arg, n)
else
n = n + 1
end
end
if list then
if #arg == 0 or #arg > 2 then usage() end
bclist(arg[1], arg[2] or "-")
else
if #arg ~= 2 then usage() end
bcsave(arg[1], arg[2], strip)
end
end
------------------------------------------------------------------------------
-- Public module functions.
module(...)
start = docmd -- Process -b command line option.

View File

@ -61,6 +61,7 @@ static void print_usage(void)
"Available options are:\n" "Available options are:\n"
" -e chunk Execute string " LUA_QL("chunk") ".\n" " -e chunk Execute string " LUA_QL("chunk") ".\n"
" -l name Require library " LUA_QL("name") ".\n" " -l name Require library " LUA_QL("name") ".\n"
" -b ... Save or list bytecode.\n"
" -j cmd Perform LuaJIT control command.\n" " -j cmd Perform LuaJIT control command.\n"
" -O[opt] Control LuaJIT optimizations.\n" " -O[opt] Control LuaJIT optimizations.\n"
" -i Enter interactive mode after executing " LUA_QL("script") ".\n" " -i Enter interactive mode after executing " LUA_QL("script") ".\n"
@ -288,7 +289,7 @@ static int handle_script(lua_State *L, char **argv, int n)
} }
/* Load add-on module. */ /* Load add-on module. */
static int loadjitmodule(lua_State *L, const char *notfound) static int loadjitmodule(lua_State *L)
{ {
lua_getglobal(L, "require"); lua_getglobal(L, "require");
lua_pushliteral(L, "jit."); lua_pushliteral(L, "jit.");
@ -298,7 +299,8 @@ static int loadjitmodule(lua_State *L, const char *notfound)
const char *msg = lua_tostring(L, -1); const char *msg = lua_tostring(L, -1);
if (msg && !strncmp(msg, "module ", 7)) { if (msg && !strncmp(msg, "module ", 7)) {
err: err:
l_message(progname, notfound); l_message(progname,
"unknown luaJIT command or jit.* modules not installed");
return 1; return 1;
} else { } else {
return report(L, 1); return report(L, 1);
@ -345,7 +347,7 @@ static int dojitcmd(lua_State *L, const char *cmd)
lua_gettable(L, -2); /* Lookup library function. */ lua_gettable(L, -2); /* Lookup library function. */
if (!lua_isfunction(L, -1)) { if (!lua_isfunction(L, -1)) {
lua_pop(L, 2); /* Drop non-function and jit.* table, keep module name. */ lua_pop(L, 2); /* Drop non-function and jit.* table, keep module name. */
if (loadjitmodule(L, "unknown luaJIT command")) if (loadjitmodule(L))
return 1; return 1;
} else { } else {
lua_remove(L, -2); /* Drop jit.* table. */ lua_remove(L, -2); /* Drop jit.* table. */
@ -365,16 +367,38 @@ static int dojitopt(lua_State *L, const char *opt)
return runcmdopt(L, opt); return runcmdopt(L, opt);
} }
/* Save or list bytecode. */
static int dobytecode(lua_State *L, char **argv)
{
int narg = 0;
lua_pushliteral(L, "bcsave");
if (loadjitmodule(L))
return 1;
if (argv[0][2]) {
narg++;
argv[0][1] = '-';
lua_pushstring(L, argv[0]+1);
}
for (argv++; *argv != NULL; narg++, argv++)
lua_pushstring(L, *argv);
return report(L, lua_pcall(L, narg, 0, 0));
}
/* check that argument has no extra characters at the end */ /* check that argument has no extra characters at the end */
#define notail(x) {if ((x)[2] != '\0') return -1;} #define notail(x) {if ((x)[2] != '\0') return -1;}
static int collectargs(char **argv, int *pi, int *pv, int *pe) #define FLAGS_INTERACTIVE 1
#define FLAGS_VERSION 2
#define FLAGS_EXEC 4
#define FLAGS_OPTION 8
static int collectargs(char **argv, int *flags)
{ {
int i; int i;
for (i = 1; argv[i] != NULL; i++) { for (i = 1; argv[i] != NULL; i++) {
if (argv[i][0] != '-') /* not an option? */ if (argv[i][0] != '-') /* Not an option? */
return i; return i;
switch (argv[i][1]) { /* option */ switch (argv[i][1]) { /* Check option. */
case '-': case '-':
notail(argv[i]); notail(argv[i]);
return (argv[i+1] != NULL ? i+1 : 0); return (argv[i+1] != NULL ? i+1 : 0);
@ -382,21 +406,27 @@ static int collectargs(char **argv, int *pi, int *pv, int *pe)
return i; return i;
case 'i': case 'i':
notail(argv[i]); notail(argv[i]);
*pi = 1; /* go through */ *flags |= FLAGS_INTERACTIVE;
/* fallthrough */
case 'v': case 'v':
notail(argv[i]); notail(argv[i]);
*pv = 1; *flags |= FLAGS_VERSION;
break; break;
case 'e': case 'e':
*pe = 1; /* go through */ *flags |= FLAGS_EXEC;
case 'j': /* LuaJIT extension */ case 'j': /* LuaJIT extension */
case 'l': case 'l':
*flags |= FLAGS_OPTION;
if (argv[i][2] == '\0') { if (argv[i][2] == '\0') {
i++; i++;
if (argv[i] == NULL) return -1; if (argv[i] == NULL) return -1;
} }
break; break;
case 'O': break; /* LuaJIT extension */ case 'O': break; /* LuaJIT extension */
case 'b': /* LuaJIT extension */
if (*flags) return -1;
*flags |= FLAGS_EXEC;
return 0;
default: return -1; /* invalid option */ default: return -1; /* invalid option */
} }
} }
@ -438,6 +468,8 @@ static int runargs(lua_State *L, char **argv, int n)
if (dojitopt(L, argv[i] + 2)) if (dojitopt(L, argv[i] + 2))
return 1; return 1;
break; break;
case 'b': /* LuaJIT extension */
return dobytecode(L, argv+i);
default: break; default: break;
} }
} }
@ -466,7 +498,7 @@ static int pmain(lua_State *L)
struct Smain *s = (struct Smain *)lua_touserdata(L, 1); struct Smain *s = (struct Smain *)lua_touserdata(L, 1);
char **argv = s->argv; char **argv = s->argv;
int script; int script;
int has_i = 0, has_v = 0, has_e = 0; int flags = 0;
globalL = L; globalL = L;
if (argv[0] && argv[0][0]) progname = argv[0]; if (argv[0] && argv[0][0]) progname = argv[0];
LUAJIT_VERSION_SYM(); /* linker-enforced version check */ LUAJIT_VERSION_SYM(); /* linker-enforced version check */
@ -475,22 +507,22 @@ static int pmain(lua_State *L)
lua_gc(L, LUA_GCRESTART, -1); lua_gc(L, LUA_GCRESTART, -1);
s->status = handle_luainit(L); s->status = handle_luainit(L);
if (s->status != 0) return 0; if (s->status != 0) return 0;
script = collectargs(argv, &has_i, &has_v, &has_e); script = collectargs(argv, &flags);
if (script < 0) { /* invalid args? */ if (script < 0) { /* invalid args? */
print_usage(); print_usage();
s->status = 1; s->status = 1;
return 0; return 0;
} }
if (has_v) print_version(); if ((flags & FLAGS_VERSION)) print_version();
s->status = runargs(L, argv, (script > 0) ? script : s->argc); s->status = runargs(L, argv, (script > 0) ? script : s->argc);
if (s->status != 0) return 0; if (s->status != 0) return 0;
if (script) if (script)
s->status = handle_script(L, argv, script); s->status = handle_script(L, argv, script);
if (s->status != 0) return 0; if (s->status != 0) return 0;
if (has_i) { if ((flags & FLAGS_INTERACTIVE)) {
print_jit_status(L); print_jit_status(L);
dotty(L); dotty(L);
} else if (script == 0 && !has_e && !has_v) { } else if (script == 0 && !(flags & (FLAGS_EXEC|FLAGS_VERSION))) {
if (lua_stdin_is_tty()) { if (lua_stdin_is_tty()) {
print_version(); print_version();
print_jit_status(L); print_jit_status(L);