From e20157c6e68472e7c4d82d9ed4c0bb5be029c388 Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Fri, 22 Feb 2013 01:40:41 +0100 Subject: Add support for embedding LuaJIT bytecode for builtins. --- src/host/buildvm_lib.c | 51 ++++++++++++++++++++++++++++++++++++ src/host/buildvm_libbc.h | 12 +++++++++ src/host/genlibbc.lua | 68 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 src/host/buildvm_libbc.h create mode 100644 src/host/genlibbc.lua (limited to 'src/host') diff --git a/src/host/buildvm_lib.c b/src/host/buildvm_lib.c index 40141dfb..182ab90f 100644 --- a/src/host/buildvm_lib.c +++ b/src/host/buildvm_lib.c @@ -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 }, diff --git a/src/host/buildvm_libbc.h b/src/host/buildvm_libbc.h new file mode 100644 index 00000000..d2d83ea6 --- /dev/null +++ b/src/host/buildvm_libbc.h @@ -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} +}; + diff --git a/src/host/genlibbc.lua b/src/host/genlibbc.lua new file mode 100644 index 00000000..b0dbf17a --- /dev/null +++ b/src/host/genlibbc.lua @@ -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) -- cgit v1.2.3-55-g6feb