diff --git a/CMakeLists.txt b/CMakeLists.txt index 97497b0d..80222cd4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,21 +12,27 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") # By default JIT is OFF option(LLVM_JIT "Controls whether LLVM JIT compilation will be enabled, default is OFF" OFF) option(OMR_JIT "Controls whether NanoJIT compilation will be enabled, default is OFF" OFF) +option(MIR_JIT "Controls whether MIR JIT compilation will be enabled, default is OFF" ON) 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(ASM_VM "Controls whether to use the new VM (not ready yet! so don't turn on)" OFF) option(LTESTS "Controls whether ltests are enabled in Debug mode" ON) -if (LLVM_JIT AND OMR_JIT) +if (LLVM_JIT AND OMR_JIT AND MIR_JIT) message(FATAL_ERROR - "Both LLVM_JIT and OMR_JIT cannot be set to ON at the same time") + "LLVM_JIT, OMR_JIT and MIR_IT cannot all be set to ON at the same time") endif () -if (LLVM_JIT OR OMR_JIT) +if (LLVM_JIT OR OMR_JIT OR MIR_JIT) # ASM VM is in development and not compatible with anything yet set(ASM_VM OFF) endif () +if (MIR_JIT) + set(LLVM_JIT OFF) + set(OMR_JIT OFF) +endif() + if (ASM_VM) # For now we switch to static build # TODO A fix is needed to ensure that in shared library the asm functions are resolved @@ -35,6 +41,7 @@ if (ASM_VM) set(LTESTS OFF) set(LLVM_JIT OFF) set(OMR_JIT OFF) + set(MIR_JIT OFF) endif () if (STATIC_BUILD) @@ -63,6 +70,12 @@ if (OMR_JIT) add_definitions(-DUSE_OMRJIT) endif () +if (MIR_JIT) + find_package(MIRJIT REQUIRED) + include_directories(${MIRJIT_INCLUDE_DIRS}) + add_definitions(-DUSE_MIRJIT) +endif () + message(STATUS "Computed goto ${COMPUTED_GOTO}") if (COMPUTED_GOTO AND MSVC) message(WARNING "Computed goto is not available with MSVC") @@ -187,6 +200,8 @@ if (LLVM_JIT) src/ravi_llvmluaapi.cpp) elseif (OMR_JIT) set(OMR_JIT_SRCS src/ravi_omrjit.c src/ravi_omrjitapi.c) +elseif (MIR_JIT) + set(MIR_JIT_SRCS src/ravi_mirjit.c) else () set(NO_JIT_SRCS src/ravi_nojit.c) endif () @@ -371,6 +386,9 @@ if (LLVM_JIT) set(LIBRAVI_NAME libravillvm) elseif (OMR_JIT) set(LIBRAVI_NAME libravilomr) +elseif (MIR_JIT) + set(LIBRAVI_NAME libravimir) + set(LIBRAVI_BUILD_TYPE STATIC) else () set(LIBRAVI_NAME libravinojit) endif () @@ -382,6 +400,7 @@ add_library(${LIBRAVI_NAME} ${LIBRAVI_BUILD_TYPE} ${LUA_CORE_SRCS} ${LLVM_JIT_SRCS} ${OMR_JIT_SRCS} + ${MIR_JIT_SRCS} ${NO_JIT_SRCS} ${DMR_C_HEADERS} ${DMR_C_SRCS} @@ -404,10 +423,13 @@ endif () if (OMR_JIT) set_target_properties(${LIBRAVI_NAME} PROPERTIES COMPILE_DEFINITIONS "USE_OMRJIT=1") endif () +if (MIR_JIT) + set_target_properties(${LIBRAVI_NAME} PROPERTIES COMPILE_DEFINITIONS "USE_MIRJIT=1") +endif () if (EMBEDDED_DMRC) set_target_properties(${LIBRAVI_NAME} PROPERTIES COMPILE_DEFINITIONS "USE_DMR_C=1") endif () -target_link_libraries(${LIBRAVI_NAME} ${EXTRA_LIBRARIES} ${LLVM_LIBS} ${OMRJIT_LIBRARIES}) +target_link_libraries(${LIBRAVI_NAME} ${EXTRA_LIBRARIES} ${LLVM_LIBS} ${OMRJIT_LIBRARIES} ${MIRJIT_LIBRARIES}) # Main Ravi executable add_executable(ravi src/lua.c) diff --git a/cmake/FindMIRJIT.cmake b/cmake/FindMIRJIT.cmake new file mode 100644 index 00000000..b44ee17c --- /dev/null +++ b/cmake/FindMIRJIT.cmake @@ -0,0 +1,16 @@ +find_path(MIRJIT_INCLUDE_DIR c2mir.h + PATHS + c:/Software/mir/include/mir + ~/Software/mir/include/mir + NO_DEFAULT_PATH +) + +find_library(MIRJIT_LIBRARY + NAMES libc2mir.a + PATHS + c:/Software/mir/lib + ~/Software/mir/lib +) + +set( MIRJIT_INCLUDE_DIRS "${MIRJIT_INCLUDE_DIR}" ) +set( MIRJIT_LIBRARIES "${MIRJIT_LIBRARY}" ) diff --git a/include/ravi_mirjit.h b/include/ravi_mirjit.h new file mode 100644 index 00000000..c500b06f --- /dev/null +++ b/include/ravi_mirjit.h @@ -0,0 +1,73 @@ +/****************************************************************************** +* Copyright (C) 2015-2017 Dibyendu Majumdar +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +******************************************************************************/ +/****************************************************************************** +* Copyright (C) 2015-2018 Dibyendu Majumdar +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +******************************************************************************/ +#ifndef RAVI_OMRJIT_H +#define RAVI_OMRJIT_H + +#include + +#ifdef USE_MIRJIT +#include "c2mir.h" + +struct ravi_State { + void *jit; + unsigned long long id; // counter to generate function names + unsigned int verbosity_ : 3; + unsigned int auto_ : 1; /* Should we auto compile what we can? */ + unsigned int enabled_ : 1; /* is JIT enabled */ + unsigned int opt_level_ : 3; /* optimization level */ + unsigned int tracehook_enabled_ : 1; /* enable calls to luaG_traceexec() at every bytecode, this is expensive ! */ + unsigned int validation_ : 1; /* Enable extra validation such as IL verification */ + unsigned int compiling_; /* flag to help avoid recursion */ + int min_code_size_; /* min code size for compilation */ + int min_exec_count_; /* min execution count for compilation */ +}; + +#ifdef __cplusplus +}; +#endif + +#endif /* USE_MIRJIT */ + +#endif /* RAVI_MIRJIT_H */ diff --git a/src/ravi_jitshared.c b/src/ravi_jitshared.c index e9507d66..566d2b3c 100644 --- a/src/ravi_jitshared.c +++ b/src/ravi_jitshared.c @@ -34,7 +34,11 @@ */ static const char Lua_header[] = "" -"typedef __SIZE_TYPE__ size_t;\n" +//"#ifndef __SIZE_TYPE__\n" +//"#define __SIZE_TYPE__ long long\n" +//"#endif\n" +//"typedef __SIZE_TYPE__ size_t;\n" +"typedef long long size_t;\n" "typedef long long ptrdiff_t;\n" "typedef long long intptr_t;\n" "typedef long long int64_t;\n" diff --git a/src/ravi_mirjit.c b/src/ravi_mirjit.c new file mode 100644 index 00000000..ec474cf1 --- /dev/null +++ b/src/ravi_mirjit.c @@ -0,0 +1,435 @@ +/****************************************************************************** + * Copyright (C) 2018 Dibyendu Majumdar + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ******************************************************************************/ + +#include +#include +#include +#include + +#define LUA_CORE + +#include "lauxlib.h" +#include "lobject.h" +#include "lstate.h" +#include "lua.h" + +static const char *errortext[] = {"integer expected", + "number expected", + "integer[] expected", + "number[] expected", + "table expected", + "upvalue of integer type, cannot be set to non integer value", + "upvalue of number type, cannot be set to non number value", + "upvalue of integer[] type, cannot be set to non integer[] value", + "upvalue of number[] type, cannot be set to non number[] value", + "upvalue of table type, cannot be set to non table value", + "for llimit must be a number", + "for step must be a number", + "for initial value must be a number", + "array index is out of bounds", + "string expected", + "closure expected", + "type mismatch: wrong userdata type", + NULL}; + +static void raise_error(lua_State *L, int errorcode) { + assert(errorcode >= 0 && errorcode <= Error_type_mismatch); + luaG_runerror(L, errortext[errorcode]); +} + +#if !RAVI_TARGET_X64 +#error OMRJIT is currently only supported on X64 architecture +#endif + +typedef struct LuaFunc { + const char *name; + void *ptr; +} LuaFunc; + +static LuaFunc Lua_functions[] = { + { "luaF_close", luaF_close }, + { "raise_error", raise_error }, + { "luaV_tonumber_", luaV_tonumber_ }, + { "luaV_tointeger", luaV_tointeger }, + { "luaD_poscall", luaD_poscall }, + { "luaV_equalobj", luaV_equalobj }, + { "luaV_lessthan", luaV_lessthan }, + { "luaV_lessequal", luaV_lessequal }, + { "luaV_execute", luaV_execute }, + { "luaV_gettable", luaV_gettable }, + { "luaV_settable", luaV_settable }, + { "luaD_precall", luaD_precall }, + { "raviV_op_newtable", raviV_op_newtable }, + { "luaO_arith", luaO_arith }, + { "raviV_op_newarrayint", raviV_op_newarrayint }, + { "raviV_op_newarrayfloat", raviV_op_newarrayfloat }, + { "raviV_op_setlist", raviV_op_setlist }, + { "raviV_op_concat", raviV_op_concat }, + { "raviV_op_closure", raviV_op_closure }, + { "raviV_op_vararg", raviV_op_vararg }, + { "luaV_objlen", luaV_objlen }, + { "luaV_forlimit", luaV_forlimit }, + { "raviV_op_setupval", raviV_op_setupval }, + { "raviV_op_setupvali", raviV_op_setupvali }, + { "raviV_op_setupvalf", raviV_op_setupvalf }, + { "raviV_op_setupvalai", raviV_op_setupvalai }, + { "raviV_op_setupvalaf", raviV_op_setupvalaf }, + { "raviV_op_setupvalt", raviV_op_setupvalt }, + { "luaD_call", luaD_call }, + { "raviH_set_int", raviH_set_int }, + { "raviH_set_float", raviH_set_float }, + { "raviV_check_usertype", raviV_check_usertype }, + { "luaT_trybinTM", luaT_trybinTM }, + { "raviV_gettable_sskey", raviV_gettable_sskey }, + { "raviV_settable_sskey", raviV_settable_sskey }, + { "raviV_gettable_i", raviV_gettable_i }, + { "raviV_settable_i", raviV_settable_i }, + + { "lua_absindex", lua_absindex }, + { "lua_gettop", lua_gettop }, + { "lua_pushvalue", lua_pushvalue }, + + { "lua_isnumber", lua_isnumber }, + { "lua_isstring", lua_isstring }, + { "lua_iscfunction", lua_iscfunction }, + { "lua_isinteger", lua_isinteger }, + { "lua_isuserdata", lua_isuserdata }, + { "lua_type", lua_type }, + { "lua_typename", (void*)lua_typename }, + { "ravi_typename", (void*)ravi_typename }, + + { "lua_tonumberx", lua_tonumberx }, + { "lua_tointegerx", lua_tointegerx }, + { "lua_toboolean", lua_toboolean }, + { "lua_tolstring", (void*)lua_tolstring }, + { "lua_rawlen", lua_rawlen }, + { "lua_tocfunction", lua_tocfunction }, + { "lua_touserdata", lua_touserdata }, + { "lua_tothread", lua_tothread }, + { "lua_topointer", (void *)lua_topointer }, + + { "lua_arith", lua_arith }, + { "lua_rawequal", lua_rawequal }, + { "lua_compare", lua_compare }, + { "lua_pushnil", lua_pushnil }, + + { "lua_pushnumber", lua_pushnumber }, + { "lua_pushinteger", lua_pushinteger }, + { "lua_pushlstring", (void*)lua_pushlstring }, + { "lua_pushstring", (void*)lua_pushstring }, + { "lua_pushcclosure", lua_pushcclosure }, + { "lua_pushboolean", lua_pushboolean }, + { "lua_pushlightuserdata", lua_pushlightuserdata }, + { "lua_pushthread", lua_pushthread }, + + { "lua_getglobal", lua_getglobal }, + { "lua_gettable", lua_gettable }, + { "lua_getfield", lua_getfield }, + { "lua_geti", lua_geti }, + { "lua_rawget", lua_rawget }, + { "lua_rawgeti", lua_rawgeti }, + { "lua_rawgetp", lua_rawgetp }, + { "lua_createtable", lua_createtable }, + { "lua_newuserdata", lua_newuserdata }, + { "lua_getmetatable", lua_getmetatable }, + { "lua_getuservalue", lua_getuservalue }, + { "lua_setglobal", lua_setglobal }, + { "lua_settable", lua_settable }, + { "lua_setfield", lua_setfield }, + { "lua_seti", lua_seti }, + { "lua_rawset", lua_rawset }, + { "lua_rawseti", lua_rawseti }, + { "lua_rawsetp", lua_rawsetp }, + { "lua_setmetatable", lua_setmetatable }, + { "lua_setuservalue", lua_setuservalue }, + { NULL, NULL } +}; + +int dummyCtx = 0; + +// Initialize the JIT State and attach it to the +// Global Lua State +// If a JIT State already exists then this function +// will return -1 +int raviV_initjit(struct lua_State *L) { + global_State *G = G(L); + if (G->ravi_state != NULL) return -1; + ravi_State *jit = (ravi_State *)calloc(1, sizeof(ravi_State)); + jit->auto_ = 0; + jit->enabled_ = 1; + jit->min_code_size_ = 150; + jit->min_exec_count_ = 50; + jit->opt_level_ = 1; + // The parameter true means we will be dumping stuff as we compile + jit->jit = &dummyCtx; + // TODO create context + G->ravi_state = jit; + return 0; +} + +// Free up the JIT State +void raviV_close(struct lua_State *L) { + global_State *G = G(L); + if (G->ravi_state == NULL) return; + // All compiled functions will be deleted at this stage + // TODO destroy G->ravi_state->jit + free(G->ravi_state); +} + +// Dump the intermediate C code +void raviV_dumpIR(struct lua_State *L, struct Proto *p) { + global_State *G = G(L); + if (G->ravi_state == NULL) + return; + + membuff_t buf; + membuff_init(&buf, 4096); + + char fname[30]; + snprintf(fname, sizeof fname, "%s", "jit_function"); + ravi_compile_options_t options; + memset(&options, 0, sizeof options); + options.codegen_type = RAVI_CODEGEN_ALL; + if (raviJ_codegen(L, p, &options, fname, &buf)) { + ravi_writestring(L, buf.buf, strlen(buf.buf)); + ravi_writeline(L); + } + membuff_free(&buf); +} + +// Dump the LLVM ASM +void raviV_dumpASM(struct lua_State *L, struct Proto *p) { + (void)L; + (void)p; +} + +void raviV_setminexeccount(lua_State *L, int value) { + global_State *G = G(L); + if (!G->ravi_state) return; + G->ravi_state->min_exec_count_ = value; +} +int raviV_getminexeccount(lua_State *L) { + global_State *G = G(L); + if (!G->ravi_state) return 0; + return G->ravi_state->min_exec_count_; +} + +void raviV_setmincodesize(lua_State *L, int value) { + global_State *G = G(L); + if (!G->ravi_state) return; + G->ravi_state->min_code_size_ = value; +} +int raviV_getmincodesize(lua_State *L) { + global_State *G = G(L); + if (!G->ravi_state) return 0; + return G->ravi_state->min_code_size_; +} + +void raviV_setauto(lua_State *L, int value) { + global_State *G = G(L); + if (!G->ravi_state) return; + G->ravi_state->auto_ = value; +} +int raviV_getauto(lua_State *L) { + global_State *G = G(L); + if (!G->ravi_state) return 0; + return G->ravi_state->auto_; +} + +// Turn on/off the JIT compiler +void raviV_setjitenabled(lua_State *L, int value) { + global_State *G = G(L); + if (!G->ravi_state) return; + G->ravi_state->enabled_ = value; +} +int raviV_getjitenabled(lua_State *L) { + global_State *G = G(L); + if (!G->ravi_state) return 0; + return G->ravi_state->enabled_; +} + +void raviV_setoptlevel(lua_State *L, int value) { + global_State *G = G(L); + if (!G->ravi_state) return; + G->ravi_state->opt_level_ = value; +} +int raviV_getoptlevel(lua_State *L) { + global_State *G = G(L); + if (!G->ravi_state) return 0; + return G->ravi_state->opt_level_; +} + +void raviV_setsizelevel(lua_State *L, int value) { + (void)L; + (void)value; +} +int raviV_getsizelevel(lua_State *L) { + (void)L; + return 0; +} + +void raviV_setvalidation(lua_State *L, int value) { + global_State *G = G(L); + if (!G->ravi_state) return; + G->ravi_state->validation_ = value; +} +int raviV_getvalidation(lua_State *L) { + global_State *G = G(L); + if (!G->ravi_state) return 0; + return G->ravi_state->validation_; +} + +void raviV_setverbosity(lua_State *L, int value) { + global_State *G = G(L); + if (!G->ravi_state) return; + G->ravi_state->verbosity_ = value; +} +int raviV_getverbosity(lua_State *L) { + global_State *G = G(L); + if (!G->ravi_state) return 0; + return G->ravi_state->verbosity_; +} + +void raviV_setgcstep(lua_State *L, int value) { + (void)L; + (void)value; +} +int raviV_getgcstep(lua_State *L) { + (void)L; + return 0; +} + +// Turn on/off the JIT compiler +void raviV_settraceenabled(lua_State *L, int value) { + (void)L; + (void)value; +} +int raviV_gettraceenabled(lua_State *L) { + (void)L; + return 0; +} + +int raviV_compile_n(struct lua_State *L, struct Proto *p[], int n, + ravi_compile_options_t *options) { + int count = 0; + for (int i = 0; i < n; i++) { + if (raviV_compile(L, p[i], options)) count++; + } + return count > 0; +} + +static void* import_resolver(const char *name) { + for (int i = 0; Lua_functions[i].name != NULL; i++) { + if (strcmp(name, Lua_functions[i].name) == 0) + return Lua_functions[i].ptr; + } + return NULL; +} + +// Compile a Lua function +// If JIT is turned off then compilation is skipped +// Compilation occurs if either auto compilation is ON (subject to some +// thresholds) +// or if a manual compilation request was made +// Returns true if compilation was successful +int raviV_compile(struct lua_State *L, struct Proto *p, ravi_compile_options_t *options) { + if (p->ravi_jit.jit_status == RAVI_JIT_COMPILED) + return true; + else if (p->ravi_jit.jit_status == RAVI_JIT_CANT_COMPILE) + return false; + if (options == NULL) return false; + + global_State *G = G(L); + if (G->ravi_state == NULL) return false; + + bool doCompile = (bool)(options && options->manual_request != 0); + if (!doCompile && G->ravi_state->auto_) { + if (p->ravi_jit.jit_flags == RAVI_JIT_FLAG_HASFORLOOP) /* function has fornum loop, so compile */ + doCompile = true; + else if (p->sizecode > G->ravi_state->min_code_size_) /* function is long so compile */ + doCompile = true; + else { + if (p->ravi_jit.execution_count < G->ravi_state->min_exec_count_) /* function has been executed many + times so compile */ + p->ravi_jit.execution_count++; + else + doCompile = true; + } + } + if (!doCompile) { return false; } + if (!raviJ_cancompile(p)) { + p->ravi_jit.jit_status = RAVI_JIT_CANT_COMPILE; + return false; + } + + if (G->ravi_state->compiling_) return false; + G->ravi_state->compiling_ = 1; + + membuff_t buf; + membuff_init(&buf, 4096); + + int (*fp)(lua_State * L) = NULL; + char fname[30]; + snprintf(fname, sizeof fname, "jit%lld", G->ravi_state->id++); + char *argv[] = { fname, "-O1", NULL }; + + if (!raviJ_codegen(L, p, options, fname, &buf)) { + p->ravi_jit.jit_status = RAVI_JIT_CANT_COMPILE; + goto Lerror; + } + if (options->manual_request && G->ravi_state->verbosity_) { + ravi_writestring(L, buf.buf, strlen(buf.buf)); + ravi_writeline(L); + } + int opt_level = G->ravi_state->opt_level_; + if (opt_level == 0) + argv[1] = "-O0"; + else if (opt_level >= 2) + argv[1] = "-O2"; + fp = MIR_compile_C_module(buf.buf, fname, import_resolver); + + if (!fp) { + p->ravi_jit.jit_status = RAVI_JIT_CANT_COMPILE; + } + else { + p->ravi_jit.jit_data = NULL; + p->ravi_jit.jit_function = fp; + p->ravi_jit.jit_status = RAVI_JIT_COMPILED; + } +Lerror: + membuff_free(&buf); + G->ravi_state->compiling_ = 0; + return fp != NULL; +} + +// Free the JIT compiled function +// Note that this is called by the garbage collector +void raviV_freeproto(struct lua_State *L, struct Proto *p) { + (void)L; + (void)p; +} + +int ravi_compile_C(lua_State *L) { + (void)L; + return 0; +} \ No newline at end of file