src/host/genlibbc.lua - luajit-2.0-src

Functions defined

Source code

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

  8. local ffi = require("ffi")
  9. local bit = require("bit")
  10. local vmdef = require("jit.vmdef")
  11. local bcnames = vmdef.bcnames

  12. local format = string.format

  13. local isbe = (string.byte(string.dump(function() end), 5) % 2 == 1)

  14. local function usage(arg)
  15.   io.stderr:write("Usage: ", arg and arg[0] or "genlibbc",
  16.                   " [-o buildvm_libbc.h] lib_*.c\n")
  17.   os.exit(1)
  18. end

  19. local function parse_arg(arg)
  20.   local outfile = "-"
  21.   if not (arg and arg[1]) then
  22.     usage(arg)
  23.   end
  24.   if arg[1] == "-o" then
  25.     outfile = arg[2]
  26.     if not outfile then usage(arg) end
  27.     table.remove(arg, 1)
  28.     table.remove(arg, 1)
  29.   end
  30.   return outfile
  31. end

  32. local function read_files(names)
  33.   local src = ""
  34.   for _,name in ipairs(names) do
  35.     local fp = assert(io.open(name))
  36.     src = src .. fp:read("*a")
  37.     fp:close()
  38.   end
  39.   return src
  40. end

  41. local function transform_lua(code)
  42.   local fixup = {}
  43.   local n = -30000
  44.   code = string.gsub(code, "CHECK_(%w*)%((.-)%)", function(tp, var)
  45.     n = n + 1
  46.     fixup[n] = { "CHECK", tp }
  47.     return format("%s=%d", var, n)
  48.   end)
  49.   code = string.gsub(code, "PAIRS%((.-)%)", function(var)
  50.     fixup.PAIRS = true
  51.     return format("nil, %s, 0", var)
  52.   end)
  53.   return "return "..code, fixup
  54. end

  55. local function read_uleb128(p)
  56.   local v = p[0]; p = p + 1
  57.   if v >= 128 then
  58.     local sh = 7; v = v - 128
  59.     repeat
  60.       local r = p[0]
  61.       v = v + bit.lshift(bit.band(r, 127), sh)
  62.       sh = sh + 7
  63.       p = p + 1
  64.     until r < 128
  65.   end
  66.   return p, v
  67. end

  68. -- ORDER LJ_T
  69. local name2itype = {
  70.   str = 5, func = 9, tab = 12, int = 14, num = 15
  71. }

  72. local BC = {}
  73. for i=0,#bcnames/6-1 do
  74.   BC[string.gsub(string.sub(bcnames, i*6+1, i*6+6), " ", "")] = i
  75. end
  76. local xop, xra = isbe and 3 or 0, isbe and 2 or 1
  77. local xrc, xrb = isbe and 1 or 2, isbe and 0 or 3

  78. local function fixup_dump(dump, fixup)
  79.   local buf = ffi.new("uint8_t[?]", #dump+1, dump)
  80.   local p = buf+5
  81.   local n, sizebc
  82.   p, n = read_uleb128(p)
  83.   local start = p
  84.   p = p + 4
  85.   p = read_uleb128(p)
  86.   p = read_uleb128(p)
  87.   p, sizebc = read_uleb128(p)
  88.   local rawtab = {}
  89.   for i=0,sizebc-1 do
  90.     local op = p[xop]
  91.     if op == BC.KSHORT then
  92.       local rd = p[xrc] + 256*p[xrb]
  93.       rd = bit.arshift(bit.lshift(rd, 16), 16)
  94.       local f = fixup[rd]
  95.       if f then
  96.         if f[1] == "CHECK" then
  97.           local tp = f[2]
  98.           if tp == "tab" then rawtab[p[xra]] = true end
  99.           p[xop] = tp == "num" and BC.ISNUM or BC.ISTYPE
  100.           p[xrb] = 0
  101.           p[xrc] = name2itype[tp]
  102.         else
  103.           error("unhandled fixup type: "..f[1])
  104.         end
  105.       end
  106.     elseif op == BC.TGETV then
  107.       if rawtab[p[xrb]] then
  108.         p[xop] = BC.TGETR
  109.       end
  110.     elseif op == BC.TSETV then
  111.       if rawtab[p[xrb]] then
  112.         p[xop] = BC.TSETR
  113.       end
  114.     elseif op == BC.ITERC then
  115.       if fixup.PAIRS then
  116.         p[xop] = BC.ITERN
  117.       end
  118.     end
  119.     p = p + 4
  120.   end
  121.   return ffi.string(start, n)
  122. end

  123. local function find_defs(src)
  124.   local defs = {}
  125.   for name, code in string.gmatch(src, "LJLIB_LUA%(([^)]*)%)%s*/%*(.-)%*/") do
  126.     local env = {}
  127.     local tcode, fixup = transform_lua(code)
  128.     local func = assert(load(tcode, "", nil, env))()
  129.     defs[name] = fixup_dump(string.dump(func, true), fixup)
  130.     defs[#defs+1] = name
  131.   end
  132.   return defs
  133. end

  134. local function gen_header(defs)
  135.   local t = {}
  136.   local function w(x) t[#t+1] = x end
  137.   w("/* This is a generated file. DO NOT EDIT! */\n\n")
  138.   w("static const int libbc_endian = ") w(isbe and 1 or 0) w(";\n\n")
  139.   local s = ""
  140.   for _,name in ipairs(defs) do
  141.     s = s .. defs[name]
  142.   end
  143.   w("static const uint8_t libbc_code[] = {\n")
  144.   local n = 0
  145.   for i=1,#s do
  146.     local x = string.byte(s, i)
  147.     w(x); w(",")
  148.     n = n + (x < 10 and 2 or (x < 100 and 3 or 4))
  149.     if n >= 75 then n = 0; w("\n") end
  150.   end
  151.   w("0\n};\n\n")
  152.   w("static const struct { const char *name; int ofs; } libbc_map[] = {\n")
  153.   local m = 0
  154.   for _,name in ipairs(defs) do
  155.     w('{"'); w(name); w('",'); w(m) w('},\n')
  156.     m = m + #defs[name]
  157.   end
  158.   w("{NULL,"); w(m); w("}\n};\n\n")
  159.   return table.concat(t)
  160. end

  161. local function write_file(name, data)
  162.   if name == "-" then
  163.     assert(io.write(data))
  164.     assert(io.flush())
  165.   else
  166.     local fp = io.open(name)
  167.     if fp then
  168.       local old = fp:read("*a")
  169.       fp:close()
  170.       if data == old then return end
  171.     end
  172.     fp = assert(io.open(name, "w"))
  173.     assert(fp:write(data))
  174.     assert(fp:close())
  175.   end
  176. end

  177. local outfile = parse_arg(arg)
  178. local src = read_files(arg)
  179. local defs = find_defs(src)
  180. local hdr = gen_header(defs)
  181. write_file(outfile, hdr)