You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ravi/readthedocs/ravi-jit-compilation-hook.rst

184 lines
5.8 KiB

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.