Add support for embedding LuaJIT bytecode for builtins.

This commit is contained in:
Mike Pall 2013-02-22 01:40:41 +01:00
parent c3219b7d17
commit e20157c6e6
12 changed files with 199 additions and 31 deletions

View File

@ -558,6 +558,10 @@ amalg:
clean: clean:
$(HOST_RM) $(ALL_RM) $(HOST_RM) $(ALL_RM)
libbc:
./$(LUAJIT_T) host/genlibbc.lua $(LJLIB_C) >host/buildvm_libbc.h
$(MAKE) all
depend: depend:
@for file in $(ALL_HDRGEN); do \ @for file in $(ALL_HDRGEN); do \
test -f $$file || touch $$file; \ test -f $$file || touch $$file; \
@ -572,7 +576,7 @@ depend:
test -s $$file || $(HOST_RM) $$file; \ test -s $$file || $(HOST_RM) $$file; \
done done
.PHONY: default all amalg clean depend .PHONY: default all amalg clean libbc depend
############################################################################## ##############################################################################
# Rules for generated files. # Rules for generated files.

View File

@ -124,7 +124,8 @@ lj_lex.o: lj_lex.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
lj_state.h lj_lex.h lj_parse.h lj_char.h lj_strscan.h lj_state.h lj_lex.h lj_parse.h lj_char.h lj_strscan.h
lj_lib.o: lj_lib.c lauxlib.h lua.h luaconf.h lj_obj.h lj_def.h lj_arch.h \ lj_lib.o: lj_lib.c lauxlib.h lua.h luaconf.h lj_obj.h lj_def.h lj_arch.h \
lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_func.h lj_bc.h \ lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_func.h lj_bc.h \
lj_dispatch.h lj_jit.h lj_ir.h lj_vm.h lj_strscan.h lj_lib.h lj_dispatch.h lj_jit.h lj_ir.h lj_vm.h lj_strscan.h lj_lex.h lj_bcdump.h \
lj_lib.h
lj_load.o: lj_load.c lua.h luaconf.h lauxlib.h lj_obj.h lj_def.h \ lj_load.o: lj_load.c lua.h luaconf.h lauxlib.h lj_obj.h lj_def.h \
lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_func.h lj_frame.h \ lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_func.h lj_frame.h \
lj_bc.h lj_vm.h lj_lex.h lj_bcdump.h lj_parse.h lj_bc.h lj_vm.h lj_lex.h lj_bcdump.h lj_parse.h
@ -220,7 +221,8 @@ host/buildvm_asm.o: host/buildvm_asm.c host/buildvm.h lj_def.h lua.h luaconf.h \
host/buildvm_fold.o: host/buildvm_fold.c host/buildvm.h lj_def.h lua.h \ host/buildvm_fold.o: host/buildvm_fold.c host/buildvm.h lj_def.h lua.h \
luaconf.h lj_arch.h lj_obj.h lj_def.h lj_arch.h lj_ir.h lj_obj.h luaconf.h lj_arch.h lj_obj.h lj_def.h lj_arch.h lj_ir.h lj_obj.h
host/buildvm_lib.o: host/buildvm_lib.c host/buildvm.h lj_def.h lua.h luaconf.h \ host/buildvm_lib.o: host/buildvm_lib.c host/buildvm.h lj_def.h lua.h luaconf.h \
lj_arch.h lj_obj.h lj_def.h lj_arch.h lj_lib.h lj_obj.h lj_arch.h lj_obj.h lj_def.h lj_arch.h lj_lib.h lj_obj.h \
host/buildvm_libbc.h
host/buildvm_peobj.o: host/buildvm_peobj.c host/buildvm.h lj_def.h lua.h \ host/buildvm_peobj.o: host/buildvm_peobj.c host/buildvm.h lj_def.h lua.h \
luaconf.h lj_arch.h lj_bc.h lj_def.h lj_arch.h luaconf.h lj_arch.h lj_bc.h lj_def.h lj_arch.h
host/minilua.o: host/minilua.c host/minilua.o: host/minilua.c

View File

@ -6,6 +6,7 @@
#include "buildvm.h" #include "buildvm.h"
#include "lj_obj.h" #include "lj_obj.h"
#include "lj_lib.h" #include "lj_lib.h"
#include "buildvm_libbc.h"
/* Context for library definitions. */ /* Context for library definitions. */
static uint8_t obuf[8192]; static uint8_t obuf[8192];
@ -151,6 +152,55 @@ static void libdef_func(BuildCtx *ctx, char *p, int arg)
regfunc = REGFUNC_OK; 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) static uint32_t find_rec(char *name)
{ {
char *p = (char *)obuf; char *p = (char *)obuf;
@ -277,6 +327,7 @@ static const LibDefHandler libdef_handlers[] = {
{ "CF(", ")", libdef_func, LIBINIT_CF }, { "CF(", ")", libdef_func, LIBINIT_CF },
{ "ASM(", ")", libdef_func, LIBINIT_ASM }, { "ASM(", ")", libdef_func, LIBINIT_ASM },
{ "ASM_(", ")", libdef_func, LIBINIT_ASM_ }, { "ASM_(", ")", libdef_func, LIBINIT_ASM_ },
{ "LUA(", ")", libdef_lua, 0 },
{ "REC(", ")", libdef_rec, 0 }, { "REC(", ")", libdef_rec, 0 },
{ "PUSH(", ")", libdef_push, 0 }, { "PUSH(", ")", libdef_push, 0 },
{ "SET(", ")", libdef_set, 0 }, { "SET(", ")", libdef_set, 0 },

12
src/host/buildvm_libbc.h Normal file
View 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
View 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)

View File

@ -61,6 +61,7 @@ enum {
LJ_FUNC int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, LJ_FUNC int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer,
void *data, int strip); void *data, int strip);
LJ_FUNC GCproto *lj_bcread_proto(LexState *ls);
LJ_FUNC GCproto *lj_bcread(LexState *ls); LJ_FUNC GCproto *lj_bcread(LexState *ls);
#endif #endif

View File

@ -326,25 +326,13 @@ static void bcread_uv(LexState *ls, GCproto *pt, MSize sizeuv)
} }
/* Read a prototype. */ /* Read a prototype. */
static GCproto *bcread_proto(LexState *ls) GCproto *lj_bcread_proto(LexState *ls)
{ {
GCproto *pt; GCproto *pt;
MSize framesize, numparams, flags, sizeuv, sizekgc, sizekn, sizebc, sizept; MSize framesize, numparams, flags, sizeuv, sizekgc, sizekn, sizebc, sizept;
MSize ofsk, ofsuv, ofsdbg; MSize ofsk, ofsuv, ofsdbg;
MSize sizedbg = 0; MSize sizedbg = 0;
BCLine firstline = 0, numline = 0; BCLine firstline = 0, numline = 0;
MSize len, startn;
/* Read length. */
if (ls->n > 0 && ls->p[0] == 0) { /* Shortcut EOF. */
ls->n--; ls->p++;
return NULL;
}
bcread_want(ls, 5);
len = bcread_uleb128(ls);
if (!len) return NULL; /* EOF */
bcread_need(ls, len);
startn = ls->n;
/* Read prototype header. */ /* Read prototype header. */
flags = bcread_byte(ls); flags = bcread_byte(ls);
@ -413,9 +401,6 @@ static GCproto *bcread_proto(LexState *ls)
setmref(pt->uvinfo, NULL); setmref(pt->uvinfo, NULL);
setmref(pt->varinfo, NULL); setmref(pt->varinfo, NULL);
} }
if (len != startn - ls->n)
bcread_error(ls, LJ_ERR_BCBAD);
return pt; return pt;
} }
@ -462,8 +447,21 @@ GCproto *lj_bcread(LexState *ls)
if (!bcread_header(ls)) if (!bcread_header(ls))
bcread_error(ls, LJ_ERR_BCFMT); bcread_error(ls, LJ_ERR_BCFMT);
for (;;) { /* Process all prototypes in the bytecode dump. */ for (;;) { /* Process all prototypes in the bytecode dump. */
GCproto *pt = bcread_proto(ls); GCproto *pt;
if (!pt) break; MSize len, startn;
/* Read length. */
if (ls->n > 0 && ls->p[0] == 0) { /* Shortcut EOF. */
ls->n--; ls->p++;
break;
}
bcread_want(ls, 5);
len = bcread_uleb128(ls);
if (!len) break; /* EOF */
bcread_need(ls, len);
startn = ls->n;
pt = lj_bcread_proto(ls);
if (len != startn - ls->n)
bcread_error(ls, LJ_ERR_BCBAD);
setprotoV(L, L->top, pt); setprotoV(L, L->top, pt);
incr_top(L); incr_top(L);
} }

View File

@ -321,7 +321,7 @@ const char *lj_debug_funcname(lua_State *L, TValue *frame, const char **name)
/* -- Source code locations ----------------------------------------------- */ /* -- Source code locations ----------------------------------------------- */
/* Generate shortened source name. */ /* Generate shortened source name. */
void lj_debug_shortname(char *out, GCstr *str) void lj_debug_shortname(char *out, GCstr *str, BCLine line)
{ {
const char *src = strdata(str); const char *src = strdata(str);
if (*src == '=') { if (*src == '=') {
@ -335,11 +335,11 @@ void lj_debug_shortname(char *out, GCstr *str)
*out++ = '.'; *out++ = '.'; *out++ = '.'; *out++ = '.'; *out++ = '.'; *out++ = '.';
} }
strcpy(out, src); strcpy(out, src);
} else { /* Output [string "string"]. */ } else { /* Output [string "string"] or [builtin:name]. */
size_t len; /* Length, up to first control char. */ size_t len; /* Length, up to first control char. */
for (len = 0; len < LUA_IDSIZE-12; len++) for (len = 0; len < LUA_IDSIZE-12; len++)
if (((const unsigned char *)src)[len] < ' ') break; if (((const unsigned char *)src)[len] < ' ') break;
strcpy(out, "[string \""); out += 9; strcpy(out, line == ~(BCLine)0 ? "[builtin:" : "[string \""); out += 9;
if (src[len] != '\0') { /* Must truncate? */ if (src[len] != '\0') { /* Must truncate? */
if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15; if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15;
strncpy(out, src, len); out += len; strncpy(out, src, len); out += len;
@ -347,7 +347,7 @@ void lj_debug_shortname(char *out, GCstr *str)
} else { } else {
strcpy(out, src); out += len; strcpy(out, src); out += len;
} }
strcpy(out, "\"]"); strcpy(out, line == ~(BCLine)0 ? "]" : "\"]");
} }
} }
@ -360,8 +360,9 @@ void lj_debug_addloc(lua_State *L, const char *msg,
if (isluafunc(fn)) { if (isluafunc(fn)) {
BCLine line = debug_frameline(L, fn, nextframe); BCLine line = debug_frameline(L, fn, nextframe);
if (line >= 0) { if (line >= 0) {
GCproto *pt = funcproto(fn);
char buf[LUA_IDSIZE]; char buf[LUA_IDSIZE];
lj_debug_shortname(buf, proto_chunkname(funcproto(fn))); lj_debug_shortname(buf, proto_chunkname(pt), pt->firstline);
lj_str_pushf(L, "%s:%d: %s", buf, line, msg); lj_str_pushf(L, "%s:%d: %s", buf, line, msg);
return; return;
} }
@ -377,7 +378,9 @@ void lj_debug_pushloc(lua_State *L, GCproto *pt, BCPos pc)
const char *s = strdata(name); const char *s = strdata(name);
MSize i, len = name->len; MSize i, len = name->len;
BCLine line = lj_debug_line(pt, pc); BCLine line = lj_debug_line(pt, pc);
if (*s == '@') { if (pt->firstline == ~(BCLine)0) {
lj_str_pushf(L, "builtin:%s", s);
} else if (*s == '@') {
s++; len--; s++; len--;
for (i = len; i > 0; i--) for (i = len; i > 0; i--)
if (s[i] == '/' || s[i] == '\\') { if (s[i] == '/' || s[i] == '\\') {
@ -453,7 +456,7 @@ int lj_debug_getinfo(lua_State *L, const char *what, lj_Debug *ar, int ext)
BCLine firstline = pt->firstline; BCLine firstline = pt->firstline;
GCstr *name = proto_chunkname(pt); GCstr *name = proto_chunkname(pt);
ar->source = strdata(name); ar->source = strdata(name);
lj_debug_shortname(ar->short_src, name); lj_debug_shortname(ar->short_src, name, pt->firstline);
ar->linedefined = (int)firstline; ar->linedefined = (int)firstline;
ar->lastlinedefined = (int)(firstline + pt->numline); ar->lastlinedefined = (int)(firstline + pt->numline);
ar->what = firstline ? "Lua" : "main"; ar->what = firstline ? "Lua" : "main";

View File

@ -34,7 +34,7 @@ LJ_FUNC const char *lj_debug_slotname(GCproto *pt, const BCIns *pc,
BCReg slot, const char **name); BCReg slot, const char **name);
LJ_FUNC const char *lj_debug_funcname(lua_State *L, TValue *frame, LJ_FUNC const char *lj_debug_funcname(lua_State *L, TValue *frame,
const char **name); const char **name);
LJ_FUNC void lj_debug_shortname(char *out, GCstr *str); LJ_FUNC void lj_debug_shortname(char *out, GCstr *str, BCLine line);
LJ_FUNC void lj_debug_addloc(lua_State *L, const char *msg, LJ_FUNC void lj_debug_addloc(lua_State *L, const char *msg,
cTValue *frame, cTValue *nextframe); cTValue *frame, cTValue *nextframe);
LJ_FUNC void lj_debug_pushloc(lua_State *L, GCproto *pt, BCPos pc); LJ_FUNC void lj_debug_pushloc(lua_State *L, GCproto *pt, BCPos pc);

View File

@ -587,7 +587,7 @@ LJ_NOINLINE void lj_err_lex(lua_State *L, GCstr *src, const char *tok,
{ {
char buff[LUA_IDSIZE]; char buff[LUA_IDSIZE];
const char *msg; const char *msg;
lj_debug_shortname(buff, src); lj_debug_shortname(buff, src, line);
msg = lj_str_pushvf(L, err2msg(em), argp); msg = lj_str_pushvf(L, err2msg(em), argp);
msg = lj_str_pushf(L, "%s:%d: %s", buff, line, msg); msg = lj_str_pushf(L, "%s:%d: %s", buff, line, msg);
if (tok) if (tok)

View File

@ -18,6 +18,8 @@
#include "lj_dispatch.h" #include "lj_dispatch.h"
#include "lj_vm.h" #include "lj_vm.h"
#include "lj_strscan.h" #include "lj_strscan.h"
#include "lj_lex.h"
#include "lj_bcdump.h"
#include "lj_lib.h" #include "lj_lib.h"
/* -- Library initialization ---------------------------------------------- */ /* -- Library initialization ---------------------------------------------- */
@ -43,6 +45,28 @@ static GCtab *lib_create_table(lua_State *L, const char *libname, int hsize)
return tabV(L->top-1); return tabV(L->top-1);
} }
static const uint8_t *lib_read_lfunc(lua_State *L, const uint8_t *p, GCtab *tab)
{
int len = *p++;
GCstr *name = lj_str_new(L, (const char *)p, len);
LexState ls;
GCproto *pt;
GCfunc *fn;
memset(&ls, 0, sizeof(ls));
ls.L = L;
ls.p = (const char *)(p+len);
ls.n = ~(MSize)0;
ls.current = -1;
ls.level = (BCDUMP_F_STRIP|(LJ_BE*BCDUMP_F_BE));
ls.chunkname = name;
pt = lj_bcread_proto(&ls);
pt->firstline = ~(BCLine)0;
fn = lj_func_newL_empty(L, pt, tabref(L->env));
/* NOBARRIER: See below for common barrier. */
setfuncV(L, lj_tab_setstr(L, tab, name), fn);
return (const uint8_t *)ls.p;
}
void lj_lib_register(lua_State *L, const char *libname, void lj_lib_register(lua_State *L, const char *libname,
const uint8_t *p, const lua_CFunction *cf) const uint8_t *p, const lua_CFunction *cf)
{ {
@ -87,6 +111,9 @@ void lj_lib_register(lua_State *L, const char *libname,
ofn = fn; ofn = fn;
} else { } else {
switch (tag | len) { switch (tag | len) {
case LIBINIT_LUA:
p = lib_read_lfunc(L, p, tab);
break;
case LIBINIT_SET: case LIBINIT_SET:
L->top -= 2; L->top -= 2;
if (tvisstr(L->top+1) && strV(L->top+1)->len == 0) if (tvisstr(L->top+1) && strV(L->top+1)->len == 0)

View File

@ -77,6 +77,7 @@ static LJ_AINLINE void lj_lib_pushcc(lua_State *L, lua_CFunction f,
#define LJLIB_CF(name) static int lj_cf_##name(lua_State *L) #define LJLIB_CF(name) static int lj_cf_##name(lua_State *L)
#define LJLIB_ASM(name) static int lj_ffh_##name(lua_State *L) #define LJLIB_ASM(name) static int lj_ffh_##name(lua_State *L)
#define LJLIB_ASM_(name) #define LJLIB_ASM_(name)
#define LJLIB_LUA(name)
#define LJLIB_SET(name) #define LJLIB_SET(name)
#define LJLIB_PUSH(arg) #define LJLIB_PUSH(arg)
#define LJLIB_REC(handler) #define LJLIB_REC(handler)
@ -96,7 +97,8 @@ LJ_FUNC void lj_lib_register(lua_State *L, const char *libname,
#define LIBINIT_ASM 0x40 #define LIBINIT_ASM 0x40
#define LIBINIT_ASM_ 0x80 #define LIBINIT_ASM_ 0x80
#define LIBINIT_STRING 0xc0 #define LIBINIT_STRING 0xc0
#define LIBINIT_MAXSTR 0x39 #define LIBINIT_MAXSTR 0x38
#define LIBINIT_LUA 0xf9
#define LIBINIT_SET 0xfa #define LIBINIT_SET 0xfa
#define LIBINIT_NUMBER 0xfb #define LIBINIT_NUMBER 0xfb
#define LIBINIT_COPY 0xfc #define LIBINIT_COPY 0xfc