diff --git a/Makefile b/Makefile index dff3dfbf..c9a65684 100644 --- a/Makefile +++ b/Makefile @@ -76,7 +76,7 @@ FILE_SO= libluajit.so FILE_MAN= luajit.1 FILE_PC= luajit.pc 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 (Darwin,$(shell uname -s)) diff --git a/doc/running.html b/doc/running.html index bcc811c4..ecf6bba4 100644 --- a/doc/running.html +++ b/doc/running.html @@ -106,9 +106,34 @@ prints a short list of the available options. Please have a look at the for details.

-Two additional options control the behavior of LuaJIT: +LuaJIT has some additional options:

+

-b[options] input output

+

+This option saves or lists bytecode. The following additional options +are accepted: +

+ +

+Typical usage examples: +

+
+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
+
+

-j cmd[=arg[,arg...]]

This option performs a LuaJIT control command or activates one of the diff --git a/lib/bcsave.lua b/lib/bcsave.lua new file mode 100644 index 00000000..c34bec89 --- /dev/null +++ b/lib/bcsave.lua @@ -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. + diff --git a/src/luajit.c b/src/luajit.c index 697c0771..17d3b5fc 100644 --- a/src/luajit.c +++ b/src/luajit.c @@ -61,6 +61,7 @@ static void print_usage(void) "Available options are:\n" " -e chunk Execute string " LUA_QL("chunk") ".\n" " -l name Require library " LUA_QL("name") ".\n" + " -b ... Save or list bytecode.\n" " -j cmd Perform LuaJIT control command.\n" " -O[opt] Control LuaJIT optimizations.\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. */ -static int loadjitmodule(lua_State *L, const char *notfound) +static int loadjitmodule(lua_State *L) { lua_getglobal(L, "require"); lua_pushliteral(L, "jit."); @@ -298,7 +299,8 @@ static int loadjitmodule(lua_State *L, const char *notfound) const char *msg = lua_tostring(L, -1); if (msg && !strncmp(msg, "module ", 7)) { err: - l_message(progname, notfound); + l_message(progname, + "unknown luaJIT command or jit.* modules not installed"); return 1; } else { return report(L, 1); @@ -345,7 +347,7 @@ static int dojitcmd(lua_State *L, const char *cmd) lua_gettable(L, -2); /* Lookup library function. */ if (!lua_isfunction(L, -1)) { lua_pop(L, 2); /* Drop non-function and jit.* table, keep module name. */ - if (loadjitmodule(L, "unknown luaJIT command")) + if (loadjitmodule(L)) return 1; } else { lua_remove(L, -2); /* Drop jit.* table. */ @@ -365,16 +367,38 @@ static int dojitopt(lua_State *L, const char *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 */ #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; for (i = 1; argv[i] != NULL; i++) { - if (argv[i][0] != '-') /* not an option? */ + if (argv[i][0] != '-') /* Not an option? */ return i; - switch (argv[i][1]) { /* option */ + switch (argv[i][1]) { /* Check option. */ case '-': notail(argv[i]); 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; case 'i': notail(argv[i]); - *pi = 1; /* go through */ + *flags |= FLAGS_INTERACTIVE; + /* fallthrough */ case 'v': notail(argv[i]); - *pv = 1; + *flags |= FLAGS_VERSION; break; case 'e': - *pe = 1; /* go through */ + *flags |= FLAGS_EXEC; case 'j': /* LuaJIT extension */ case 'l': + *flags |= FLAGS_OPTION; if (argv[i][2] == '\0') { i++; if (argv[i] == NULL) return -1; } break; case 'O': break; /* LuaJIT extension */ + case 'b': /* LuaJIT extension */ + if (*flags) return -1; + *flags |= FLAGS_EXEC; + return 0; 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)) return 1; break; + case 'b': /* LuaJIT extension */ + return dobytecode(L, argv+i); default: break; } } @@ -466,7 +498,7 @@ static int pmain(lua_State *L) struct Smain *s = (struct Smain *)lua_touserdata(L, 1); char **argv = s->argv; int script; - int has_i = 0, has_v = 0, has_e = 0; + int flags = 0; globalL = L; if (argv[0] && argv[0][0]) progname = argv[0]; LUAJIT_VERSION_SYM(); /* linker-enforced version check */ @@ -475,22 +507,22 @@ static int pmain(lua_State *L) lua_gc(L, LUA_GCRESTART, -1); s->status = handle_luainit(L); if (s->status != 0) return 0; - script = collectargs(argv, &has_i, &has_v, &has_e); + script = collectargs(argv, &flags); if (script < 0) { /* invalid args? */ print_usage(); s->status = 1; return 0; } - if (has_v) print_version(); + if ((flags & FLAGS_VERSION)) print_version(); s->status = runargs(L, argv, (script > 0) ? script : s->argc); if (s->status != 0) return 0; if (script) s->status = handle_script(L, argv, script); if (s->status != 0) return 0; - if (has_i) { + if ((flags & FLAGS_INTERACTIVE)) { print_jit_status(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()) { print_version(); print_jit_status(L);