aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--doc/running.html27
-rw-r--r--lib/bcsave.lua125
-rw-r--r--src/luajit.c60
4 files changed, 198 insertions, 16 deletions
diff --git a/Makefile b/Makefile
index dff3dfbf..c9a65684 100644
--- a/Makefile
+++ b/Makefile
@@ -76,7 +76,7 @@ FILE_SO= libluajit.so
76FILE_MAN= luajit.1 76FILE_MAN= luajit.1
77FILE_PC= luajit.pc 77FILE_PC= luajit.pc
78FILES_INC= lua.h lualib.h lauxlib.h luaconf.h lua.hpp luajit.h 78FILES_INC= lua.h lualib.h lauxlib.h luaconf.h lua.hpp luajit.h
79FILES_JITLIB= bc.lua v.lua dump.lua dis_x86.lua dis_x64.lua vmdef.lua 79FILES_JITLIB= bc.lua v.lua dump.lua dis_x86.lua dis_x64.lua bcsave.lua vmdef.lua
80 80
81ifeq (,$(findstring Windows,$(OS))) 81ifeq (,$(findstring Windows,$(OS)))
82 ifeq (Darwin,$(shell uname -s)) 82 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
106for details. 106for details.
107</p> 107</p>
108<p> 108<p>
109Two additional options control the behavior of LuaJIT: 109LuaJIT has some additional options:
110</p> 110</p>
111 111
112<h3 id="opt_b"><tt>-b[options] input output</tt></h3>
113<p>
114This option saves or lists bytecode. The following additional options
115are accepted:
116</p>
117<ul>
118<li><tt>-l</tt> &mdash; Only list bytecode.</li>
119<li><tt>-s</tt> &mdash; Strip debug info (this is the default).</li>
120<li><tt>-g</tt> &mdash; Keep debug info.</li>
121<li><tt>-e chunk</tt> &mdash; Use chunk string as input.</li>
122<li><tt>-</tt> (a single minus sign) &mdash; Use stdin as input and/or stdout as output.</li>
123</ul>
124<p>
125Typical usage examples:
126</p>
127<pre class="code">
128luajit -b test.lua test.out # Save to test.out
129luajit -bg test.lua test.out # Keep debug info
130luajit -be "print('hello world') end" test.out # Save cmdline script
131
132luajit -bl test.lua # List to stdout
133luajit -bl test.lua test.txt # List to test.txt
134luajit -ble "print('hello world') end" # List cmdline script
135</pre>
136
112<h3 id="opt_j"><tt>-j cmd[=arg[,arg...]]</tt></h3> 137<h3 id="opt_j"><tt>-j cmd[=arg[,arg...]]</tt></h3>
113<p> 138<p>
114This option performs a LuaJIT control command or activates one of the 139This 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 @@
1----------------------------------------------------------------------------
2-- LuaJIT module to save/list bytecode.
3--
4-- Copyright (C) 2005-2011 Mike Pall. All rights reserved.
5-- Released under the MIT/X license. See Copyright Notice in luajit.h
6----------------------------------------------------------------------------
7--
8-- This module saves or lists the bytecode for an input file.
9-- It's run by the -b command line option.
10--
11------------------------------------------------------------------------------
12
13-- Cache some library functions and objects.
14local jit = require("jit")
15assert(jit.version_num == 20000, "LuaJIT core/library version mismatch")
16
17------------------------------------------------------------------------------
18
19local function usage()
20 io.stderr:write[[
21Save LuaJIT bytecode: luajit -b[options] input output
22 -l Only list bytecode.
23 -s Strip debug info (default).
24 -g Keep debug info.
25 -e chunk Use chunk string as input.
26 -- Stop handling options.
27 - Use stdin as input and/or stdout as output.
28]]
29 os.exit(1)
30end
31
32local function readfile(input)
33 if type(input) == "function" then return input end
34 if input == "-" then input = nil end
35 local f, err = loadfile(input)
36 if not f then
37 io.stderr:write("luajit: ", err, "\n")
38 os.exit(1)
39 end
40 return f
41end
42
43local function readstring(input)
44 local f, err = loadstring(input)
45 if not f then
46 io.stderr:write("luajit: ", err, "\n")
47 os.exit(1)
48 end
49 return f
50end
51
52local function savefile(name, mode)
53 if name == "-" then return io.stdout end
54 local fp, err = io.open(name, mode)
55 if not fp then
56 io.stderr:write("luajit: cannot write ", err, "\n")
57 os.exit(1)
58 end
59 return fp
60end
61
62------------------------------------------------------------------------------
63
64local function bclist(input, output)
65 local f = readfile(input)
66 require("jit.bc").dump(f, savefile(output, "w"), true)
67end
68
69local function bcsave(input, output, strip)
70 local f = readfile(input)
71 local s = string.dump(f, strip)
72 local fp = savefile(output, "wb")
73 local ok, err = fp:write(s)
74 if ok and output ~= "-" then ok, err = fp:close() end
75 if not ok then
76 io.stderr:write("luajit: cannot write ", arg[2], ": ", err, "\n")
77 os.exit(1)
78 end
79end
80
81local function docmd(...)
82 local arg = {...}
83 local n = 1
84 local list = false
85 local strip = true
86 while n <= #arg do
87 local a = arg[n]
88 if type(a) == "string" and string.sub(a, 1, 1) == "-" and a ~= "-" then
89 if a == "--" then table.remove(arg, n); break end
90 for m=2,#a do
91 local opt = string.sub(a, m, m)
92 if opt == "l" then
93 list = true
94 elseif opt == "s" then
95 strip = true
96 elseif opt == "g" then
97 strip = false
98 elseif opt == "e" then
99 if n ~= 1 or #arg < 2 or m ~= #a then usage() end
100 arg[2] = readstring(arg[2])
101 else
102 usage()
103 end
104 end
105 table.remove(arg, n)
106 else
107 n = n + 1
108 end
109 end
110 if list then
111 if #arg == 0 or #arg > 2 then usage() end
112 bclist(arg[1], arg[2] or "-")
113 else
114 if #arg ~= 2 then usage() end
115 bcsave(arg[1], arg[2], strip)
116 end
117end
118
119------------------------------------------------------------------------------
120
121-- Public module functions.
122module(...)
123
124start = docmd -- Process -b command line option.
125
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)
61 "Available options are:\n" 61 "Available options are:\n"
62 " -e chunk Execute string " LUA_QL("chunk") ".\n" 62 " -e chunk Execute string " LUA_QL("chunk") ".\n"
63 " -l name Require library " LUA_QL("name") ".\n" 63 " -l name Require library " LUA_QL("name") ".\n"
64 " -b ... Save or list bytecode.\n"
64 " -j cmd Perform LuaJIT control command.\n" 65 " -j cmd Perform LuaJIT control command.\n"
65 " -O[opt] Control LuaJIT optimizations.\n" 66 " -O[opt] Control LuaJIT optimizations.\n"
66 " -i Enter interactive mode after executing " LUA_QL("script") ".\n" 67 " -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)
288} 289}
289 290
290/* Load add-on module. */ 291/* Load add-on module. */
291static int loadjitmodule(lua_State *L, const char *notfound) 292static int loadjitmodule(lua_State *L)
292{ 293{
293 lua_getglobal(L, "require"); 294 lua_getglobal(L, "require");
294 lua_pushliteral(L, "jit."); 295 lua_pushliteral(L, "jit.");
@@ -298,7 +299,8 @@ static int loadjitmodule(lua_State *L, const char *notfound)
298 const char *msg = lua_tostring(L, -1); 299 const char *msg = lua_tostring(L, -1);
299 if (msg && !strncmp(msg, "module ", 7)) { 300 if (msg && !strncmp(msg, "module ", 7)) {
300 err: 301 err:
301 l_message(progname, notfound); 302 l_message(progname,
303 "unknown luaJIT command or jit.* modules not installed");
302 return 1; 304 return 1;
303 } else { 305 } else {
304 return report(L, 1); 306 return report(L, 1);
@@ -345,7 +347,7 @@ static int dojitcmd(lua_State *L, const char *cmd)
345 lua_gettable(L, -2); /* Lookup library function. */ 347 lua_gettable(L, -2); /* Lookup library function. */
346 if (!lua_isfunction(L, -1)) { 348 if (!lua_isfunction(L, -1)) {
347 lua_pop(L, 2); /* Drop non-function and jit.* table, keep module name. */ 349 lua_pop(L, 2); /* Drop non-function and jit.* table, keep module name. */
348 if (loadjitmodule(L, "unknown luaJIT command")) 350 if (loadjitmodule(L))
349 return 1; 351 return 1;
350 } else { 352 } else {
351 lua_remove(L, -2); /* Drop jit.* table. */ 353 lua_remove(L, -2); /* Drop jit.* table. */
@@ -365,16 +367,38 @@ static int dojitopt(lua_State *L, const char *opt)
365 return runcmdopt(L, opt); 367 return runcmdopt(L, opt);
366} 368}
367 369
370/* Save or list bytecode. */
371static int dobytecode(lua_State *L, char **argv)
372{
373 int narg = 0;
374 lua_pushliteral(L, "bcsave");
375 if (loadjitmodule(L))
376 return 1;
377 if (argv[0][2]) {
378 narg++;
379 argv[0][1] = '-';
380 lua_pushstring(L, argv[0]+1);
381 }
382 for (argv++; *argv != NULL; narg++, argv++)
383 lua_pushstring(L, *argv);
384 return report(L, lua_pcall(L, narg, 0, 0));
385}
386
368/* check that argument has no extra characters at the end */ 387/* check that argument has no extra characters at the end */
369#define notail(x) {if ((x)[2] != '\0') return -1;} 388#define notail(x) {if ((x)[2] != '\0') return -1;}
370 389
371static int collectargs(char **argv, int *pi, int *pv, int *pe) 390#define FLAGS_INTERACTIVE 1
391#define FLAGS_VERSION 2
392#define FLAGS_EXEC 4
393#define FLAGS_OPTION 8
394
395static int collectargs(char **argv, int *flags)
372{ 396{
373 int i; 397 int i;
374 for (i = 1; argv[i] != NULL; i++) { 398 for (i = 1; argv[i] != NULL; i++) {
375 if (argv[i][0] != '-') /* not an option? */ 399 if (argv[i][0] != '-') /* Not an option? */
376 return i; 400 return i;
377 switch (argv[i][1]) { /* option */ 401 switch (argv[i][1]) { /* Check option. */
378 case '-': 402 case '-':
379 notail(argv[i]); 403 notail(argv[i]);
380 return (argv[i+1] != NULL ? i+1 : 0); 404 return (argv[i+1] != NULL ? i+1 : 0);
@@ -382,21 +406,27 @@ static int collectargs(char **argv, int *pi, int *pv, int *pe)
382 return i; 406 return i;
383 case 'i': 407 case 'i':
384 notail(argv[i]); 408 notail(argv[i]);
385 *pi = 1; /* go through */ 409 *flags |= FLAGS_INTERACTIVE;
410 /* fallthrough */
386 case 'v': 411 case 'v':
387 notail(argv[i]); 412 notail(argv[i]);
388 *pv = 1; 413 *flags |= FLAGS_VERSION;
389 break; 414 break;
390 case 'e': 415 case 'e':
391 *pe = 1; /* go through */ 416 *flags |= FLAGS_EXEC;
392 case 'j': /* LuaJIT extension */ 417 case 'j': /* LuaJIT extension */
393 case 'l': 418 case 'l':
419 *flags |= FLAGS_OPTION;
394 if (argv[i][2] == '\0') { 420 if (argv[i][2] == '\0') {
395 i++; 421 i++;
396 if (argv[i] == NULL) return -1; 422 if (argv[i] == NULL) return -1;
397 } 423 }
398 break; 424 break;
399 case 'O': break; /* LuaJIT extension */ 425 case 'O': break; /* LuaJIT extension */
426 case 'b': /* LuaJIT extension */
427 if (*flags) return -1;
428 *flags |= FLAGS_EXEC;
429 return 0;
400 default: return -1; /* invalid option */ 430 default: return -1; /* invalid option */
401 } 431 }
402 } 432 }
@@ -438,6 +468,8 @@ static int runargs(lua_State *L, char **argv, int n)
438 if (dojitopt(L, argv[i] + 2)) 468 if (dojitopt(L, argv[i] + 2))
439 return 1; 469 return 1;
440 break; 470 break;
471 case 'b': /* LuaJIT extension */
472 return dobytecode(L, argv+i);
441 default: break; 473 default: break;
442 } 474 }
443 } 475 }
@@ -466,7 +498,7 @@ static int pmain(lua_State *L)
466 struct Smain *s = (struct Smain *)lua_touserdata(L, 1); 498 struct Smain *s = (struct Smain *)lua_touserdata(L, 1);
467 char **argv = s->argv; 499 char **argv = s->argv;
468 int script; 500 int script;
469 int has_i = 0, has_v = 0, has_e = 0; 501 int flags = 0;
470 globalL = L; 502 globalL = L;
471 if (argv[0] && argv[0][0]) progname = argv[0]; 503 if (argv[0] && argv[0][0]) progname = argv[0];
472 LUAJIT_VERSION_SYM(); /* linker-enforced version check */ 504 LUAJIT_VERSION_SYM(); /* linker-enforced version check */
@@ -475,22 +507,22 @@ static int pmain(lua_State *L)
475 lua_gc(L, LUA_GCRESTART, -1); 507 lua_gc(L, LUA_GCRESTART, -1);
476 s->status = handle_luainit(L); 508 s->status = handle_luainit(L);
477 if (s->status != 0) return 0; 509 if (s->status != 0) return 0;
478 script = collectargs(argv, &has_i, &has_v, &has_e); 510 script = collectargs(argv, &flags);
479 if (script < 0) { /* invalid args? */ 511 if (script < 0) { /* invalid args? */
480 print_usage(); 512 print_usage();
481 s->status = 1; 513 s->status = 1;
482 return 0; 514 return 0;
483 } 515 }
484 if (has_v) print_version(); 516 if ((flags & FLAGS_VERSION)) print_version();
485 s->status = runargs(L, argv, (script > 0) ? script : s->argc); 517 s->status = runargs(L, argv, (script > 0) ? script : s->argc);
486 if (s->status != 0) return 0; 518 if (s->status != 0) return 0;
487 if (script) 519 if (script)
488 s->status = handle_script(L, argv, script); 520 s->status = handle_script(L, argv, script);
489 if (s->status != 0) return 0; 521 if (s->status != 0) return 0;
490 if (has_i) { 522 if ((flags & FLAGS_INTERACTIVE)) {
491 print_jit_status(L); 523 print_jit_status(L);
492 dotty(L); 524 dotty(L);
493 } else if (script == 0 && !has_e && !has_v) { 525 } else if (script == 0 && !(flags & (FLAGS_EXEC|FLAGS_VERSION))) {
494 if (lua_stdin_is_tty()) { 526 if (lua_stdin_is_tty()) {
495 print_version(); 527 print_version();
496 print_jit_status(L); 528 print_jit_status(L);