LLVM Compilation hooks in Ravi ============================== The current approach is Ravi is that a Lua function can be compiled at the function level. (Note that this is the plan - I am working on the implementation). In terms of changes to support this - we essentially have following. First we have a bunch of C functions - think of these are the compiler API:: #ifdef __cplusplus extern "C" { #endif struct lua_State; struct Proto; /* Initialise the JIT engine */ int raviV_initjit(struct lua_State *L); /* Shutdown the JIT engine */ void raviV_close(struct lua_State *L); /* Compile the given function if possible */ int raviV_compile(struct lua_State *L, struct Proto *p); /* Free the JIT structures associated with the prototype */ void raviV_freeproto(struct lua_State *L, struct Proto *p); #ifdef __cplusplus } #endif Next the ``Proto`` struct definition has some extra fields:: typedef struct RaviJITProto { lu_byte jit_status; // 0=not compiled, 1=can't compile, 2=compiled, 3=freed void *jit_data; lua_CFunction jit_function; } RaviJITProto; /* ** Function Prototypes */ typedef struct Proto { CommonHeader; lu_byte numparams; /* number of fixed parameters */ lu_byte is_vararg; lu_byte maxstacksize; /* maximum stack used by this function */ int sizeupvalues; /* size of 'upvalues' */ int sizek; /* size of 'k' */ int sizecode; int sizelineinfo; int sizep; /* size of 'p' */ int sizelocvars; int linedefined; int lastlinedefined; TValue *k; /* constants used by the function */ Instruction *code; struct Proto **p; /* functions defined inside the function */ int *lineinfo; /* map from opcodes to source lines (debug information) */ LocVar *locvars; /* information about local variables (debug information) */ Upvaldesc *upvalues; /* upvalue information */ struct LClosure *cache; /* last created closure with this prototype */ TString *source; /* used for debug information */ GCObject *gclist; /* RAVI */ RaviJITProto ravi_jit; } Proto; The ``ravi_jit`` member is initialized in ``lfunc.c``:: Proto *luaF_newproto (lua_State *L) { GCObject *o = luaC_newobj(L, LUA_TPROTO, sizeof(Proto)); Proto *f = gco2p(o); f->k = NULL; /* code ommitted */ f->ravi_jit.jit_data = NULL; f->ravi_jit.jit_function = NULL; f->ravi_jit.jit_status = 0; /* not compiled */ return f; } The corresponding function to free is:: void luaF_freeproto (lua_State *L, Proto *f) { raviV_freeproto(L, f); luaM_freearray(L, f->code, f->sizecode); luaM_freearray(L, f->p, f->sizep); luaM_freearray(L, f->k, f->sizek); luaM_freearray(L, f->lineinfo, f->sizelineinfo); luaM_freearray(L, f->locvars, f->sizelocvars); luaM_freearray(L, f->upvalues, f->sizeupvalues); luaM_free(L, f); } When a Lua Function is called it goes through ``luaD_precall()`` in ``ldo.c``. This has been modified to invoke the compiler / use compiled version:: /* ** returns true if function has been executed (C function) */ int luaD_precall (lua_State *L, StkId func, int nresults) { lua_CFunction f; CallInfo *ci; int n; /* number of arguments (Lua) or returns (C) */ ptrdiff_t funcr = savestack(L, func); switch (ttype(func)) { /* omitted */ case LUA_TLCL: { /* Lua function: prepare its call */ CallInfo *prevci = L->ci; /* RAVI - for validation */ StkId base; Proto *p = clLvalue(func)->p; n = cast_int(L->top - func) - 1; /* number of real arguments */ luaD_checkstack(L, p->maxstacksize); for (; n < p->numparams; n++) setnilvalue(L->top++); /* complete missing arguments */ if (!p->is_vararg) { func = restorestack(L, funcr); base = func + 1; } else { base = adjust_varargs(L, p, n); func = restorestack(L, funcr); /* previous call can change stack */ } ci = next_ci(L); /* now 'enter' new function */ ci->nresults = nresults; ci->func = func; ci->u.l.base = base; ci->top = base + p->maxstacksize; lua_assert(ci->top <= L->stack_last); ci->u.l.savedpc = p->code; /* starting point */ ci->callstatus = CIST_LUA; ci->jitstatus = 0; L->top = ci->top; luaC_checkGC(L); /* stack grow uses memory */ if (L->hookmask & LUA_MASKCALL) callhook(L, ci); if (compile) { if (p->ravi_jit.jit_status == 0) { /* not compiled */ raviV_compile(L, p, 0); } if (p->ravi_jit.jit_status == 2) { /* compiled */ lua_assert(p->ravi_jit.jit_function != NULL); ci->jitstatus = 1; /* As JITed function is like a C function * employ the same restrictions on recursive * calls as for C functions */ if (++L->nCcalls >= LUAI_MAXCCALLS) { if (L->nCcalls == LUAI_MAXCCALLS) luaG_runerror(L, "C stack overflow"); else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS >> 3))) luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ } /* Disable YIELDs - so JITed functions cannot * yield */ L->nny++; (*p->ravi_jit.jit_function)(L); L->nny--; L->nCcalls--; lua_assert(L->ci == prevci); /* Return a different value from 1 to * allow luaV_execute() to distinguish between * JITed function and true C function */ return 2; } } return 0; } default: { /* not a function */ /* omitted */ } } } Note that the above returns 2 if compiled Lua function is called. The behaviour in ``lvm.c`` is similar to that when a C function is called.