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.
184 lines
5.8 KiB
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.
|
|
|