1 ----------------------------------------------------------------------------
2 -- Lua script to dump the bytecode of the library functions written in Lua.
3 -- The resulting 'buildvm_libbc.h' is used for the build process of LuaJIT.
4 ----------------------------------------------------------------------------
5 -- Copyright (C) 2005-2015 Mike Pall. All rights reserved.
6 -- Released under the MIT license. See Copyright Notice in luajit.h
7 ----------------------------------------------------------------------------
9 local ffi
= require("ffi")
10 local bit
= require("bit")
11 local vmdef
= require("jit.vmdef")
12 local bcnames
= vmdef
.bcnames
14 local format = string.format
16 local isbe
= (string.byte(string.dump(function() end), 5) % 2 == 1)
18 local function usage(arg
)
19 io
.stderr
:write("Usage: ", arg
and arg
[0] or "genlibbc",
20 " [-o buildvm_libbc.h] lib_*.c\n")
24 local function parse_arg(arg
)
26 if not (arg
and arg
[1]) then
29 if arg
[1] == "-o" then
31 if not outfile
then usage(arg
) end
38 local function read_files(names
)
40 for _
,name
in ipairs(names
) do
41 local fp
= assert(io
.open(name
))
42 src
= src
.. fp
:read("*a")
48 local function transform_lua(code
)
51 code
= string.gsub(code
, "CHECK_(%w*)%((.-)%)", function(tp
, var
)
53 fixup
[n
] = { "CHECK", tp
}
54 return format("%s=%d", var
, n
)
56 code
= string.gsub(code
, "PAIRS%((.-)%)", function(var
)
58 return format("nil, %s, 0", var
)
60 return "return "..code
, fixup
63 local function read_uleb128(p
)
64 local v
= p
[0]; p
= p
+ 1
66 local sh
= 7; v
= v
- 128
69 v
= v
+ bit
.lshift(bit
.band(r
, 127), sh
)
79 str
= 5, func
= 9, tab
= 12, int
= 14, num
= 15
83 for i
=0,#bcnames
/6-1 do
84 BC
[string.gsub(string.sub(bcnames
, i
*6+1, i
*6+6), " ", "")] = i
86 local xop
, xra
= isbe
and 3 or 0, isbe
and 2 or 1
87 local xrc
, xrb
= isbe
and 1 or 2, isbe
and 0 or 3
89 local function fixup_dump(dump
, fixup
)
90 local buf
= ffi
.new("uint8_t[?]", #dump
+1, dump
)
93 p
, n
= read_uleb128(p
)
98 p
, sizebc
= read_uleb128(p
)
102 if op
== BC
.KSHORT
then
103 local rd
= p
[xrc
] + 256*p
[xrb
]
104 rd
= bit
.arshift(bit
.lshift(rd
, 16), 16)
107 if f
[1] == "CHECK" then
109 if tp
== "tab" then rawtab
[p
[xra]]
= true end
110 p
[xop
] = tp
== "num" and BC
.ISNUM
or BC
.ISTYPE
112 p
[xrc
] = name2itype
[tp
]
114 error("unhandled fixup type: "..f
[1])
117 elseif op
== BC
.TGETV
then
118 if rawtab
[p
[xrb]]
then
121 elseif op
== BC
.TSETV
then
122 if rawtab
[p
[xrb]]
then
125 elseif op
== BC
.ITERC
then
132 return ffi
.string(start
, n
)
135 local function find_defs(src
)
137 for name
, code
in string.gmatch(src
, "LJLIB_LUA%(([^)]*)%)%s*/%*(.-)%*/") do
139 local tcode
, fixup
= transform_lua(code
)
140 local func
= assert(load(tcode
, "", nil, env
))()
141 defs
[name
] = fixup_dump(string.dump(func
, true), fixup
)
147 local function gen_header(defs
)
149 local function w(x
) t
[#t
+1] = x
end
150 w("/* This is a generated file. DO NOT EDIT! */\n\n")
151 w("static const int libbc_endian = ") w(isbe
and 1 or 0) w(";\n\n")
153 for _
,name
in ipairs(defs
) do
156 w("static const uint8_t libbc_code[] = {\n")
159 local x
= string.byte(s
, i
)
161 n
= n
+ (x
< 10 and 2 or (x
< 100 and 3 or 4))
162 if n
>= 75 then n
= 0; w("\n") end
165 w("static const struct { const char *name; int ofs; } libbc_map[] = {\n")
167 for _
,name
in ipairs(defs
) do
168 w('{"'); w(name
); w('",'); w(m
) w('},\n')
171 w("{NULL,"); w(m
); w("}\n};\n\n")
172 return table.concat(t
)
175 local function write_file(name
, data
)
177 assert(io
.write(data
))
180 local fp
= io
.open(name
)
182 local old
= fp
:read("*a")
184 if data
== old
then return end
186 fp
= assert(io
.open(name
, "w"))
187 assert(fp
:write(data
))
192 local outfile
= parse_arg(arg
)
193 local src
= read_files(arg
)
194 local defs
= find_defs(src
)
195 local hdr
= gen_header(defs
)
196 write_file(outfile
, hdr
)