From 34c6b33a2fb49b6e64f55c8ac369428ddbc74bf5 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Thu, 27 Aug 2020 01:24:01 +0100 Subject: [PATCH 01/15] issue #198 WIP add interface to RaviCompiler project --- CMakeLists.txt | 28 ++++++++++++--- cmake/FindRaviComp.cmake | 14 ++++++++ include/lualib.h | 6 ++-- ravi-config.h.in | 1 + src/linit.c | 3 ++ src/ravi_complib.c | 75 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 121 insertions(+), 6 deletions(-) create mode 100644 cmake/FindRaviComp.cmake create mode 100644 src/ravi_complib.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 068755d..e7471f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,9 @@ option(STATIC_BUILD "Build static version of Ravi, default is OFF" OFF) option(COMPUTED_GOTO "Controls whether the interpreter switch will use computed gotos on gcc/clang, default is ON" ON) option(LTESTS "Controls whether ltests are enabled in Debug mode; note requires Debug build" ON) option(ASAN "Controls whether address sanitizer should be enabled" OFF) +option(RAVICOMP "Controls whether to link in RaviComp" ON) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") # By default on non-Windows platforms we enable MIR JIT if (NOT WIN32 @@ -66,6 +69,7 @@ set(C2MIR_SRCS mir/c2mir/c2mir.c) set(MIR_JIT_SRCS src/ravi_mirjit.c) set(NO_JIT_SRCS src/ravi_nojit.c) set(LUA_CMD_SRCS src/lua.c) +set(RAVICOMP_SRCS src/ravi_complib.c) file(GLOB RAVI_HEADERS "${PROJECT_SOURCE_DIR}/include/*.h") if (COMPUTED_GOTO AND NOT MSVC) @@ -89,7 +93,6 @@ if (ASAN) endif() endif() - if (LLVM_JIT) find_package(LLVM REQUIRED CONFIG) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") @@ -133,10 +136,18 @@ else () endif () endif () +if (RAVICOMP) + find_package(RaviComp REQUIRED) + set(ADDON_SRCS ${RAVICOMP_SRCS}) + set_property(SOURCE ${RAVICOMP_SRCS} + APPEND + PROPERTY INCLUDE_DIRECTORIES ${RAVICOMP_INCLUDE_DIRS}) +endif() + # IDE stuff if (MSVC OR APPLE) source_group("Ravi Headers" FILES ${RAVI_HEADERS}) - source_group("Ravi Source Files" FILES ${LUA_CORE_SRCS} ${LUA_LIB_SRCS} ${JIT_SRCS}) + source_group("Ravi Source Files" FILES ${LUA_CORE_SRCS} ${LUA_LIB_SRCS} ${JIT_SRCS} ${ADDON_SRCS}) endif () # Misc setup @@ -208,6 +219,7 @@ if (LLVM_JIT) message(STATUS "LLVM_LIBS ${LLVM_LIBS}") endif () + set(LIBRAVI_NAME libravi) #Main library @@ -215,8 +227,9 @@ add_library(${LIBRAVI_NAME} ${LIBRAVI_BUILD_TYPE} ${RAVI_HEADERS} ${LUA_LIB_SRCS} ${LUA_CORE_SRCS} - ${JIT_SRCS}) -target_link_libraries(${LIBRAVI_NAME} ${EXTRA_LIBRARIES} ${LLVM_LIBS} ${MIRJIT_LIBRARIES}) + ${JIT_SRCS} + ${ADDON_SRCS}) +target_link_libraries(${LIBRAVI_NAME} ${EXTRA_LIBRARIES} ${LLVM_LIBS} ${MIRJIT_LIBRARIES} ${RAVICOMP_LIBRARIES}) # Main Ravi executable add_executable(ravi ${LUA_CMD_SRCS}) @@ -279,6 +292,13 @@ if (NOT STATIC_BUILD) else () set_target_properties(${LIBRAVI_NAME} PROPERTIES PREFIX "") endif () +if (RAVICOMP) + set_property( + TARGET ${LIBRAVI_NAME} + APPEND + PROPERTY COMPILE_DEFINITIONS "USE_RAVICOMP=1") + set(USE_RAVICOMP 1) +endif() if (APPLE) set_property( TARGET ${LIBRAVI_NAME} libravinojit_static diff --git a/cmake/FindRaviComp.cmake b/cmake/FindRaviComp.cmake new file mode 100644 index 0000000..fd9c10d --- /dev/null +++ b/cmake/FindRaviComp.cmake @@ -0,0 +1,14 @@ +find_path(RAVICOMP_INCLUDE_DIRS ravi_compiler.h + PATHS + c:/Software/ravicomp/include/ravicomp + ~/Software/ravicomp/include/ravicomp + NO_DEFAULT_PATH + ) + +find_library(RAVICOMP_LIBRARIES + NAMES ravicomp + PATHS + c:/Software/ravicomp/lib + ~/Software/ravicomp/lib + ) + diff --git a/include/lualib.h b/include/lualib.h index 1579358..50f7dac 100644 --- a/include/lualib.h +++ b/include/lualib.h @@ -54,8 +54,10 @@ LUAMOD_API int (luaopen_package) (lua_State *L); #define LUA_RAVILIBNAME "ravi" LUAMOD_API int (raviopen_jit)(lua_State *L); -#define LUA_ASTLIBNAME "ast" -LUAMOD_API int (raviopen_ast_library)(lua_State *L); +#define LUA_RAVICOMPLIBNAME "compiler" +LUAMOD_API int (raviopen_compiler)(lua_State *L); + + /* open all previous libraries */ LUALIB_API void (luaL_openlibs) (lua_State *L); diff --git a/ravi-config.h.in b/ravi-config.h.in index 0e21edc..bf82f93 100644 --- a/ravi-config.h.in +++ b/ravi-config.h.in @@ -5,5 +5,6 @@ #cmakedefine USE_LLVM @USE_LLVM@ #cmakedefine USE_OMRJIT @USE_OMRJIT@ #cmakedefine USE_MIRJIT @USE_MIRJIT@ +#cmakedefine USE_RAVICOMP @USE_RAVICOMP@ #endif //_REDUKTI_RAVI_CONFIG_H_IN_H diff --git a/src/linit.c b/src/linit.c index d3f44b3..d2c2ac4 100644 --- a/src/linit.c +++ b/src/linit.c @@ -54,6 +54,9 @@ static const luaL_Reg loadedlibs[] = { {LUA_BITLIBNAME, luaopen_bit32}, #endif {LUAJIT_BITLIBNAME, luaopen_bit }, +#if defined(USE_RAVICOMP) + {LUA_RAVICOMPLIBNAME, raviopen_compiler }, +#endif {NULL, NULL} }; diff --git a/src/ravi_complib.c b/src/ravi_complib.c new file mode 100644 index 0000000..77fb268 --- /dev/null +++ b/src/ravi_complib.c @@ -0,0 +1,75 @@ +#include "ravi_api.h" + +#define LUA_CORE + +#include "lua.h" +#include "lapi.h" +#include "lauxlib.h" +#include "lfunc.h" +#include "lmem.h" +#include "lstring.h" +#include "ltable.h" + +struct CompilerContext { + lua_State* L; + Table* h; /* to avoid collection/reuse strings */ +}; + +static Proto* lua_newProto(void* context, Proto* parent) { + struct CompilerContext* ccontext = (struct CompilerContext*)context; + lua_State* L = ccontext->L; + Proto* p = luaF_newproto(L); + if (parent) { + int old_size = parent->sizep; + int new_size = parent->sizep + 1; + luaM_growvector(L, parent->p, old_size, new_size, Proto*, MAXARG_Bx, "functions"); + parent->p[parent->sizep++] = p; + // luaC_objbarrier(L, f, clp); + } + return p; +} + +/* +** creates a new string and anchors it in scanner's table so that +** it will not be collected until the end of the compilation +** (by that time it should be anchored somewhere) +*/ +//TString* create_newstring(lua_State* L, Table *h, const char* str, size_t l) { +// TValue* o; /* entry for 'str' */ +// TString* ts = luaS_newlstr(L, str, l); /* create new string */ +// setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ +// o = luaH_set(L, h, L->top - 1); +// if (ttisnil(o)) { /* not in use yet? */ +// /* boolean value does not need GC barrier; +// table has no metatable, so it does not need to invalidate cache */ +// setbvalue(o, 1); /* t[string] = true */ +// luaC_checkGC(L); +// } +// else { /* string already present */ +// ts = tsvalue(keyfromval(o)); /* re-use value previously stored */ +// } +// L->top--; /* remove string from stack */ +// return ts; +//} + +/* Add a string constant to Proto and return its index */ +static int lua_newStringConstant(void *context, Proto* proto, const char* s, unsigned len) { + struct CompilerContext* ccontext = (struct CompilerContext*)context; + lua_State* L = ccontext->L; + Table* h = ccontext->h; + //TString* ts = create_newstring(L, h, s, len); + +} + +/* Compile the C code for the given proto, and C source */ +void lua_compileProto(lua_State* L, Proto* proto, const char* C_src, unsigned len) { + +} + +static const luaL_Reg ravilib[] = { + {NULL, NULL} }; + +int (raviopen_compiler)(lua_State *L) { + luaL_newlib(L, ravilib); + return 1; +} \ No newline at end of file From 02a7796f774c3cc97015db9ec4b806c5089bf7af Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Thu, 27 Aug 2020 22:00:55 +0100 Subject: [PATCH 02/15] issue #198 WIP --- src/ravi_complib.c | 128 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 104 insertions(+), 24 deletions(-) diff --git a/src/ravi_complib.c b/src/ravi_complib.c index 77fb268..5ea8072 100644 --- a/src/ravi_complib.c +++ b/src/ravi_complib.c @@ -30,39 +30,119 @@ static Proto* lua_newProto(void* context, Proto* parent) { } /* -** creates a new string and anchors it in scanner's table so that -** it will not be collected until the end of the compilation -** (by that time it should be anchored somewhere) +* Based off the Lua lexer code. */ -//TString* create_newstring(lua_State* L, Table *h, const char* str, size_t l) { -// TValue* o; /* entry for 'str' */ -// TString* ts = luaS_newlstr(L, str, l); /* create new string */ -// setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ -// o = luaH_set(L, h, L->top - 1); -// if (ttisnil(o)) { /* not in use yet? */ -// /* boolean value does not need GC barrier; -// table has no metatable, so it does not need to invalidate cache */ -// setbvalue(o, 1); /* t[string] = true */ -// luaC_checkGC(L); -// } -// else { /* string already present */ -// ts = tsvalue(keyfromval(o)); /* re-use value previously stored */ -// } -// L->top--; /* remove string from stack */ -// return ts; -//} +TString* create_newstring(lua_State* L, Table *h, const char* str, size_t l) { + TValue* o; /* entry for 'str' */ + TString* ts = luaS_newlstr(L, str, l); /* create new string */ + setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ + o = luaH_set(L, h, L->top - 1); + if (ttisnil(o)) { /* not in use yet? */ + /* boolean value does not need GC barrier; + table has no metatable, so it does not need to invalidate cache */ + setbvalue(o, 1); /* t[string] = true */ + luaC_checkGC(L); + } + else { /* string already present */ + ts = tsvalue(keyfromval(o)); /* re-use value previously stored */ + } + L->top--; /* remove string from stack */ + return ts; +} + +/* +** Add constant 'v' to prototype's list of constants (field 'k'). +** Use scanner's table to cache position of constants in constant list +** and try to reuse constants. Because some values should not be used +** as keys (nil cannot be a key, integer keys can collapse with float +** keys), the caller must provide a useful 'key' for indexing the cache. +*/ +static int addk(lua_State *L, Proto* f, Table* h, TValue* key, TValue* v) { + TValue* idx = luaH_set(L, h, key); /* index scanner table */ + int k, oldsize; + if (ttisinteger(idx)) { /* is there an index there? */ + k = cast_int(ivalue(idx)); + /* correct value? (warning: must distinguish floats from integers!) */ + if (k < f->sizek && ttype(&f->k[k]) == ttype(v) && + luaV_rawequalobj(&f->k[k], v)) + return k; /* reuse index */ + } + /* constant not found; create a new entry */ + oldsize = f->sizek; + k = f->sizek; + /* numerical value does not need GC barrier; + table has no metatable, so it does not need to invalidate cache */ + setivalue(idx, k); + luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); + while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); + setobj(L, &f->k[k], v); + f->sizek++; + luaC_barrier(L, f, v); + return k; +} + + +/* +** Add a string to list of constants and return its index. +*/ +static int lua_stringK(lua_State *L, Proto* p, Table *h, TString* s) { + TValue o; + setsvalue(L, &o, s); + return addk(L, p, h, &o, &o); /* use string itself as key */ +} /* Add a string constant to Proto and return its index */ -static int lua_newStringConstant(void *context, Proto* proto, const char* s, unsigned len) { +static int lua_newStringConstant(void *context, Proto* proto, struct string_object *s) { struct CompilerContext* ccontext = (struct CompilerContext*)context; lua_State* L = ccontext->L; Table* h = ccontext->h; - //TString* ts = create_newstring(L, h, s, len); - + TString* ts = NULL; + if (s->userdata == NULL) { + ts = create_newstring(L, h, s->str, s->len); + s->userdata = ts; + } + else { + ts = (TString *) s->userdata; + } + return lua_stringK(L, proto, h, ts); } /* Compile the C code for the given proto, and C source */ -void lua_compileProto(lua_State* L, Proto* proto, const char* C_src, unsigned len) { +int lua_compileProto(void *context, Proto* proto, const char* C_src, unsigned len) { + struct CompilerContext* ccontext = (struct CompilerContext*)context; + lua_State* L = ccontext->L; + +} + +static int load_and_compile(lua_State* L) { + const char* s = luaL_checkstring(L, 1); + struct CompilerContext ccontext = { .L = L }; + + LClosure* cl = luaF_newLclosure(L, 1); /* create main closure */ + setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */ + luaD_inctop(L); + ccontext.h = luaH_new(L); /* create table for string constants */ + sethvalue(L, L->top, ccontext.h); /* anchor it */ + luaD_inctop(L); + Proto *main_proto = cl->p = luaF_newproto(L); + luaC_objbarrier(L, cl, cl->p); + + struct Ravi_CompilerInterface ravicomp_interface = { + .source = s, + .source_len = strlen(s), + .source_name = "input", + .lua_newProto = lua_newProto, + .lua_newStringConstant = lua_newStringConstant, + .main_proto = main_proto, + .context = &ccontext + }; + + int rc = raviX_compile(&ravicomp_interface); + L->top--; /* remove table */ + + lua_assert(cl->nupvalues == cl->p->sizeupvalues); + luaF_initupvals(L, cl); + } From 2cab1f104afcac2e01bf449339520f57f3af306b Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 29 Aug 2020 13:33:04 +0100 Subject: [PATCH 03/15] issue #198 WIP flesh out some more api functions --- src/ravi_complib.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/ravi_complib.c b/src/ravi_complib.c index 5ea8072..5e88c5c 100644 --- a/src/ravi_complib.c +++ b/src/ravi_complib.c @@ -107,12 +107,25 @@ static int lua_newStringConstant(void *context, Proto* proto, struct string_obje return lua_stringK(L, proto, h, ts); } -/* Compile the C code for the given proto, and C source */ -int lua_compileProto(void *context, Proto* proto, const char* C_src, unsigned len) { - struct CompilerContext* ccontext = (struct CompilerContext*)context; - lua_State* L = ccontext->L; +static void init_C_compiler(void* context) { + struct CompilerContext* ccontext = (struct CompilerContext*)context; + mir_prepare(ccontext->jit->jit, 2); +} +static void* compile_C(void* context, const char* C_src, unsigned len) { + struct CompilerContext* ccontext = (struct CompilerContext*)context; + return NULL; +} +static void finish_C_compiler(void* context) { + struct CompilerContext* ccontext = (struct CompilerContext*)context; + mir_cleanup(ccontext->jit->jit); +} +static lua_CFunction get_compiled_function(void* context, void* module, const char* name) { + struct CompilerContext* ccontext = (struct CompilerContext*)context; + MIR_module_t M = (MIR_module_t)module; + return (lua_CFunction)mir_get_func(ccontext->jit->jit, M, name); } +static void lua_setProtoFunction(void* context, Proto* p, lua_CFunction func) { p->ravi_jit.jit_function = func; } static int load_and_compile(lua_State* L) { const char* s = luaL_checkstring(L, 1); From 98c96c11eb6067567e853a9b6b874ea86c1f7314 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 29 Aug 2020 13:39:01 +0100 Subject: [PATCH 04/15] issue #198 WIP flesh out some more api functions --- CMakeLists.txt | 7 +- cmake/FindRaviComp.cmake | 1 + src/ravi_complib.c | 216 ++++++++++++++++++++------------------- 3 files changed, 118 insertions(+), 106 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a490325..23ef2e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,12 +140,17 @@ else () endif () endif () -if (RAVICOMP) +if (RAVICOMP AND MIR_JIT) + # Need MIR_JIT for the compiler add-on find_package(RaviComp REQUIRED) set(ADDON_SRCS ${RAVICOMP_SRCS}) set_property(SOURCE ${RAVICOMP_SRCS} APPEND PROPERTY INCLUDE_DIRECTORIES ${RAVICOMP_INCLUDE_DIRS}) + if ($ENV{CLION_IDE}) + # CLion seems unable to handle include paths set on sources + include_directories(${RAVICOMP_INCLUDE_DIRS}) + endif () endif() # IDE stuff diff --git a/cmake/FindRaviComp.cmake b/cmake/FindRaviComp.cmake index fd9c10d..3a4d6da 100644 --- a/cmake/FindRaviComp.cmake +++ b/cmake/FindRaviComp.cmake @@ -10,5 +10,6 @@ find_library(RAVICOMP_LIBRARIES PATHS c:/Software/ravicomp/lib ~/Software/ravicomp/lib + ~/Software/ravicomp/lib64 ) diff --git a/src/ravi_complib.c b/src/ravi_complib.c index 5e88c5c..8ef2c4f 100644 --- a/src/ravi_complib.c +++ b/src/ravi_complib.c @@ -2,6 +2,8 @@ #define LUA_CORE +#include "ravi_mirjit.h" + #include "lua.h" #include "lapi.h" #include "lauxlib.h" @@ -9,45 +11,50 @@ #include "lmem.h" #include "lstring.h" #include "ltable.h" +#include "lvm.h" + +#include struct CompilerContext { - lua_State* L; - Table* h; /* to avoid collection/reuse strings */ + lua_State* L; + ravi_State* jit; + Table* h; /* to avoid collection/reuse strings */ }; +/* Create a new proto and insert it into parent's list of protos */ static Proto* lua_newProto(void* context, Proto* parent) { - struct CompilerContext* ccontext = (struct CompilerContext*)context; - lua_State* L = ccontext->L; - Proto* p = luaF_newproto(L); - if (parent) { - int old_size = parent->sizep; - int new_size = parent->sizep + 1; - luaM_growvector(L, parent->p, old_size, new_size, Proto*, MAXARG_Bx, "functions"); - parent->p[parent->sizep++] = p; - // luaC_objbarrier(L, f, clp); - } - return p; + struct CompilerContext* ccontext = (struct CompilerContext*)context; + lua_State* L = ccontext->L; + Proto* p = luaF_newproto(L); + assert(parent); + /* FIXME make this more efficient */ + int old_size = parent->sizep; + int new_size = parent->sizep + 1; + luaM_growvector(L, parent->p, old_size, new_size, Proto*, MAXARG_Bx, "functions"); + parent->p[parent->sizep++] = p; + luaC_objbarrier(L, parent, p); + return p; } /* -* Based off the Lua lexer code. -*/ -TString* create_newstring(lua_State* L, Table *h, const char* str, size_t l) { - TValue* o; /* entry for 'str' */ - TString* ts = luaS_newlstr(L, str, l); /* create new string */ - setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ - o = luaH_set(L, h, L->top - 1); - if (ttisnil(o)) { /* not in use yet? */ - /* boolean value does not need GC barrier; - table has no metatable, so it does not need to invalidate cache */ - setbvalue(o, 1); /* t[string] = true */ - luaC_checkGC(L); - } - else { /* string already present */ - ts = tsvalue(keyfromval(o)); /* re-use value previously stored */ - } - L->top--; /* remove string from stack */ - return ts; + * Based off the Lua lexer code. + */ +TString* create_newstring(lua_State* L, Table* h, const char* str, size_t l) { + TValue* o; /* entry for 'str' */ + TString* ts = luaS_newlstr(L, str, l); /* create new string */ + setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ + o = luaH_set(L, h, L->top - 1); + if (ttisnil(o)) { /* not in use yet? */ + /* boolean value does not need GC barrier; + table has no metatable, so it does not need to invalidate cache */ + setbvalue(o, 1); /* t[string] = true */ + luaC_checkGC(L); + } + else { /* string already present */ + ts = tsvalue(keyfromval(o)); /* re-use value previously stored */ + } + L->top--; /* remove string from stack */ + return ts; } /* @@ -57,54 +64,53 @@ TString* create_newstring(lua_State* L, Table *h, const char* str, size_t l) { ** as keys (nil cannot be a key, integer keys can collapse with float ** keys), the caller must provide a useful 'key' for indexing the cache. */ -static int addk(lua_State *L, Proto* f, Table* h, TValue* key, TValue* v) { - TValue* idx = luaH_set(L, h, key); /* index scanner table */ - int k, oldsize; - if (ttisinteger(idx)) { /* is there an index there? */ - k = cast_int(ivalue(idx)); - /* correct value? (warning: must distinguish floats from integers!) */ - if (k < f->sizek && ttype(&f->k[k]) == ttype(v) && - luaV_rawequalobj(&f->k[k], v)) - return k; /* reuse index */ - } - /* constant not found; create a new entry */ - oldsize = f->sizek; - k = f->sizek; - /* numerical value does not need GC barrier; - table has no metatable, so it does not need to invalidate cache */ - setivalue(idx, k); - luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); - while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); - setobj(L, &f->k[k], v); - f->sizek++; - luaC_barrier(L, f, v); - return k; +static int addk(lua_State* L, Proto* f, Table* h, TValue* key, TValue* v) { + TValue* idx = luaH_set(L, h, key); /* index scanner table */ + int k, oldsize; + if (ttisinteger(idx)) { /* is there an index there? */ + k = cast_int(ivalue(idx)); + /* correct value? (warning: must distinguish floats from integers!) */ + if (k < f->sizek && ttype(&f->k[k]) == ttype(v) && luaV_rawequalobj(&f->k[k], v)) + return k; /* reuse index */ + } + /* constant not found; create a new entry */ + oldsize = f->sizek; + k = f->sizek; + /* numerical value does not need GC barrier; + table has no metatable, so it does not need to invalidate cache */ + setivalue(idx, k); + luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); + while (oldsize < f->sizek) + setnilvalue(&f->k[oldsize++]); + setobj(L, &f->k[k], v); + f->sizek++; + luaC_barrier(L, f, v); + return k; } - /* ** Add a string to list of constants and return its index. */ -static int lua_stringK(lua_State *L, Proto* p, Table *h, TString* s) { - TValue o; - setsvalue(L, &o, s); - return addk(L, p, h, &o, &o); /* use string itself as key */ +static int lua_stringK(lua_State* L, Proto* p, Table* h, TString* s) { + TValue o; + setsvalue(L, &o, s); + return addk(L, p, h, &o, &o); /* use string itself as key */ } /* Add a string constant to Proto and return its index */ -static int lua_newStringConstant(void *context, Proto* proto, struct string_object *s) { - struct CompilerContext* ccontext = (struct CompilerContext*)context; - lua_State* L = ccontext->L; - Table* h = ccontext->h; - TString* ts = NULL; - if (s->userdata == NULL) { - ts = create_newstring(L, h, s->str, s->len); - s->userdata = ts; - } - else { - ts = (TString *) s->userdata; - } - return lua_stringK(L, proto, h, ts); +static int lua_newStringConstant(void* context, Proto* proto, struct string_object* s) { + struct CompilerContext* ccontext = (struct CompilerContext*)context; + lua_State* L = ccontext->L; + Table* h = ccontext->h; + TString* ts = NULL; + if (s->userdata == NULL) { + ts = create_newstring(L, h, s->str, s->len); + s->userdata = ts; + } + else { + ts = (TString*)s->userdata; + } + return lua_stringK(L, proto, h, ts); } static void init_C_compiler(void* context) { @@ -128,41 +134,41 @@ static lua_CFunction get_compiled_function(void* context, void* module, const ch static void lua_setProtoFunction(void* context, Proto* p, lua_CFunction func) { p->ravi_jit.jit_function = func; } static int load_and_compile(lua_State* L) { - const char* s = luaL_checkstring(L, 1); - struct CompilerContext ccontext = { .L = L }; - - LClosure* cl = luaF_newLclosure(L, 1); /* create main closure */ - setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */ - luaD_inctop(L); - ccontext.h = luaH_new(L); /* create table for string constants */ - sethvalue(L, L->top, ccontext.h); /* anchor it */ - luaD_inctop(L); - Proto *main_proto = cl->p = luaF_newproto(L); - luaC_objbarrier(L, cl, cl->p); - - struct Ravi_CompilerInterface ravicomp_interface = { - .source = s, - .source_len = strlen(s), - .source_name = "input", - .lua_newProto = lua_newProto, - .lua_newStringConstant = lua_newStringConstant, - .main_proto = main_proto, - .context = &ccontext - }; - - int rc = raviX_compile(&ravicomp_interface); - L->top--; /* remove table */ - - lua_assert(cl->nupvalues == cl->p->sizeupvalues); - luaF_initupvals(L, cl); - - + const char* s = luaL_checkstring(L, 1); + struct CompilerContext ccontext = {.L = L, .jit = G(L)->ravi_state}; + + LClosure* cl = luaF_newLclosure(L, 1); /* create main closure */ + setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */ + luaD_inctop(L); + ccontext.h = luaH_new(L); /* create table for string constants */ + sethvalue(L, L->top, ccontext.h); /* anchor it */ + luaD_inctop(L); + Proto* main_proto = cl->p = luaF_newproto(L); + luaC_objbarrier(L, cl, cl->p); + + struct Ravi_CompilerInterface ravicomp_interface = {.source = s, + .source_len = strlen(s), + .source_name = "input", + .main_proto = main_proto, + .context = &ccontext, + .lua_newProto = lua_newProto, + .lua_newStringConstant = lua_newStringConstant, + .init_C_compiler = init_C_compiler, + .compile_C = compile_C, + .finish_C_compiler = finish_C_compiler, + .get_compiled_function = get_compiled_function, + .lua_setProtoFunction = lua_setProtoFunction}; + + int rc = raviX_compile(&ravicomp_interface); + L->top--; /* remove table */ + + lua_assert(cl->nupvalues == cl->p->sizeupvalues); + luaF_initupvals(L, cl); } -static const luaL_Reg ravilib[] = { - {NULL, NULL} }; +static const luaL_Reg ravilib[] = {{NULL, NULL}}; -int (raviopen_compiler)(lua_State *L) { - luaL_newlib(L, ravilib); - return 1; +int(raviopen_compiler)(lua_State* L) { + luaL_newlib(L, ravilib); + return 1; } \ No newline at end of file From 0f698f354c2dfdcf75bf5575eddd1b914066672f Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Mon, 31 Aug 2020 01:48:34 +0100 Subject: [PATCH 05/15] issue #198 WIP add api for adding an upvalue. Hook up the compiler library. --- src/ravi_complib.c | 72 +++++++++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 20 deletions(-) diff --git a/src/ravi_complib.c b/src/ravi_complib.c index 8ef2c4f..f4b6c37 100644 --- a/src/ravi_complib.c +++ b/src/ravi_complib.c @@ -30,8 +30,10 @@ static Proto* lua_newProto(void* context, Proto* parent) { /* FIXME make this more efficient */ int old_size = parent->sizep; int new_size = parent->sizep + 1; - luaM_growvector(L, parent->p, old_size, new_size, Proto*, MAXARG_Bx, "functions"); - parent->p[parent->sizep++] = p; + luaM_reallocvector(L, parent->p, old_size, new_size, Proto*); + parent->p[old_size] = p; + parent->sizep++; + lua_assert(parent->sizep == new_size); luaC_objbarrier(L, parent, p); return p; } @@ -66,7 +68,7 @@ TString* create_newstring(lua_State* L, Table* h, const char* str, size_t l) { */ static int addk(lua_State* L, Proto* f, Table* h, TValue* key, TValue* v) { TValue* idx = luaH_set(L, h, key); /* index scanner table */ - int k, oldsize; + int k, oldsize, newsize; if (ttisinteger(idx)) { /* is there an index there? */ k = cast_int(ivalue(idx)); /* correct value? (warning: must distinguish floats from integers!) */ @@ -74,16 +76,15 @@ static int addk(lua_State* L, Proto* f, Table* h, TValue* key, TValue* v) { return k; /* reuse index */ } /* constant not found; create a new entry */ - oldsize = f->sizek; - k = f->sizek; + oldsize = k = f->sizek; + newsize = oldsize + 1; /* numerical value does not need GC barrier; table has no metatable, so it does not need to invalidate cache */ setivalue(idx, k); - luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); - while (oldsize < f->sizek) - setnilvalue(&f->k[oldsize++]); + luaM_reallocvector(L, f->k, oldsize, newsize, TValue); setobj(L, &f->k[k], v); f->sizek++; + lua_assert(f->sizek == newsize); luaC_barrier(L, f, v); return k; } @@ -97,30 +98,60 @@ static int lua_stringK(lua_State* L, Proto* p, Table* h, TString* s) { return addk(L, p, h, &o, &o); /* use string itself as key */ } +static inline TString* create_luaString(lua_State* L, Table* h, struct string_object* s) { + if (s->userdata == NULL) { + s->userdata = create_newstring(L, h, s->str, s->len); + } + return (TString*)s->userdata; +} + /* Add a string constant to Proto and return its index */ static int lua_newStringConstant(void* context, Proto* proto, struct string_object* s) { struct CompilerContext* ccontext = (struct CompilerContext*)context; lua_State* L = ccontext->L; Table* h = ccontext->h; - TString* ts = NULL; - if (s->userdata == NULL) { - ts = create_newstring(L, h, s->str, s->len); - s->userdata = ts; - } - else { - ts = (TString*)s->userdata; - } + TString* ts = create_luaString(L, h, s); return lua_stringK(L, proto, h, ts); } +/* Add an upvalue. If the upvalue refers to a local variable in parent proto then idx should contain + * the register for the local variable and instack should be true, else idx should have the index of + * upvalue in parent proto and instack should be false. + */ +static int add_upvalue(void* context, Proto* f, struct string_object* name, unsigned idx, int instack, unsigned tc, + struct string_object* usertype) { + ravitype_t typecode = (ravitype_t)tc; + struct CompilerContext* ccontext = (struct CompilerContext*)context; + lua_State* L = ccontext->L; + Table* h = ccontext->h; + int oldsize = f->sizeupvalues; + int newsize = oldsize + 1; + int pos = oldsize; + // checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues"); + // TODO optimize the allocation + luaM_reallocvector(L, f->upvalues, oldsize, newsize, Upvaldesc); + f->sizeupvalues++; + lua_assert(f->sizeupvalues == newsize); + f->upvalues[pos].instack = instack; /* is the upvalue in parent function's local stack ? */ + f->upvalues[pos].idx = cast_byte(idx); /* If instack then parent's local register else parent's upvalue index */ + TString* tsname = create_luaString(L, h, name); + f->upvalues[pos].name = tsname; + f->upvalues[pos].ravi_type = typecode; + if (usertype != NULL) { + int kpos = lua_newStringConstant(context, f, usertype); + f->upvalues[pos].usertype = tsvalue(&f->k[kpos]); + } + luaC_objbarrier(L, f, tsname); + return pos; +} + static void init_C_compiler(void* context) { struct CompilerContext* ccontext = (struct CompilerContext*)context; mir_prepare(ccontext->jit->jit, 2); } static void* compile_C(void* context, const char* C_src, unsigned len) { struct CompilerContext* ccontext = (struct CompilerContext*)context; - - return NULL; + return mir_compile_C_module(&ccontext->jit->options, ccontext->jit->jit, C_src, "input"); } static void finish_C_compiler(void* context) { struct CompilerContext* ccontext = (struct CompilerContext*)context; @@ -157,16 +188,17 @@ static int load_and_compile(lua_State* L) { .compile_C = compile_C, .finish_C_compiler = finish_C_compiler, .get_compiled_function = get_compiled_function, + .add_upvalue = add_upvalue, .lua_setProtoFunction = lua_setProtoFunction}; int rc = raviX_compile(&ravicomp_interface); L->top--; /* remove table */ - lua_assert(cl->nupvalues == cl->p->sizeupvalues); luaF_initupvals(L, cl); + return 1; } -static const luaL_Reg ravilib[] = {{NULL, NULL}}; +static const luaL_Reg ravilib[] = {{"load", load_and_compile}, {NULL, NULL}}; int(raviopen_compiler)(lua_State* L) { luaL_newlib(L, ravilib); From 90a26a4b88a55fb1ceff2c471298344d4383878d Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Mon, 31 Aug 2020 02:15:19 +0100 Subject: [PATCH 06/15] issue #198 WIP add api for marking a proto as var arg --- src/ravi_complib.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ravi_complib.c b/src/ravi_complib.c index f4b6c37..317780d 100644 --- a/src/ravi_complib.c +++ b/src/ravi_complib.c @@ -163,6 +163,7 @@ static lua_CFunction get_compiled_function(void* context, void* module, const ch return (lua_CFunction)mir_get_func(ccontext->jit->jit, M, name); } static void lua_setProtoFunction(void* context, Proto* p, lua_CFunction func) { p->ravi_jit.jit_function = func; } +static void lua_setVarArg(void *context, Proto *p) { p->is_vararg = 1; } static int load_and_compile(lua_State* L) { const char* s = luaL_checkstring(L, 1); @@ -189,6 +190,7 @@ static int load_and_compile(lua_State* L) { .finish_C_compiler = finish_C_compiler, .get_compiled_function = get_compiled_function, .add_upvalue = add_upvalue, + .lua_setVarArg = lua_setVarArg, .lua_setProtoFunction = lua_setProtoFunction}; int rc = raviX_compile(&ravicomp_interface); From fba87f24f196dedbe3d48a61f6112af18de14c4e Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Mon, 31 Aug 2020 17:28:53 +0100 Subject: [PATCH 07/15] issue #198 WIP add api for error reporting and generating debug messages --- src/ravi_complib.c | 91 +++++++++++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 29 deletions(-) diff --git a/src/ravi_complib.c b/src/ravi_complib.c index 317780d..895be11 100644 --- a/src/ravi_complib.c +++ b/src/ravi_complib.c @@ -21,6 +21,22 @@ struct CompilerContext { Table* h; /* to avoid collection/reuse strings */ }; +static void debug_message(void* context, const char* filename, long long line, const char* message) { + struct CompilerContext* ccontext = (struct CompilerContext*)context; + ravi_writestring(ccontext->L, filename, strlen(filename)); + char temp[80]; + snprintf(temp, sizeof temp, "%lld: ", line); + ravi_writestring(ccontext->L, temp, strlen(temp)); + ravi_writestring(ccontext->L, message, strlen(message)); + ravi_writeline(ccontext->L); +} + +void error_message(void* context, const char* message) { + struct CompilerContext* ccontext = (struct CompilerContext*)context; + ravi_writestring(ccontext->L, message, strlen(message)); + ravi_writeline(ccontext->L); +} + /* Create a new proto and insert it into parent's list of protos */ static Proto* lua_newProto(void* context, Proto* parent) { struct CompilerContext* ccontext = (struct CompilerContext*)context; @@ -39,9 +55,11 @@ static Proto* lua_newProto(void* context, Proto* parent) { } /* - * Based off the Lua lexer code. + * Based off the Lua lexer code. Strings are anchored in a table initially - eventually + * ending up either in a Proto constant table or some other structure related to + * protos. */ -TString* create_newstring(lua_State* L, Table* h, const char* str, size_t l) { +TString* intern_string(lua_State* L, Table* h, const char* str, size_t l) { TValue* o; /* entry for 'str' */ TString* ts = luaS_newlstr(L, str, l); /* create new string */ setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ @@ -61,28 +79,27 @@ TString* create_newstring(lua_State* L, Table* h, const char* str, size_t l) { /* ** Add constant 'v' to prototype's list of constants (field 'k'). -** Use scanner's table to cache position of constants in constant list -** and try to reuse constants. Because some values should not be used -** as keys (nil cannot be a key, integer keys can collapse with float -** keys), the caller must provide a useful 'key' for indexing the cache. +** Use parser's table to cache position of constants in constant list +** and try to reuse constants. */ -static int addk(lua_State* L, Proto* f, Table* h, TValue* key, TValue* v) { - TValue* idx = luaH_set(L, h, key); /* index scanner table */ +static int add_konstant(lua_State* L, Proto* f, Table* h, TValue* key, TValue* v) { + TValue* idx = luaH_set(L, h, key); /* The k index is cached against the key */ int k, oldsize, newsize; - if (ttisinteger(idx)) { /* is there an index there? */ + if (ttisinteger(idx)) { /* is there an integer value index there? */ k = cast_int(ivalue(idx)); /* correct value? (warning: must distinguish floats from integers!) */ - if (k < f->sizek && ttype(&f->k[k]) == ttype(v) && luaV_rawequalobj(&f->k[k], v)) + if (k >= 0 && k < f->sizek && ttype(&f->k[k]) == ttype(v) && luaV_rawequalobj(&f->k[k], v)) return k; /* reuse index */ } - /* constant not found; create a new entry */ + /* constant not found; create a new entry in Proto->k */ oldsize = k = f->sizek; newsize = oldsize + 1; /* numerical value does not need GC barrier; table has no metatable, so it does not need to invalidate cache */ setivalue(idx, k); + // FIXME make the allocation more efficient luaM_reallocvector(L, f->k, oldsize, newsize, TValue); - setobj(L, &f->k[k], v); + setobj(L, &f->k[k], v); /* record the position k in the table against key */ f->sizek++; lua_assert(f->sizek == newsize); luaC_barrier(L, f, v); @@ -92,15 +109,19 @@ static int addk(lua_State* L, Proto* f, Table* h, TValue* key, TValue* v) { /* ** Add a string to list of constants and return its index. */ -static int lua_stringK(lua_State* L, Proto* p, Table* h, TString* s) { +static int add_string_konstant(lua_State* L, Proto* p, Table* h, TString* s) { TValue o; setsvalue(L, &o, s); - return addk(L, p, h, &o, &o); /* use string itself as key */ + return add_konstant(L, p, h, &o, &o); /* use string itself as key */ } +/* Create a Lua TString object from a string. Save it so that we can avoid creating same + * string again. + */ static inline TString* create_luaString(lua_State* L, Table* h, struct string_object* s) { if (s->userdata == NULL) { - s->userdata = create_newstring(L, h, s->str, s->len); + /* Create and save it */ + s->userdata = intern_string(L, h, s->str, s->len); } return (TString*)s->userdata; } @@ -111,15 +132,15 @@ static int lua_newStringConstant(void* context, Proto* proto, struct string_obje lua_State* L = ccontext->L; Table* h = ccontext->h; TString* ts = create_luaString(L, h, s); - return lua_stringK(L, proto, h, ts); + return add_string_konstant(L, proto, h, ts); } /* Add an upvalue. If the upvalue refers to a local variable in parent proto then idx should contain * the register for the local variable and instack should be true, else idx should have the index of * upvalue in parent proto and instack should be false. */ -static int add_upvalue(void* context, Proto* f, struct string_object* name, unsigned idx, int instack, unsigned tc, - struct string_object* usertype) { +static int lua_addUpValue(void* context, Proto* f, struct string_object* name, unsigned idx, int instack, unsigned tc, + struct string_object* usertype) { ravitype_t typecode = (ravitype_t)tc; struct CompilerContext* ccontext = (struct CompilerContext*)context; lua_State* L = ccontext->L; @@ -128,16 +149,17 @@ static int add_upvalue(void* context, Proto* f, struct string_object* name, unsi int newsize = oldsize + 1; int pos = oldsize; // checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues"); - // TODO optimize the allocation + // FIXME optimize the allocation luaM_reallocvector(L, f->upvalues, oldsize, newsize, Upvaldesc); f->sizeupvalues++; lua_assert(f->sizeupvalues == newsize); - f->upvalues[pos].instack = instack; /* is the upvalue in parent function's local stack ? */ + f->upvalues[pos].instack = cast_byte(instack); /* is the upvalue in parent function's local stack ? */ f->upvalues[pos].idx = cast_byte(idx); /* If instack then parent's local register else parent's upvalue index */ - TString* tsname = create_luaString(L, h, name); + TString* tsname = create_luaString(L, h, name); /* name of the variable */ f->upvalues[pos].name = tsname; f->upvalues[pos].ravi_type = typecode; if (usertype != NULL) { + /* User type string goes into the proto's constant table */ int kpos = lua_newStringConstant(context, f, usertype); f->upvalues[pos].usertype = tsvalue(&f->k[kpos]); } @@ -151,6 +173,7 @@ static void init_C_compiler(void* context) { } static void* compile_C(void* context, const char* C_src, unsigned len) { struct CompilerContext* ccontext = (struct CompilerContext*)context; + fprintf(stdout, "%s\n", C_src); return mir_compile_C_module(&ccontext->jit->options, ccontext->jit->jit, C_src, "input"); } static void finish_C_compiler(void* context) { @@ -163,13 +186,15 @@ static lua_CFunction get_compiled_function(void* context, void* module, const ch return (lua_CFunction)mir_get_func(ccontext->jit->jit, M, name); } static void lua_setProtoFunction(void* context, Proto* p, lua_CFunction func) { p->ravi_jit.jit_function = func; } -static void lua_setVarArg(void *context, Proto *p) { p->is_vararg = 1; } +static void lua_setVarArg(void* context, Proto* p) { p->is_vararg = 1; } + + static int load_and_compile(lua_State* L) { const char* s = luaL_checkstring(L, 1); struct CompilerContext ccontext = {.L = L, .jit = G(L)->ravi_state}; - LClosure* cl = luaF_newLclosure(L, 1); /* create main closure */ + LClosure* cl = luaF_newLclosure(L, 1); /* create main closure with 1 up-value for _ENV */ setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */ luaD_inctop(L); ccontext.h = luaH_new(L); /* create table for string constants */ @@ -185,19 +210,27 @@ static int load_and_compile(lua_State* L) { .context = &ccontext, .lua_newProto = lua_newProto, .lua_newStringConstant = lua_newStringConstant, + .lua_addUpValue = lua_addUpValue, + .lua_setVarArg = lua_setVarArg, + .lua_setProtoFunction = lua_setProtoFunction, .init_C_compiler = init_C_compiler, .compile_C = compile_C, .finish_C_compiler = finish_C_compiler, .get_compiled_function = get_compiled_function, - .add_upvalue = add_upvalue, - .lua_setVarArg = lua_setVarArg, - .lua_setProtoFunction = lua_setProtoFunction}; + .debug_message = debug_message, + .error_message = error_message}; int rc = raviX_compile(&ravicomp_interface); L->top--; /* remove table */ - lua_assert(cl->nupvalues == cl->p->sizeupvalues); - luaF_initupvals(L, cl); - return 1; + if (rc == 0) { + lua_assert(cl->nupvalues == cl->p->sizeupvalues); + luaF_initupvals(L, cl); + return 1; + } + else { + lua_error(L); + return 0; + } } static const luaL_Reg ravilib[] = {{"load", load_and_compile}, {NULL, NULL}}; From 48617fda4450431236ea5eea49ff7fefb12f240e Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Mon, 31 Aug 2020 22:48:11 +0100 Subject: [PATCH 08/15] issue #198 WIP add api functions for setting some proto attributes --- src/ravi_complib.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/ravi_complib.c b/src/ravi_complib.c index 895be11..19ff103 100644 --- a/src/ravi_complib.c +++ b/src/ravi_complib.c @@ -185,10 +185,15 @@ static lua_CFunction get_compiled_function(void* context, void* module, const ch MIR_module_t M = (MIR_module_t)module; return (lua_CFunction)mir_get_func(ccontext->jit->jit, M, name); } -static void lua_setProtoFunction(void* context, Proto* p, lua_CFunction func) { p->ravi_jit.jit_function = func; } +static void lua_setProtoFunction(void* context, Proto* p, lua_CFunction func) { + p->ravi_jit.jit_function = func; + p->ravi_jit.jit_status = RAVI_JIT_COMPILED; +} static void lua_setVarArg(void* context, Proto* p) { p->is_vararg = 1; } - - +static void lua_setNumParams(void* context, Proto* p, unsigned num_params) { p->numparams = cast_byte(num_params); } +static void lua_setMaxStackSize(void *context, Proto *p, unsigned max_stack_size) { + p->maxstacksize = cast_byte(max_stack_size); +} static int load_and_compile(lua_State* L) { const char* s = luaL_checkstring(L, 1); @@ -213,6 +218,8 @@ static int load_and_compile(lua_State* L) { .lua_addUpValue = lua_addUpValue, .lua_setVarArg = lua_setVarArg, .lua_setProtoFunction = lua_setProtoFunction, + .lua_setNumParams = lua_setNumParams, + .lua_setMaxStackSize = lua_setMaxStackSize, .init_C_compiler = init_C_compiler, .compile_C = compile_C, .finish_C_compiler = finish_C_compiler, @@ -221,7 +228,7 @@ static int load_and_compile(lua_State* L) { .error_message = error_message}; int rc = raviX_compile(&ravicomp_interface); - L->top--; /* remove table */ + L->top--; /* remove table for string constants */ if (rc == 0) { lua_assert(cl->nupvalues == cl->p->sizeupvalues); luaF_initupvals(L, cl); From a45eaa8a24935b3c009e63aa56c4e5a7b41e6d5e Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sun, 6 Sep 2020 01:52:24 +0100 Subject: [PATCH 09/15] issue #198 Cmake build failing to find c2mir header --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 23ef2e4..f7b4a41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -147,6 +147,9 @@ if (RAVICOMP AND MIR_JIT) set_property(SOURCE ${RAVICOMP_SRCS} APPEND PROPERTY INCLUDE_DIRECTORIES ${RAVICOMP_INCLUDE_DIRS}) + set_property(SOURCE ${RAVICOMP_SRCS} + APPEND + PROPERTY INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/mir;${CMAKE_SOURCE_DIR}/mir/c2mir") if ($ENV{CLION_IDE}) # CLion seems unable to handle include paths set on sources include_directories(${RAVICOMP_INCLUDE_DIRS}) From 45f823b604a9b55b8fc2fb6618db58f5776f62d0 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sun, 6 Sep 2020 12:30:06 +0100 Subject: [PATCH 10/15] issue #198 Missing initializer for proto->upvalues[i].usertype when usertype is NULL --- src/ravi_complib.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ravi_complib.c b/src/ravi_complib.c index 19ff103..cbc92de 100644 --- a/src/ravi_complib.c +++ b/src/ravi_complib.c @@ -163,6 +163,9 @@ static int lua_addUpValue(void* context, Proto* f, struct string_object* name, u int kpos = lua_newStringConstant(context, f, usertype); f->upvalues[pos].usertype = tsvalue(&f->k[kpos]); } + else { + f->upvalues[pos].usertype = NULL; + } luaC_objbarrier(L, f, tsname); return pos; } From d65beddb75a51fdbae6226a915af31300f1b4b79 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sun, 6 Sep 2020 12:30:25 +0100 Subject: [PATCH 11/15] issue #198 Test case for op_ret --- tests/comptests/00_ret.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tests/comptests/00_ret.lua diff --git a/tests/comptests/00_ret.lua b/tests/comptests/00_ret.lua new file mode 100644 index 0000000..db8307f --- /dev/null +++ b/tests/comptests/00_ret.lua @@ -0,0 +1,10 @@ +f = compiler.load("return 1, 'hello', 5.6, true") +assert(f and type(f) == 'function') +local x = 4.3 +local a,b,c,d,e = f() +assert(a == 1) +assert(b == 'hello') +assert(c == 5.6) +assert(d == true) +assert(x == 4.3) +assert(e == nil) From 4f7cab694c134e2ea8e52e487c959e476be6b413 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sun, 6 Sep 2020 16:53:21 +0100 Subject: [PATCH 12/15] issue #198 Test case for op_mov --- tests/comptests/01_mov.lua | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/comptests/01_mov.lua diff --git a/tests/comptests/01_mov.lua b/tests/comptests/01_mov.lua new file mode 100644 index 0000000..3603d4f --- /dev/null +++ b/tests/comptests/01_mov.lua @@ -0,0 +1,7 @@ +f = compiler.load("local a, b, c = 4.2, true, 'hi' return a, b, c") +local z = 62 +local a,b,c,d = f() +assert(z == 62) +assert(a == 4.2) +assert(b == true) +assert(c == 'hi') \ No newline at end of file From 4819f38a803425364953a32fa6f77c19c91c461f Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sun, 6 Sep 2020 17:46:53 +0100 Subject: [PATCH 13/15] issue #198 Test cases for op_mov, op_br, op_cbr --- tests/comptests/01_mov.lua | 1 + tests/comptests/02_cbr_br.lua | 3 +++ tests/comptests/03_cbr_br.lua | 3 +++ tests/comptests/04_cbr_br.lua | 3 +++ tests/comptests/05_cbr_br.lua | 3 +++ 5 files changed, 13 insertions(+) create mode 100644 tests/comptests/02_cbr_br.lua create mode 100644 tests/comptests/03_cbr_br.lua create mode 100644 tests/comptests/04_cbr_br.lua create mode 100644 tests/comptests/05_cbr_br.lua diff --git a/tests/comptests/01_mov.lua b/tests/comptests/01_mov.lua index 3603d4f..1008f5c 100644 --- a/tests/comptests/01_mov.lua +++ b/tests/comptests/01_mov.lua @@ -1,4 +1,5 @@ f = compiler.load("local a, b, c = 4.2, true, 'hi' return a, b, c") +assert(f and type(f) == 'function') local z = 62 local a,b,c,d = f() assert(z == 62) diff --git a/tests/comptests/02_cbr_br.lua b/tests/comptests/02_cbr_br.lua new file mode 100644 index 0000000..93fee49 --- /dev/null +++ b/tests/comptests/02_cbr_br.lua @@ -0,0 +1,3 @@ +f = compiler.load("local a,b = 1,2 return a or b"); +assert(f and type(f) == 'function') +assert(f() == 1) \ No newline at end of file diff --git a/tests/comptests/03_cbr_br.lua b/tests/comptests/03_cbr_br.lua new file mode 100644 index 0000000..10085e2 --- /dev/null +++ b/tests/comptests/03_cbr_br.lua @@ -0,0 +1,3 @@ +f = compiler.load("local a,b = 1,2 return a and b"); +assert(f and type(f) == 'function') +assert(f() == 2) \ No newline at end of file diff --git a/tests/comptests/04_cbr_br.lua b/tests/comptests/04_cbr_br.lua new file mode 100644 index 0000000..59fbb13 --- /dev/null +++ b/tests/comptests/04_cbr_br.lua @@ -0,0 +1,3 @@ +f = compiler.load("local a = 2 return 1 or a"); +assert(f and type(f) == 'function') +assert(f() == 1) \ No newline at end of file diff --git a/tests/comptests/05_cbr_br.lua b/tests/comptests/05_cbr_br.lua new file mode 100644 index 0000000..e237500 --- /dev/null +++ b/tests/comptests/05_cbr_br.lua @@ -0,0 +1,3 @@ +f = compiler.load("local a = 2 return 1 and a"); +assert(f and type(f) == 'function') +assert(f() == 2) \ No newline at end of file From 6daf1a5529b39ac422c752aa6c36b9b4fa93a2d3 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sun, 13 Sep 2020 12:58:53 +0100 Subject: [PATCH 14/15] Add link to the VSCode debugger --- README.rst | 3 ++- readthedocs/ravi-overview.rst | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index d2957b6..39c1681 100644 --- a/README.rst +++ b/README.rst @@ -38,6 +38,7 @@ Features * Compact JIT backend `MIR `_; only Linux and x86-64 supported for now. * `LLVM `_ supported as alternative JIT backend. * A `distribution with batteries `_. +* A `Visual Studio Code debugger extension `_ - interpreted mode debugger. Documentation ============= @@ -73,7 +74,7 @@ Compatibility with Lua 5.3 ========================== Ravi should be able to run all Lua 5.3 programs in interpreted mode, but following should be noted: -* Ravi supports optional typing and enhanced types such as arrays (described above). Programs using these features cannot be run by standard Lua. However all types in Ravi can be passed to Lua functions; operations on Ravi arrays within Lua code will be subject to restrictions as described in the section above on arrays. +* Ravi supports optional typing and enhanced types such as arrays (see the documentation). Programs using these features cannot be run by standard Lua. However all types in Ravi can be passed to Lua functions; operations on Ravi arrays within Lua code will be subject to restrictions as described in the section above on arrays. * Values crossing from Lua to Ravi will be subjected to typechecks should these values be assigned to typed variables. * Upvalues cannot subvert the static typing of local variables (issue #26) when types are annotated. * Certain Lua limits are reduced due to changed byte code structure. These are described below. diff --git a/readthedocs/ravi-overview.rst b/readthedocs/ravi-overview.rst index b786e72..39c1681 100644 --- a/readthedocs/ravi-overview.rst +++ b/readthedocs/ravi-overview.rst @@ -38,6 +38,7 @@ Features * Compact JIT backend `MIR `_; only Linux and x86-64 supported for now. * `LLVM `_ supported as alternative JIT backend. * A `distribution with batteries `_. +* A `Visual Studio Code debugger extension `_ - interpreted mode debugger. Documentation ============= @@ -73,7 +74,7 @@ Compatibility with Lua 5.3 ========================== Ravi should be able to run all Lua 5.3 programs in interpreted mode, but following should be noted: -* Ravi supports optional typing and enhanced types such as arrays (described above). Programs using these features cannot be run by standard Lua. However all types in Ravi can be passed to Lua functions; operations on Ravi arrays within Lua code will be subject to restrictions as described in the section above on arrays. +* Ravi supports optional typing and enhanced types such as arrays (see the documentation). Programs using these features cannot be run by standard Lua. However all types in Ravi can be passed to Lua functions; operations on Ravi arrays within Lua code will be subject to restrictions as described in the section above on arrays. * Values crossing from Lua to Ravi will be subjected to typechecks should these values be assigned to typed variables. * Upvalues cannot subvert the static typing of local variables (issue #26) when types are annotated. * Certain Lua limits are reduced due to changed byte code structure. These are described below. @@ -103,14 +104,14 @@ History ======= * 2015 - Implemented JIT compilation using LLVM - - Implemented libgccjit based alternative JIT (now discontinued) + - Implemented `libgccjit based alternative JIT `_ (now discontinued) * 2016 - Implemented debugger for Ravi and Lua 5.3 for `Visual Studio Code `_ * 2017 - Embedded C compiler using dmrC project (C JIT compiler) (now discontinued) - Additional type-annotations * 2018 - - Implemented Eclipse OMR JIT backend (now discontinued) + - Implemented `Eclipse OMR JIT backend `_ (now discontinued) - Created `Ravi with batteries `_. * 2019 - New language feature - `defer` statement From 6b273f746835e46614f75d2cb6b3ddd88668feb1 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 3 Oct 2020 23:32:52 +0100 Subject: [PATCH 15/15] issue #198 Make the MIR portion of the compiler optional so that we can just get the C codegen --- CMakeLists.txt | 28 +++++++++++++++------------- src/ravi_complib.c | 12 ++++++++++++ 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f7b4a41..24c008c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ option(STATIC_BUILD "Build static version of Ravi, default is OFF" OFF) option(COMPUTED_GOTO "Controls whether the interpreter switch will use computed gotos on gcc/clang, default is ON" ON) option(LTESTS "Controls whether ltests are enabled in Debug mode; note requires Debug build" ON) option(ASAN "Controls whether address sanitizer should be enabled" OFF) -option(RAVICOMP "Controls whether to link in RaviComp" ON) +option(RAVICOMP "Controls whether to link in RaviComp" OFF) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") @@ -83,15 +83,15 @@ endif () include(CheckCCompilerFlag) check_c_compiler_flag("-march=native" COMPILER_OPT_ARCH_NATIVE_SUPPORTED) if (COMPILER_OPT_ARCH_NATIVE_SUPPORTED AND NOT CMAKE_C_FLAGS MATCHES "-march=") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native") -endif() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native") +endif () if (ASAN) set(CMAKE_REQUIRED_FLAGS "-fsanitize=address") check_c_compiler_flag("-fsanitize=address" COMPILER_ASAN_SUPPORTED) if (COMPILER_ASAN_SUPPORTED AND NOT CMAKE_C_FLAGS_DEBUG MATCHES "-fsanitize=address") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fsanitize=address") - endif() -endif() + endif () +endif () if (LLVM_JIT) find_package(LLVM REQUIRED CONFIG) @@ -135,26 +135,28 @@ else () # CLion seems unable to handle include paths set on sources include_directories("${CMAKE_SOURCE_DIR}/mir;${CMAKE_SOURCE_DIR}/mir/c2mir") endif () - else() + else () set(JIT_SRCS ${NO_JIT_SRCS}) endif () endif () -if (RAVICOMP AND MIR_JIT) +if (RAVICOMP) # Need MIR_JIT for the compiler add-on find_package(RaviComp REQUIRED) set(ADDON_SRCS ${RAVICOMP_SRCS}) - set_property(SOURCE ${RAVICOMP_SRCS} - APPEND - PROPERTY INCLUDE_DIRECTORIES ${RAVICOMP_INCLUDE_DIRS}) set_property(SOURCE ${RAVICOMP_SRCS} APPEND - PROPERTY INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/mir;${CMAKE_SOURCE_DIR}/mir/c2mir") + PROPERTY INCLUDE_DIRECTORIES ${RAVICOMP_INCLUDE_DIRS}) + if (MIR_JIT) + set_property(SOURCE ${RAVICOMP_SRCS} + APPEND + PROPERTY INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/mir;${CMAKE_SOURCE_DIR}/mir/c2mir") + endif () if ($ENV{CLION_IDE}) # CLion seems unable to handle include paths set on sources include_directories(${RAVICOMP_INCLUDE_DIRS}) endif () -endif() +endif () # IDE stuff if (MSVC OR APPLE) @@ -310,7 +312,7 @@ if (RAVICOMP) APPEND PROPERTY COMPILE_DEFINITIONS "USE_RAVICOMP=1") set(USE_RAVICOMP 1) -endif() +endif () if (APPLE) set_property( TARGET ${LIBRAVI_NAME} libravinojit_static diff --git a/src/ravi_complib.c b/src/ravi_complib.c index cbc92de..d245245 100644 --- a/src/ravi_complib.c +++ b/src/ravi_complib.c @@ -172,21 +172,33 @@ static int lua_addUpValue(void* context, Proto* f, struct string_object* name, u static void init_C_compiler(void* context) { struct CompilerContext* ccontext = (struct CompilerContext*)context; +#ifdef USE_MIRJIT mir_prepare(ccontext->jit->jit, 2); +#endif } static void* compile_C(void* context, const char* C_src, unsigned len) { struct CompilerContext* ccontext = (struct CompilerContext*)context; fprintf(stdout, "%s\n", C_src); +#ifdef USE_MIRJIT return mir_compile_C_module(&ccontext->jit->options, ccontext->jit->jit, C_src, "input"); +#else + return NULL; +#endif } static void finish_C_compiler(void* context) { struct CompilerContext* ccontext = (struct CompilerContext*)context; +#ifdef USE_MIRJIT mir_cleanup(ccontext->jit->jit); +#endif } static lua_CFunction get_compiled_function(void* context, void* module, const char* name) { struct CompilerContext* ccontext = (struct CompilerContext*)context; +#if USE_MIRJIT MIR_module_t M = (MIR_module_t)module; return (lua_CFunction)mir_get_func(ccontext->jit->jit, M, name); +#else + return NULL; +#endif } static void lua_setProtoFunction(void* context, Proto* p, lua_CFunction func) { p->ravi_jit.jit_function = func;