Add support for embedding LuaJIT bytecode for builtins.
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
#include "buildvm.h"
|
||||
#include "lj_obj.h"
|
||||
#include "lj_lib.h"
|
||||
#include "buildvm_libbc.h"
|
||||
|
||||
/* Context for library definitions. */
|
||||
static uint8_t obuf[8192];
|
||||
@@ -151,6 +152,55 @@ static void libdef_func(BuildCtx *ctx, char *p, int arg)
|
||||
regfunc = REGFUNC_OK;
|
||||
}
|
||||
|
||||
static uint32_t libdef_uleb128(uint8_t **pp)
|
||||
{
|
||||
uint8_t *p = *pp;
|
||||
uint32_t v = *p++;
|
||||
if (v >= 0x80) {
|
||||
int sh = 0; v &= 0x7f;
|
||||
do { v |= ((*p & 0x7f) << (sh += 7)); } while (*p++ >= 0x80);
|
||||
}
|
||||
*pp = p;
|
||||
return v;
|
||||
}
|
||||
|
||||
static void libdef_swapbc(uint8_t *p)
|
||||
{
|
||||
uint32_t i, sizebc;
|
||||
p += 4;
|
||||
libdef_uleb128(&p);
|
||||
libdef_uleb128(&p);
|
||||
sizebc = libdef_uleb128(&p);
|
||||
for (i = 0; i < sizebc; i++, p += 4) {
|
||||
uint8_t t = p[0]; p[0] = p[3]; p[3] = t;
|
||||
t = p[1]; p[1] = p[2]; p[2] = t;
|
||||
}
|
||||
}
|
||||
|
||||
static void libdef_lua(BuildCtx *ctx, char *p, int arg)
|
||||
{
|
||||
UNUSED(arg);
|
||||
if (ctx->mode == BUILD_libdef) {
|
||||
int i;
|
||||
for (i = 0; libbc_map[i].name != NULL; i++) {
|
||||
if (!strcmp(libbc_map[i].name, p)) {
|
||||
int ofs = libbc_map[i].ofs;
|
||||
int len = libbc_map[i+1].ofs - ofs;
|
||||
obuf[2]++; /* Bump hash table size. */
|
||||
*optr++ = LIBINIT_LUA;
|
||||
libdef_name(p, 0);
|
||||
memcpy(optr, libbc_code + ofs, len);
|
||||
if (libbc_endian != LJ_BE)
|
||||
libdef_swapbc(optr);
|
||||
optr += len;
|
||||
return;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "Error: missing libbc definition for %s\n", p);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t find_rec(char *name)
|
||||
{
|
||||
char *p = (char *)obuf;
|
||||
@@ -277,6 +327,7 @@ static const LibDefHandler libdef_handlers[] = {
|
||||
{ "CF(", ")", libdef_func, LIBINIT_CF },
|
||||
{ "ASM(", ")", libdef_func, LIBINIT_ASM },
|
||||
{ "ASM_(", ")", libdef_func, LIBINIT_ASM_ },
|
||||
{ "LUA(", ")", libdef_lua, 0 },
|
||||
{ "REC(", ")", libdef_rec, 0 },
|
||||
{ "PUSH(", ")", libdef_push, 0 },
|
||||
{ "SET(", ")", libdef_set, 0 },
|
||||
|
||||
12
src/host/buildvm_libbc.h
Normal file
12
src/host/buildvm_libbc.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/* This is a generated file. DO NOT EDIT! */
|
||||
|
||||
static const int libbc_endian = 0;
|
||||
|
||||
static const uint8_t libbc_code[] = {
|
||||
0
|
||||
};
|
||||
|
||||
static const struct { const char *name; int ofs; } libbc_map[] = {
|
||||
{NULL,0}
|
||||
};
|
||||
|
||||
68
src/host/genlibbc.lua
Normal file
68
src/host/genlibbc.lua
Normal file
@@ -0,0 +1,68 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- Lua script to dump the bytecode of the library functions written in Lua.
|
||||
-- The resulting 'buildvm_libbc.h' is used for the build process of LuaJIT.
|
||||
----------------------------------------------------------------------------
|
||||
-- Copyright (C) 2005-2013 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
local function usage()
|
||||
io.stderr:write("Usage: ", arg and arg[0] or "genlibbc", " lib_*.c\n")
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
local function read_source()
|
||||
if not (arg and arg[1]) then usage() end
|
||||
local src = ""
|
||||
for _,name in ipairs(arg) do
|
||||
local fp = assert(io.open(name))
|
||||
src = src .. fp:read("*a")
|
||||
fp:close()
|
||||
end
|
||||
return src
|
||||
end
|
||||
|
||||
local function find_defs(src)
|
||||
local defs = {}
|
||||
for name, code in string.gmatch(src, "LJLIB_LUA%(([^)]*)%)%s*/%*(.-)%*/") do
|
||||
local env = {}
|
||||
local func = assert(load("return "..code, "", nil, env))()
|
||||
local d = string.dump(func, true)
|
||||
local ofs = 6
|
||||
while string.byte(d, ofs) > 127 do ofs = ofs + 1 end
|
||||
defs[name] = string.sub(d, ofs+1, -2)
|
||||
defs[#defs+1] = name
|
||||
end
|
||||
return defs
|
||||
end
|
||||
|
||||
local function write_defs(fp, defs)
|
||||
fp:write("/* This is a generated file. DO NOT EDIT! */\n\n")
|
||||
fp:write("static const int libbc_endian = ",
|
||||
string.byte(string.dump(function() end), 5) % 2, ";\n\n")
|
||||
local s = ""
|
||||
for _,name in ipairs(defs) do
|
||||
s = s .. defs[name]
|
||||
end
|
||||
fp:write("static const uint8_t libbc_code[] = {\n")
|
||||
local n = 0
|
||||
for i=1,#s do
|
||||
local x = string.byte(s, i)
|
||||
fp:write(x, ",")
|
||||
n = n + (x < 10 and 2 or (x < 100 and 3 or 4))
|
||||
if n >= 75 then n = 0; fp:write("\n") end
|
||||
end
|
||||
fp:write("0\n};\n\n")
|
||||
fp:write("static const struct { const char *name; int ofs; } libbc_map[] = {\n")
|
||||
local m = 0
|
||||
for _,name in ipairs(defs) do
|
||||
fp:write('{"', name, '",', m, '},\n')
|
||||
m = m + #defs[name]
|
||||
end
|
||||
fp:write("{NULL,", m, "}\n};\n\n")
|
||||
fp:flush()
|
||||
end
|
||||
|
||||
local src = read_source()
|
||||
local defs = find_defs(src)
|
||||
write_defs(io.stdout, defs)
|
||||
Reference in New Issue
Block a user