ravi-compiler
Dibyendu Majumdar 4 years ago
commit 3a75ee9eb7

@ -33,8 +33,10 @@ Features
* Optional static typing - for details `see the reference manual <https://the-ravi-programming-language.readthedocs.io/en/latest/ravi-reference.html>`_.
* Type specific bytecodes to improve performance
* Compatibility with Lua 5.3 (see Compatibility section below)
* New! JIT backend `MIR <https://github.com/vnmakarov/mir>`_; only Linux and x86-64 supported for now.
* `LLVM <http://www.llvm.org/>`_ powered JIT compiler
* Generational GC from Lua 5.4
* ``defer`` statement for releasing resources
* Compact JIT backend `MIR <https://github.com/vnmakarov/mir>`_; only Linux and x86-64 supported for now.
* `LLVM <http://www.llvm.org/>`_ supported as alternative JIT backend.
* A `distribution with batteries <https://github.com/dibyendumajumdar/Suravi>`_.
Documentation
@ -55,14 +57,15 @@ Lua 5.4 Position Statement
==========================
Lua 5.4 relationship to Ravi is as follows:
* Generational GC - This has been back-ported to Ravi.
* Generational GC - back-ported to Ravi.
* New random number generator - back-ported to Ravi.
* Multiple user values can be associated with userdata - under consideration.
* ``<const>`` variables - no plan to include this.
* ``<const>`` variables - not planned.
* ``<close>`` variables - Ravi has ``'defer'`` statement which is better option in my opinion, hence no plans to support ``<close>`` variables.
* Interpreter performance improvements - these are beneficial to Lua interpreter but not to the JIT backends, hence not much point in back-porting.
* Table implementation changes - under consideration.
* String to number coertion is now part of string library metamethods - back-ported to Ravi.
* String to number coercion is now part of string library metamethods - back-ported to Ravi.
* utf8 library accepts codepoints up to 2^31 - back-ported to Ravi.
* Removal of compatibility layers for 5.1, and 5.2 - not implemented as Ravi continues to provide these layers as per Lua 5.3.
Compatibility with Lua 5.3
@ -74,6 +77,7 @@ Ravi should be able to run all Lua 5.3 programs in interpreted mode, but followi
* 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.
* Ravi uses an extended bytecode which means it is not compatible with Lua 5.3 bytecode.
* Ravi incorporates the new Generational GC from Lua 5.4, hence the GC interface has changed.
+-----------------+-------------+-------------+
| Limit name | Lua value | Ravi value |

@ -294,10 +294,6 @@ LUALIB_API void (luaL_setmetatable)(lua_State *L, const char *tname);
LUALIB_API void *(luaL_testudata)(lua_State *L, int ud, const char *tname);
LUALIB_API void *(luaL_checkudata)(lua_State *L, int ud, const char *tname);
LUALIB_API int (raviL_build_ast_from_buffer) (lua_State *L, const char *buff, size_t size,
const char *name, const char *mode);
LUALIB_API int (raviL_dumpast) (lua_State *L);
LUALIB_API void *ravi_alloc_f(void *msp, void *ptr, size_t osize, size_t nsize);
#endif

@ -32,6 +32,17 @@
#define upisopen(up) ((up)->v != &(up)->u.value)
#ifdef RAVI_DEFER_STATEMENT
/*
** Special "status" for 'luaF_close'
*/
/* close upvalues without running their closing methods */
#define NOCLOSINGMETH (-1)
/* close upvalues running all closing methods in protected mode */
#define CLOSEPROTECT (-2)
#endif
LUAI_FUNC Proto *luaF_newproto (lua_State *L);
LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems);

@ -102,7 +102,7 @@ typedef LUAI_UACINT l_uacInt;
#if defined(lua_assert)
/** RAVI changes */
#if !defined(RAVI_OPTION_STRING1)
#define RAVI_OPTION_STRING1 " assertions"
#define RAVI_OPTION_STRING1 "assertions "
#endif
#if !defined(RAVI_OPTION_STRING2)
#define RAVI_OPTION_STRING2
@ -114,7 +114,7 @@ typedef LUAI_UACINT l_uacInt;
#define lua_assert(c) ((void)0)
#define check_exp(c,e) (e)
#define lua_longassert(c) ((void)0)
/** RVAI changes */
/** RAVI changes */
#define RAVI_OPTION_STRING1
#define RAVI_OPTION_STRING2
#endif

@ -140,10 +140,10 @@ typedef void(*ravi_Writestringerror)(const char *fmt, const char *p);
#define lua_assert(c) assert(c)
#if !defined(RAVI_OPTION_STRING1)
#define RAVI_OPTION_STRING1 " assertions"
#define RAVI_OPTION_STRING1 "assertions "
#endif
#define RAVI_OPTION_STRING2 " ltests"
#define RAVI_OPTION_STRING2 "ltests "
/* to avoid warnings, and to make sure value is really unused */
#define UNUSED(x) (x=0, (void)(x))
@ -226,7 +226,9 @@ extern const char lua_ident[];
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
LUA_API void (lua_close) (lua_State *L);
LUA_API lua_State *(lua_newthread) (lua_State *L);
#ifdef RAVI_DEFER_STATEMENT
LUA_API int (lua_resetthread) (lua_State *L);
#endif
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);

@ -33,10 +33,20 @@
** integral values)
*/
#if !defined(LUA_FLOORN2I)
#define LUA_FLOORN2I 0
#define LUA_FLOORN2I F2Ieq
#endif
/*
** Rounding modes for float->integer coercion
*/
typedef enum {
F2Ieq, /* no rounding; accepts only integral values */
F2Ifloor, /* takes the floor of the number */
F2Iceil /* takes the ceil of the number */
} F2Imod;
/* convert an object to a float (including string coercion) */
#define tonumber(o,n) \
(RAVI_LIKELY(ttisfloat(o)) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n))
@ -55,8 +65,7 @@
/* convert an object to an integer (without string coercion) */
#define tointegerns(o,i) \
(ttisinteger(o) ? (*(i) = ivalue(o), 1) \
: luaV_flttointeger(o,i,LUA_FLOORN2I))
(ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointegerns(o,i,LUA_FLOORN2I))
#define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2))
@ -105,9 +114,11 @@ LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);
LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n);
LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode);
LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, F2Imod mode);
LUAI_FUNC int luaV_tointegerns (const TValue *obj, lua_Integer *p,
F2Imod mode);
LUAI_FUNC int luaV_flttointeger (lua_Number n, lua_Integer *p, F2Imod mode);
/** RAVI changes start **/
LUAI_FUNC int luaV_flttointeger (const TValue *obj, lua_Integer *p, int mode);
LUAI_FUNC int luaV_tointeger_(const TValue *obj, lua_Integer *p);
LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key,
StkId val);
@ -122,8 +133,9 @@ LUAI_FUNC void luaV_finishOp (lua_State *L);
/* RAVI change: the int return value is a Ravi extension */
LUAI_FUNC int luaV_execute (lua_State *L);
LUAI_FUNC void luaV_concat (lua_State *L, int total);
LUAI_FUNC lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y);
LUAI_FUNC lua_Integer luaV_idiv (lua_State *L, lua_Integer x, lua_Integer y);
LUAI_FUNC lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y);
LUAI_FUNC lua_Number luaV_modf (lua_State *L, lua_Number x, lua_Number y);
LUAI_FUNC lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y);
LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb);

@ -93,6 +93,12 @@ void raviV_dumpIR(struct lua_State *L, struct Proto *p);
/* Dump the compiled assembly code if available */
void raviV_dumpASM(struct lua_State *L, struct Proto *p);
/* Return JIT backend identifier */
const char *raviV_jit_id(struct lua_State *L);
/* Options */
const char *raviV_options(struct lua_State *L);
#ifdef __cplusplus
}
#endif

@ -253,7 +253,7 @@ struct LuaLLVMTypes {
llvm::FunctionType *luaV_tointegerT;
llvm::FunctionType *luaV_modT;
llvm::FunctionType *luaV_objlenT;
llvm::FunctionType *luaV_divT;
llvm::FunctionType *luaV_idivT;
llvm::FunctionType *luaV_executeT;
llvm::FunctionType *luaV_gettableT;
llvm::FunctionType *luaV_settableT;
@ -801,7 +801,7 @@ struct RaviFunctionDef {
llvm::Function *luaV_gettableF;
llvm::Function *luaV_settableF;
llvm::Function *luaV_modF;
llvm::Function *luaV_divF;
llvm::Function *luaV_idivF;
llvm::Function *luaV_objlenF;
llvm::Function *luaC_upvalbarrierF;
llvm::Function *luaH_getstrF;

@ -33,8 +33,10 @@ Features
* Optional static typing - for details `see the reference manual <https://the-ravi-programming-language.readthedocs.io/en/latest/ravi-reference.html>`_.
* Type specific bytecodes to improve performance
* Compatibility with Lua 5.3 (see Compatibility section below)
* New! JIT backend `MIR <https://github.com/vnmakarov/mir>`_; only Linux and x86-64 supported for now.
* `LLVM <http://www.llvm.org/>`_ powered JIT compiler
* Generational GC from Lua 5.4
* ``defer`` statement for releasing resources
* Compact JIT backend `MIR <https://github.com/vnmakarov/mir>`_; only Linux and x86-64 supported for now.
* `LLVM <http://www.llvm.org/>`_ supported as alternative JIT backend.
* A `distribution with batteries <https://github.com/dibyendumajumdar/Suravi>`_.
Documentation
@ -55,14 +57,15 @@ Lua 5.4 Position Statement
==========================
Lua 5.4 relationship to Ravi is as follows:
* Generational GC - This has been back-ported to Ravi.
* Generational GC - back-ported to Ravi.
* New random number generator - back-ported to Ravi.
* Multiple user values can be associated with userdata - under consideration.
* ``<const>`` variables - no plan to include this.
* ``<const>`` variables - not planned.
* ``<close>`` variables - Ravi has ``'defer'`` statement which is better option in my opinion, hence no plans to support ``<close>`` variables.
* Interpreter performance improvements - these are beneficial to Lua interpreter but not to the JIT backends, hence not much point in back-porting.
* Table implementation changes - under consideration.
* String to number coertion is now part of string library metamethods - back-ported to Ravi.
* String to number coercion is now part of string library metamethods - back-ported to Ravi.
* utf8 library accepts codepoints up to 2^31 - back-ported to Ravi.
* Removal of compatibility layers for 5.1, and 5.2 - not implemented as Ravi continues to provide these layers as per Lua 5.3.
Compatibility with Lua 5.3
@ -74,6 +77,7 @@ Ravi should be able to run all Lua 5.3 programs in interpreted mode, but followi
* 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.
* Ravi uses an extended bytecode which means it is not compatible with Lua 5.3 bytecode.
* Ravi incorporates the new Generational GC from Lua 5.4, hence the GC interface has changed.
+-----------------+-------------+-------------+
| Limit name | Lua value | Ravi value |

@ -5,6 +5,18 @@ Ravi Extensions to Lua 5.3
:depth: 2
:backlinks: top
------------
Introduction
------------
Ravi is based on Lua 5.3. Additionally some features of Lua 5.4 have been back-ported to Ravi.
This document describes the enhancements available in Ravi compared to the Lua 5.3 baseline.
* Optional static typing
* ``defer`` statement
* Generational Garbage Collector
* New random number generator
----------------------
Optional Static Typing
----------------------
@ -277,8 +289,9 @@ Another example using arrays. Here the function receives a parameter ``arr`` of
The ``table.numarray(n, initial_value)`` creates a ``number[]`` of specified size and initializes the array with the given initial value.
``defer`` statement
-------------------
-----------------------
The ``defer`` statement
-----------------------
A new addition to Ravi is the ``defer`` statement. The statement has the form::
@ -327,6 +340,10 @@ A JIT api is available with following functions:
``ravi.jit([b])``
returns enabled setting of JIT compiler; also enables/disables the JIT compiler; defaults to true
``ravi.jitname()``
returns an identifier for the JIT
``ravi.options()``
returns a string with compiled options
``ravi.auto([b [, min_size [, min_executions]]])``
returns setting of auto compilation and compilation thresholds; also sets the new settings if values are supplied; defaults are false, 150, 50.
``ravi.compile(func_or_table[, options])``
@ -350,7 +367,29 @@ A JIT api is available with following functions:
Enables support for line hooks via the debug api. Note that enabling this option will result in inefficient JIT as a call to a C function will be inserted at beginning of every Lua bytecode boundary; use this option only when you want to use the debug api to step through code line by line. Currently only supported by LLVM backend.
``ravi.verbosity([b])``
Controls the amount of verbose messages generated during compilation.
-------------------------------
Generational Garbage Collection
-------------------------------
Ravi incorporates the generational garbage collector from Lua 5.4.
Please refer to the Lua 5.4 manual regarding the api changes to support generational collection.
Note that by default, Ravi now enables generational garbage collector.
To switch to incremental GC::
collectgarbage("incremental")
To switch to generational GC::
collectgarbage("generational")
-----------------------
Random Number Generator
-----------------------
Ravi incorporates the new random number generator from Lua 5.4.
Please refer to the Lua 5.4 manual for api changes in this area.
----------------
C API Extensions
----------------

@ -1081,9 +1081,3 @@ LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) {
luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f",
(LUAI_UACNUMBER)ver, (LUAI_UACNUMBER)*v);
}
LUALIB_API int (raviL_dumpast) (lua_State *L) {
(void) L;
return 0;
}

@ -75,8 +75,13 @@ static int luaB_auxwrap (lua_State *L) {
lua_State *co = lua_tothread(L, lua_upvalueindex(1));
int r = auxresume(L, co, lua_gettop(L));
if (r < 0) {
#ifdef RAVI_DEFER_STATEMENT
int stat = lua_status(co);
if (stat != LUA_OK && stat != LUA_YIELD)
lua_resetthread(co); /* close variables in case of errors */
#endif
if (lua_type(L, -1) == LUA_TSTRING) { /* error object is a string? */
luaL_where(L, 1); /* add extra info */
luaL_where(L, 1); /* add extra info, if available */
lua_insert(L, -2);
lua_concat(L, 2);
}

@ -104,6 +104,12 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling"));
break;
}
#ifdef RAVI_DEFER_STATEMENT
case CLOSEPROTECT: {
setnilvalue(oldtop); /* no error message */
break;
}
#endif
default: {
setobjs2s(L, oldtop, L->top - 1); /* error message on current top */
break;
@ -120,6 +126,9 @@ l_noret luaD_throw (lua_State *L, int errcode) {
}
else { /* thread has no error handler */
global_State *g = G(L);
#ifdef RAVI_DEFER_STATEMENT
errcode = luaF_close(L, L->stack, errcode); /* close all upvalues */
#endif
L->status = cast_byte(errcode); /* mark it as dead */
if (g->mainthread->errorJmp) { /* main thread has a handler? */
setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */
@ -763,19 +772,17 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
L->nny = 0; /* allow yields */
api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
status = luaD_rawrunprotected(L, resume, &nargs);
if (status == -1) /* error calling 'lua_resume'? */
status = LUA_ERRRUN;
else { /* continue running after recoverable errors */
while (errorstatus(status) && recover(L, status)) {
/* unroll continuation */
status = luaD_rawrunprotected(L, unroll, &status);
}
if (errorstatus(status)) { /* unrecoverable error? */
L->status = cast_byte(status); /* mark thread as 'dead' */
luaD_seterrorobj(L, status, L->top); /* push error message */
L->ci->top = L->top;
}
else lua_assert(status == L->status); /* normal end or yield */
/* continue running after recoverable errors */
while (errorstatus(status) && recover(L, status)) {
/* unroll continuation */
status = luaD_rawrunprotected(L, unroll, &status);
}
if (likely(!errorstatus(status)))
lua_assert(status == L->status); /* normal end or yield */
else { /* unrecoverable error */
L->status = cast_byte(status); /* mark thread as 'dead' */
luaD_seterrorobj(L, status, L->top); /* push error message */
L->ci->top = L->top;
}
L->nny = oldnny; /* restore 'nny' */
L->nCcalls--;

@ -123,7 +123,7 @@ static int preparetocall(lua_State *L, TValue *func, TValue *err) {
** inside the original protected call, and so any error will be handled
** there. Otherwise, a previous error already activated the original
** protected call, and so the call to the deferred method must be
** protected here. (A status == -1 behaves like a previous
** protected here. (A status == CLOSEPROTECT behaves like a previous
** error, to also run the closing method in protected mode).
** If status is OK, the call to the deferred method will be pushed
** at the top of the stack. Otherwise, values are pushed after
@ -143,7 +143,7 @@ static int calldeferredfunction(lua_State *L, StkId level, int status) {
luaD_seterrorobj(L, status, level); /* set error message */
preparetocall(L, uv, level);
int newstatus = luaD_pcall(L, calldeferred, NULL, oldtop, 0);
if (newstatus != LUA_OK && status == -1) /* first error? */
if (newstatus != LUA_OK && status == CLOSEPROTECT) /* first error? */
status = newstatus; /* this will be the new error */
else {
/* leave original error (or nil) on top */
@ -161,7 +161,7 @@ int luaF_close (lua_State *L, StkId level, int status) {
if (uv->refcount == 0) { /* no references? */
UpVal uv1 = *uv; /* copy the upvalue as we will free it below */
luaM_free(L, uv); /* free upvalue before invoking any deferred functions */
if (uv1.flags && ttisfunction(uv1.v)) {
if (status != NOCLOSINGMETH && uv1.flags && ttisfunction(uv1.v)) {
ptrdiff_t levelrel = savestack(L, level);
status = calldeferredfunction(L, uv1.v, status);
level = restorestack(L, levelrel);

@ -670,6 +670,7 @@ static int traverseLclosure (global_State *g, LClosure *cl) {
** That ensures that the entire stack have valid (non-dead) objects.
*/
static lu_mem traversethread (global_State *g, lua_State *th) {
UpVal *uv;
StkId o = th->stack;
if (o == NULL)
return 1; /* stack not completely built yet */
@ -677,6 +678,8 @@ static lu_mem traversethread (global_State *g, lua_State *th) {
th->openupval == NULL || isintwups(th));
for (; o < th->top; o++) /* mark live elements in the stack */
markvalue(g, o);
for (uv = th->openupval; uv != NULL; uv = uv->u.open.next)
markvalue(g, uv->v); /* open upvalues cannot be collected */
if (g->gcstate == GCSatomic) { /* final traversal? */
StkId lim = th->stack + th->stacksize; /* real end of stack */
for (; o < lim; o++) /* clear not-marked stack slice */

@ -87,7 +87,7 @@ static lua_Integer intarith (lua_State *L, int op, lua_Integer v1,
case LUA_OPSUB:return intop(-, v1, v2);
case LUA_OPMUL:return intop(*, v1, v2);
case LUA_OPMOD: return luaV_mod(L, v1, v2);
case LUA_OPIDIV: return luaV_div(L, v1, v2);
case LUA_OPIDIV: return luaV_idiv(L, v1, v2);
case LUA_OPBAND: return intop(&, v1, v2);
case LUA_OPBOR: return intop(|, v1, v2);
case LUA_OPBXOR: return intop(^, v1, v2);
@ -110,11 +110,7 @@ static lua_Number numarith (lua_State *L, int op, lua_Number v1,
case LUA_OPPOW: return luai_numpow(L, v1, v2);
case LUA_OPIDIV: return luai_numidiv(L, v1, v2);
case LUA_OPUNM: return luai_numunm(L, v1);
case LUA_OPMOD: {
lua_Number m;
luai_nummod(L, v1, v2, m);
return m;
}
case LUA_OPMOD: return luaV_modf(L, v1, v2);
default: lua_assert(0); return 0;
}
}

@ -60,6 +60,7 @@ typedef struct BlockCnt {
lu_byte nactvar; /* # active locals outside the block */
lu_byte upval; /* true if some variable in the block is an upvalue */
lu_byte isloop; /* true if 'block' is a loop */
lu_byte insidetbc; /* true if inside the scope of a defer stmt (i.e. defer closure var) */
} BlockCnt;
/* RAVI set debug level */
@ -843,6 +844,7 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) {
bl->firstlabel = fs->ls->dyd->label.n;
bl->firstgoto = fs->ls->dyd->gt.n;
bl->upval = 0;
bl->insidetbc = (fs->bl != NULL && fs->bl->insidetbc);
bl->previous = fs->bl;
fs->bl = bl;
lua_assert(fs->freereg == fs->nactvar);
@ -2231,6 +2233,7 @@ static void localfunc (LexState *ls, int defer) {
static const char funcname[] = "(deferred function)";
new_localvar(ls, luaX_newstring(ls, funcname, sizeof funcname-1), RAVI_TFUNCTION, NULL); /* new local variable */
markupval(fs, fs->nactvar);
fs->bl->insidetbc = 1; /* in the scope of a defer closure variable */
} else {
/* RAVI change - add type */
new_localvar(ls, str_checkname(ls), RAVI_TFUNCTION, NULL); /* new local variable */
@ -2349,7 +2352,7 @@ static void retstat (LexState *ls) {
nret = explist(ls, &e); /* optional return values */
if (hasmultret(e.k)) {
luaK_setmultret(fs, &e);
if (e.k == VCALL && nret == 1) { /* tail call? */
if (e.k == VCALL && nret == 1 && !fs->bl->insidetbc) { /* tail call? */
SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL);
lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar);
}

@ -259,7 +259,7 @@ void *ravi_alloc_f(void *msp, void *ptr, size_t osize, size_t nsize)
static void close_state (lua_State *L) {
global_State *g = G(L);
#ifdef RAVI_DEFER_STATEMENT
luaF_close(L, L->stack, -1); /* close all upvalues for this thread */
luaF_close(L, L->stack, CLOSEPROTECT); /* close all upvalues for this thread */
#else
luaF_close(L, L->stack); /* close all upvalues for this thread */
#endif
@ -310,7 +310,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
void luaE_freethread (lua_State *L, lua_State *L1) {
LX *l = fromstate(L1);
#ifdef RAVI_DEFER_STATEMENT
luaF_close(L1, L1->stack, -1); /* close all upvalues for this thread */
luaF_close(L1, L1->stack, NOCLOSINGMETH); /* close all upvalues for this thread */
#else
luaF_close(L1, L1->stack); /* close all upvalues for this thread */
#endif
@ -320,6 +320,29 @@ void luaE_freethread (lua_State *L, lua_State *L1) {
luaM_free(L, l);
}
#ifdef RAVI_DEFER_STATEMENT
int lua_resetthread (lua_State *L) {
CallInfo *ci;
int status;
lua_lock(L);
L->ci = ci = &L->base_ci; /* unwind CallInfo list */
setnilvalue(L->stack); /* 'function' entry for basic 'ci' */
ci->func = L->stack;
ci->callstatus = 0;
status = luaF_close(L, L->stack, CLOSEPROTECT);
if (status != CLOSEPROTECT) /* real errors? */
luaD_seterrorobj(L, status, L->stack + 1);
else {
status = LUA_OK;
L->top = L->stack + 1;
}
ci->top = L->top + LUA_MINSTACK;
L->status = status;
lua_unlock(L);
return status;
}
#endif
/* TODO following should probably not live here*/
static void raviE_default_writestring(const char *s, size_t l) {

@ -17,6 +17,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ravi_jit.h>
#include "lua.h"
@ -44,20 +45,6 @@
#define LUA_INITVARVERSION LUA_INIT_VAR LUA_VERSUFFIX
#ifdef USE_LLVM
#define ravi_xstringify(s) ravi_stringify(s)
#define ravi_stringify(s) #s
#define RAVI_OPTION_STRING3 " LLVM-" LLVM_VERSION_STRING " ORC=" ravi_xstringify(USE_ORC_JIT) " v2=" ravi_xstringify(USE_ORCv2_JIT)
#elif USE_OMRJIT
#define RAVI_OPTION_STRING3 " omrjit"
#elif USE_MIRJIT
#define RAVI_OPTION_STRING3 " mirjit"
#else
#define RAVI_OPTION_STRING3 " nojit"
#endif
#define RAVI_OPTIONS "\nOptions" RAVI_OPTION_STRING1 RAVI_OPTION_STRING2 RAVI_OPTION_STRING3
/*
** lua_stdin_is_tty detects whether the standard input is a 'tty' (that
** is, whether we're running lua interactively).
@ -228,7 +215,12 @@ static int docall (lua_State *L, int narg, int nres) {
static void print_version (lua_State *L) {
lua_writestring(LUA_COPYRIGHT, strlen(LUA_COPYRIGHT));
lua_writestring(RAVI_OPTIONS, strlen(RAVI_OPTIONS));
const char *options = raviV_options(L);
lua_writeline();
#define OPTSTR "Options "
lua_writestring(OPTSTR, strlen(OPTSTR));
#undef OPTSTR
lua_writestring(options, strlen(options));
lua_writeline();
}

@ -40,12 +40,10 @@
#define MAXTAGLOOP 2000
/*
** 'l_intfitsf' checks whether a given integer is in the range that
** can be converted to a float without rounding. Used in comparisons.
*/
#if !defined(l_intfitsf)
/* number of bits in the mantissa of a float */
#define NBM (l_floatatt(MANT_DIG))
@ -72,8 +70,21 @@
#endif
#endif
/*
** Try to convert a value from string to a number value.
** If the value is not a string or is a string not representing
** a valid numeral (or if coercions from strings to numbers
** are disabled via macro 'cvt2num'), do not modify 'result'
** and return 0.
*/
static int l_strton (const TValue *obj, TValue *result) {
lua_assert(obj != result);
if (!cvt2num(obj)) /* is object not a string? */
return 0;
else
return (luaO_str2num(svalue(obj), result) == vslen(obj) + 1);
}
/*
@ -86,8 +97,7 @@ int luaV_tonumber_ (const TValue *obj, lua_Number *n) {
*n = cast_num(ivalue(obj));
return 1;
}
else if (cvt2num(obj) && /* string coercible to number? */
luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) {
else if (l_strton(obj, &v)) { /* string coercible to number? */
*n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */
return 1;
}
@ -97,46 +107,49 @@ int luaV_tonumber_ (const TValue *obj, lua_Number *n) {
/*
** try to convert a float to an integer, rounding according to 'mode':
** mode == 0: accepts only integral values
** mode == 1: takes the floor of the number
** mode == 2: takes the ceil of the number
** try to convert a float to an integer, rounding according to 'mode'.
*/
int luaV_flttointeger (const TValue *obj, lua_Integer *p, int mode) {
if (!ttisfloat(obj))
return 0;
else {
lua_Number n = fltvalue(obj);
lua_Number f = l_floor(n);
if (n != f) { /* not an integral value? */
if (mode == 0) return 0; /* fails if mode demands integral value */
else if (mode > 1) /* needs ceil? */
f += 1; /* convert floor to ceil (remember: n != f) */
}
return lua_numbertointeger(f, p);
int luaV_flttointeger (lua_Number n, lua_Integer *p, F2Imod mode) {
lua_Number f = l_floor(n);
if (n != f) { /* not an integral value? */
if (mode == F2Ieq) return 0; /* fails if mode demands integral value */
else if (mode == F2Iceil) /* needs ceil? */
f += 1; /* convert floor to ceil (remember: n != f) */
}
return lua_numbertointeger(f, p);
}
/*
** try to convert a value to an integer. ("Fast track" is handled
** by macro 'tointeger'.)
** try to convert a value to an integer, rounding according to 'mode',
** without string coercion.
** ("Fast track" handled by macro 'tointegerns'.)
*/
int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) {
TValue v;
if (cvt2num(obj) && luaO_str2num(svalue(obj), &v) == vslen(obj) + 1)
obj = &v; /* change string to its corresponding number */
if (ttisinteger(obj)) {
int luaV_tointegerns (const TValue *obj, lua_Integer *p, F2Imod mode) {
if (ttisfloat(obj))
return luaV_flttointeger(fltvalue(obj), p, mode);
else if (ttisinteger(obj)) {
*p = ivalue(obj);
return 1;
}
else
return luaV_flttointeger(obj, p, mode);
return 0;
}
/*
** try to convert a value to an integer.
*/
int luaV_tointeger (const TValue *obj, lua_Integer *p, F2Imod mode) {
TValue v;
if (l_strton(obj, &v)) /* does 'obj' point to a numerical string? */
obj = &v; /* change it to point to its corresponding number */
return luaV_tointegerns(obj, p, mode);
}
/*
** try to convert a value to an integer
** try to convert a value to an integer.
*/
int luaV_tointeger_ (const TValue *obj, lua_Integer *p) {
return luaV_tointeger(obj, p, LUA_FLOORN2I);
@ -163,7 +176,7 @@ int luaV_forlimit (const TValue *obj, lua_Integer *p, lua_Integer step,
*stopnow = 0; /* usually, let loops run */
if (ttisinteger(obj))
*p = ivalue(obj);
else if (!luaV_tointeger(obj, p, (step < 0 ? 2 : 1))) {
else if (!luaV_tointeger(obj, p, (step < 0 ? F2Iceil : F2Ifloor))) {
/* not coercible to in integer */
lua_Number n; /* try to convert to float */
if (!tonumber(obj, &n)) /* cannot convert to float? */
@ -513,8 +526,8 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
/*
** Compare two strings 'ls' x 'rs', returning an integer smaller-equal-
** -larger than zero if 'ls' is smaller-equal-larger than 'rs'.
** Compare two strings 'ls' x 'rs', returning an integer less-equal-
** -greater than zero if 'ls' is less-equal-greater than 'rs'.
** The code is a little tricky because it allows '\0' in the strings
** and it uses 'strcoll' (to respect locales) for each segments
** of the strings.
@ -533,7 +546,7 @@ static int l_strcmp (const TString *ls, const TString *rs) {
if (len == lr) /* 'rs' is finished? */
return (len == ll) ? 0 : 1; /* check 'ls' */
else if (len == ll) /* 'ls' is finished? */
return -1; /* 'ls' is smaller than 'rs' ('rs' is not finished) */
return -1; /* 'ls' is less than 'rs' ('rs' is not finished) */
/* both strings longer than 'len'; go on comparing after the '\0' */
len++;
l += len; ll -= len; r += len; lr -= len;
@ -545,25 +558,24 @@ static int l_strcmp (const TString *ls, const TString *rs) {
/*
** Check whether integer 'i' is less than float 'f'. If 'i' has an
** exact representation as a float ('l_intfitsf'), compare numbers as
** floats. Otherwise, if 'f' is outside the range for integers, result
** is trivial. Otherwise, compare them as integers. (When 'i' has no
** float representation, either 'f' is "far away" from 'i' or 'f' has
** no precision left for a fractional part; either way, how 'f' is
** truncated is irrelevant.) When 'f' is NaN, comparisons must result
** in false.
** floats. Otherwise, use the equivalence 'i < f <=> i < ceil(f)'.
** If 'ceil(f)' is out of integer range, either 'f' is greater than
** all integers or less than all integers.
** (The test with 'l_intfitsf' is only for performance; the else
** case is correct for all values, but it is slow due to the conversion
** from float to int.)
** When 'f' is NaN, comparisons must result in false.
*/
static int LTintfloat (lua_Integer i, lua_Number f) {
#if defined(l_intfitsf)
if (!l_intfitsf(i)) {
if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */
return 1; /* f >= maxint + 1 > i */
else if (f > cast_num(LUA_MININTEGER)) /* minint < f <= maxint ? */
return (i < cast(lua_Integer, f)); /* compare them as integers */
else /* f <= minint <= i (or 'f' is NaN) --> not(i < f) */
return 0;
if (l_intfitsf(i))
return luai_numlt(cast_num(i), f); /* compare them as floats */
else { /* i < f <=> i < ceil(f) */
lua_Integer fi;
if (luaV_flttointeger(f, &fi, F2Iceil)) /* fi = ceil(f) */
return i < fi; /* compare them as integers */
else /* 'f' is either greater or less than all integers */
return f > 0; /* greater? */
}
#endif
return luai_numlt(cast_num(i), f); /* compare them as floats */
}
@ -572,17 +584,49 @@ static int LTintfloat (lua_Integer i, lua_Number f) {
** See comments on previous function.
*/
static int LEintfloat (lua_Integer i, lua_Number f) {
#if defined(l_intfitsf)
if (!l_intfitsf(i)) {
if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */
return 1; /* f >= maxint + 1 > i */
else if (f >= cast_num(LUA_MININTEGER)) /* minint <= f <= maxint ? */
return (i <= cast(lua_Integer, f)); /* compare them as integers */
else /* f < minint <= i (or 'f' is NaN) --> not(i <= f) */
return 0;
if (l_intfitsf(i))
return luai_numle(cast_num(i), f); /* compare them as floats */
else { /* i <= f <=> i <= floor(f) */
lua_Integer fi;
if (luaV_flttointeger(f, &fi, F2Ifloor)) /* fi = floor(f) */
return i <= fi; /* compare them as integers */
else /* 'f' is either greater or less than all integers */
return f > 0; /* greater? */
}
}
/*
** Check whether float 'f' is less than integer 'i'.
** See comments on previous function.
*/
static int LTfloatint (lua_Number f, lua_Integer i) {
if (l_intfitsf(i))
return luai_numlt(f, cast_num(i)); /* compare them as floats */
else { /* f < i <=> floor(f) < i */
lua_Integer fi;
if (luaV_flttointeger(f, &fi, F2Ifloor)) /* fi = floor(f) */
return fi < i; /* compare them as integers */
else /* 'f' is either greater or less than all integers */
return f < 0; /* less? */
}
}
/*
** Check whether float 'f' is less than or equal to integer 'i'.
** See comments on previous function.
*/
static int LEfloatint (lua_Number f, lua_Integer i) {
if (l_intfitsf(i))
return luai_numle(f, cast_num(i)); /* compare them as floats */
else { /* f <= i <=> ceil(f) <= i */
lua_Integer fi;
if (luaV_flttointeger(f, &fi, F2Iceil)) /* fi = ceil(f) */
return fi <= i; /* compare them as integers */
else /* 'f' is either greater or less than all integers */
return f < 0; /* less? */
}
#endif
return luai_numle(cast_num(i), f); /* compare them as floats */
}
@ -602,10 +646,8 @@ static int LTnum (const TValue *l, const TValue *r) {
lua_Number lf = fltvalue(l); /* 'l' must be float */
if (ttisfloat(r))
return luai_numlt(lf, fltvalue(r)); /* both are float */
else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */
return 0; /* NaN < i is always false */
else /* without NaN, (l < r) <--> not(r <= l) */
return !LEintfloat(ivalue(r), lf); /* not (r <= l) ? */
else /* 'l' is float and 'r' is int */
return LTfloatint(lf, ivalue(r));
}
}
@ -626,10 +668,8 @@ static int LEnum (const TValue *l, const TValue *r) {
lua_Number lf = fltvalue(l); /* 'l' must be float */
if (ttisfloat(r))
return luai_numle(lf, fltvalue(r)); /* both are float */
else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */
return 0; /* NaN <= i is always false */
else /* without NaN, (l <= r) <--> not(r < l) */
return !LTintfloat(ivalue(r), lf); /* not (r < l) ? */
else /* 'l' is float and 'r' is int */
return LEfloatint(lf, ivalue(r));
}
}
@ -772,7 +812,7 @@ void luaV_concat (lua_State *L, int total) {
/* collect total length and number of strings */
for (n = 1; n < total && tostring(L, top - n - 1); n++) {
size_t l = vslen(top - n - 1);
if (l >= (MAX_SIZE/sizeof(char)) - tl)
if (unlikely(l >= (MAX_SIZE/sizeof(char)) - tl))
luaG_runerror(L, "string length overflow");
tl += l;
}
@ -822,7 +862,7 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
}
default: { /* try metamethod */
tm = luaT_gettmbyobj(L, rb, TM_LEN);
if (ttisnil(tm)) /* no metamethod? */
if (unlikely(ttisnil(tm))) /* no metamethod? */
luaG_typeerror(L, rb, "get length of");
break;
}
@ -837,8 +877,8 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
** 'floor(q) == trunc(q)' when 'q >= 0' or when 'q' is integer,
** otherwise 'floor(q) == trunc(q) - 1'.
*/
lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) {
if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */
lua_Integer luaV_idiv (lua_State *L, lua_Integer m, lua_Integer n) {
if (unlikely(l_castS2U(n) + 1u <= 1u)) { /* special cases: -1 or 0 */
if (n == 0)
luaG_runerror(L, "attempt to divide by zero");
return intop(-, 0, m); /* n==-1; avoid overflow with 0x80000...//-1 */
@ -855,23 +895,33 @@ lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) {
/*
** Integer modulus; return 'm % n'. (Assume that C '%' with
** negative operands follows C99 behavior. See previous comment
** about luaV_div.)
** about luaV_idiv.)
*/
lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) {
if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */
if (unlikely(l_castS2U(n) + 1u <= 1u)) { /* special cases: -1 or 0 */
if (n == 0)
luaG_runerror(L, "attempt to perform 'n%%0'");
return 0; /* m % -1 == 0; avoid overflow with 0x80000...%-1 */
}
else {
lua_Integer r = m % n;
if (r != 0 && (m ^ n) < 0) /* 'm/n' would be non-integer negative? */
if (r != 0 && (r ^ n) < 0) /* 'm/n' would be non-integer negative? */
r += n; /* correct result for different rounding */
return r;
}
}
/*
** Float modulus
*/
lua_Number luaV_modf (lua_State *L, lua_Number m, lua_Number n) {
lua_Number r;
luai_nummod(L, m, n, r);
return r;
}
/* number of bits in an integer */
#define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT)
@ -1547,7 +1597,7 @@ int luaV_execute (lua_State *L) {
lua_Number nb; lua_Number nc;
if (ttisinteger(rb) && ttisinteger(rc)) {
lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
setivalue(ra, luaV_div(L, ib, ic));
setivalue(ra, luaV_idiv(L, ib, ic));
}
else if (tonumberns(rb, nb) && tonumberns(rc, nc)) {
setfltvalue(ra, luai_numidiv(L, nb, nc));
@ -1738,7 +1788,7 @@ int luaV_execute (lua_State *L) {
/* close all upvalues from previous call */
#ifdef RAVI_DEFER_STATEMENT
if (cl->p->sizep > 0)
Protect_base(luaF_close(L, oci->u.l.base, LUA_OK));
Protect_base(luaF_close(L, oci->u.l.base, NOCLOSINGMETH));
#else
if (cl->p->sizep > 0) luaF_close(L, oci->u.l.base);
#endif
@ -1759,8 +1809,10 @@ int luaV_execute (lua_State *L) {
vmcase(OP_RETURN) {
int b = GETARG_B(i);
#ifdef RAVI_DEFER_STATEMENT
if (cl->p->sizep > 0)
if (cl->p->sizep > 0) {
Protect_base(luaF_close(L, base, LUA_OK));
ra = RA(i);
}
#else
if (cl->p->sizep > 0) luaF_close(L, base);
#endif

@ -238,6 +238,18 @@ static int ravi_listcode(lua_State *L) {
return ravi_list_code(L);
}
static int ravi_get_jit_id(lua_State *L) {
const char *id = raviV_jit_id(L);
lua_pushstring(L, id);
return 1;
}
static int ravi_get_options(lua_State *L) {
const char *options = raviV_options(L);
lua_pushstring(L, options);
return 1;
}
static const luaL_Reg ravilib[] = {{"iscompiled", ravi_is_compiled},
{"compile", ravi_compile_n},
{"dumplua", ravi_dump_luacode},
@ -254,6 +266,8 @@ static const luaL_Reg ravilib[] = {{"iscompiled", ravi_is_compiled},
{"tracehook", ravi_traceenable},
{"listcode", ravi_listcode},
{"limits", ravi_get_limits},
{"jitname", ravi_get_jit_id},
{"options", ravi_get_options},
{NULL, NULL}};
#include <math.h>

@ -1062,7 +1062,6 @@ static void emit_op_loadk(struct function *fn, int A, int Bx, int pc) {
static void emit_op_return(struct function *fn, int A, int B, int pc) {
(void)pc;
emit_reg(fn, "ra", A);
#ifdef RAVI_DEFER_STATEMENT
membuff_add_string(&fn->body, "if (cl->p->sizep > 0) {\n luaF_close(L, base, LUA_OK);\n");
membuff_add_string(&fn->body, " base = ci->u.l.base;\n");
@ -1070,6 +1069,7 @@ static void emit_op_return(struct function *fn, int A, int B, int pc) {
#else
membuff_add_string(&fn->body, "if (cl->p->sizep > 0) luaF_close(L, base);\n");
#endif
emit_reg(fn, "ra", A);
membuff_add_fstring(&fn->body, "result = (%d != 0 ? %d - 1 : cast_int(L->top - ra));\n", B, B);
membuff_add_string(&fn->body, "return luaD_poscall(L, ci, ra, result);\n");
}

@ -739,7 +739,7 @@ void RaviCodeGenerator::emit_IDIV(RaviFunctionDef *def, int A, int B, int C,
// lua_Number nb; lua_Number nc;
// if (ttisinteger(rb) && ttisinteger(rc)) {
// lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
// setivalue(ra, luaV_div(L, ib, ic));
// setivalue(ra, luaV_idiv(L, ib, ic));
//}
// else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
// setfltvalue(ra, luai_numidiv(L, nb, nc));
@ -786,7 +786,7 @@ void RaviCodeGenerator::emit_IDIV(RaviFunctionDef *def, int A, int B, int C,
llvm::Instruction *rhs = emit_load_reg_i(def, rc);
llvm::Value *result =
CreateCall3(def->builder, def->luaV_divF, def->L, lhs, rhs);
CreateCall3(def->builder, def->luaV_idivF, def->L, lhs, rhs);
emit_store_reg_i_withtype(def, result, ra);
def->builder->CreateBr(done_block);

@ -1135,8 +1135,8 @@ void RaviCodeGenerator::emit_extern_declarations(RaviFunctionDef *def) {
reinterpret_cast<void *>(&raviV_op_setlist), "raviV_op_setlist");
def->luaV_modF = def->raviF->addExternFunction(
def->types->luaV_modT, reinterpret_cast<void *>(&luaV_mod), "luaV_mod");
def->luaV_divF = def->raviF->addExternFunction(
def->types->luaV_divT, reinterpret_cast<void *>(&luaV_div), "luaV_div");
def->luaV_idivF = def->raviF->addExternFunction(
def->types->luaV_idivT, reinterpret_cast<void *>(&luaV_idiv), "luaV_idiv");
def->luaV_objlenF = def->raviF->addExternFunction(
def->types->luaV_objlenT, reinterpret_cast<void *>(&luaV_objlen),
"luaV_objlen");

@ -151,7 +151,7 @@ static struct {
{"luaV_forlimit", reinterpret_cast<void *>(luaV_forlimit)},
{"luaV_finishget", reinterpret_cast<void *>(luaV_finishget)},
{"luaV_mod", reinterpret_cast<void *>(luaV_mod)},
{"luaV_div", reinterpret_cast<void *>(luaV_div)},
{"luaV_idiv", reinterpret_cast<void *>(luaV_idiv)},
{"raviV_op_newtable", reinterpret_cast<void *>(raviV_op_newtable)},
{"raviV_op_newarrayint", reinterpret_cast<void *>(raviV_op_newarrayint)},
{"raviV_op_newarrayfloat", reinterpret_cast<void *>(raviV_op_newarrayfloat)},
@ -1080,3 +1080,17 @@ int raviV_gettraceenabled(lua_State *L) {
}
extern "C" int ravi_compile_C(lua_State *L) { return 0; }
const char *raviV_jit_id(struct lua_State *L) {
return "llvm";
}
#define ravi_xstringify(s) ravi_stringify(s)
#define ravi_stringify(s) #s
#define RAVI_OPTION_STRING3 "LLVM-" LLVM_VERSION_STRING " ORC=" ravi_xstringify(USE_ORC_JIT) " v2=" ravi_xstringify(USE_ORCv2_JIT)
#define RAVI_OPTIONS RAVI_OPTION_STRING1 RAVI_OPTION_STRING2 RAVI_OPTION_STRING3
const char *raviV_options(struct lua_State *L) {
return RAVI_OPTIONS;
}

@ -899,14 +899,14 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
raviV_op_setlistT =
llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false);
// lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n)
// lua_Integer luaV_idiv (lua_State *L, lua_Integer m, lua_Integer n)
// lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n)
elements.clear();
elements.push_back(plua_StateT);
elements.push_back(lua_IntegerT);
elements.push_back(lua_IntegerT);
luaV_modT = llvm::FunctionType::get(lua_IntegerT, elements, false);
luaV_divT = llvm::FunctionType::get(lua_IntegerT, elements, false);
luaV_idivT = llvm::FunctionType::get(lua_IntegerT, elements, false);
// void raviV_op_concat(lua_State *L, CallInfo *ci, int a, int b, int c)
elements.clear();

@ -494,4 +494,15 @@ void raviV_freeproto(struct lua_State *L, struct Proto *p) {
int ravi_compile_C(lua_State *L) {
(void)L;
return 0;
}
}
const char *raviV_jit_id(struct lua_State *L) {
return "mir";
}
#define RAVI_OPTION_STRING3 "mirjit"
#define RAVI_OPTIONS RAVI_OPTION_STRING1 RAVI_OPTION_STRING2 RAVI_OPTION_STRING3
const char *raviV_options(struct lua_State *L) {
return RAVI_OPTIONS;
}

@ -166,4 +166,16 @@ int raviV_gettraceenabled(struct lua_State *L) {
int ravi_compile_C(lua_State *L) {
(void)L;
return 0;
}
}
const char *raviV_jit_id(struct lua_State *L) {
return "nojit";
}
#define RAVI_OPTION_STRING3 "nojit"
#define RAVI_OPTIONS RAVI_OPTION_STRING1 RAVI_OPTION_STRING2 RAVI_OPTION_STRING3
const char *raviV_options(struct lua_State *L) {
return RAVI_OPTIONS;
}

@ -0,0 +1,485 @@
if ravi then
ravi.auto(true)
end
T = ravi
local opcodes_coverage = {}
opcodes_coverage.MOVE = 0
opcodes_coverage.LOADK = 0
opcodes_coverage.LOADKX = 0
opcodes_coverage.LOADBOOL = 0
opcodes_coverage.LOADNIL = 0
opcodes_coverage.GETUPVAL = 0
opcodes_coverage.GETTABUP = 0
opcodes_coverage.GETTABUP_SK = 0
opcodes_coverage.GETTABLE = 0
opcodes_coverage.SETTABUP = 0
opcodes_coverage.SETTABUP_SK = 0
opcodes_coverage.SETUPVAL = 0
opcodes_coverage.SETTABLE = 0
opcodes_coverage.NEWTABLE = 0
opcodes_coverage.SELF = 0
opcodes_coverage.ADD = 0
opcodes_coverage.SUB = 0
opcodes_coverage.MUL = 0
opcodes_coverage.MOD = 0
opcodes_coverage.POW = 0
opcodes_coverage.DIV = 0
opcodes_coverage.IDIV = 0
opcodes_coverage.BAND = 0
opcodes_coverage.BOR = 0
opcodes_coverage.BXOR = 0
opcodes_coverage.SHL = 0
opcodes_coverage.SHR = 0
opcodes_coverage.UNM = 0
opcodes_coverage.BNOT = 0
opcodes_coverage.NOT = 0
opcodes_coverage.LEN = 0
opcodes_coverage.CONCAT = 0
opcodes_coverage.JMP = 0
opcodes_coverage.EQ = 0
opcodes_coverage.LT = 0
opcodes_coverage.LE = 0
opcodes_coverage.TEST = 0
opcodes_coverage.TESTSET = 0
opcodes_coverage.CALL = 0
opcodes_coverage.TAILCALL = 0
opcodes_coverage.RETURN = 0
opcodes_coverage.FORLOOP = 0
opcodes_coverage.FORPREP = 0
opcodes_coverage.TFORCALL = 0
opcodes_coverage.TFORLOOP = 0
opcodes_coverage.SETLIST = 0
opcodes_coverage.CLOSURE = 0
opcodes_coverage.VARARG = 0
opcodes_coverage.EXTRAARG = 0
opcodes_coverage.NEW_IARRAY = 0
opcodes_coverage.NEW_FARRAY = 0
opcodes_coverage.LOADIZ = 0
opcodes_coverage.LOADFZ = 0
opcodes_coverage.UNMF = 0
opcodes_coverage.UNMI = 0
opcodes_coverage.ADDFF = 0
opcodes_coverage.ADDFI = 0
opcodes_coverage.ADDII = 0
opcodes_coverage.SUBFF = 0
opcodes_coverage.SUBFI = 0
opcodes_coverage.SUBIF = 0
opcodes_coverage.SUBII = 0
opcodes_coverage.MULFF = 0
opcodes_coverage.MULFI = 0
opcodes_coverage.MULII = 0
opcodes_coverage.DIVFF = 0
opcodes_coverage.DIVFI = 0
opcodes_coverage.DIVIF = 0
opcodes_coverage.DIVII = 0
opcodes_coverage.TOINT = 0
opcodes_coverage.TOFLT = 0
opcodes_coverage.TOIARRAY = 0
opcodes_coverage.TOFARRAY = 0
opcodes_coverage.MOVEI = 0
opcodes_coverage.MOVEF = 0
opcodes_coverage.MOVEIARRAY = 0
opcodes_coverage.MOVEFARRAY = 0
opcodes_coverage.IARRAY_GET = 0
opcodes_coverage.FARRAY_GET = 0
opcodes_coverage.IARRAY_SET = 0
opcodes_coverage.FARRAY_SET = 0
opcodes_coverage.FORLOOP_IP = 0
opcodes_coverage.FORLOOP_I1 = 0
opcodes_coverage.FORPREP_IP = 0
opcodes_coverage.FORPREP_I1 = 0
opcodes_coverage.SETUPVALI = 0
opcodes_coverage.SETUPVALF = 0
opcodes_coverage.SETUPVAL_IARRAY = 0
opcodes_coverage.SETUPVAL_FARRAY = 0
opcodes_coverage.IARRAY_SETI = 0
opcodes_coverage.FARRAY_SETF = 0
opcodes_coverage.BAND_II = 0
opcodes_coverage.BOR_II = 0
opcodes_coverage.BXOR_II = 0
opcodes_coverage.SHL_II = 0
opcodes_coverage.SHR_II = 0
opcodes_coverage.BNOT_I = 0
opcodes_coverage.EQ_II = 0
opcodes_coverage.EQ_FF = 0
opcodes_coverage.LT_II = 0
opcodes_coverage.LT_FF = 0
opcodes_coverage.LE_II = 0
opcodes_coverage.LE_FF = 0
opcodes_coverage.GETI = 0
opcodes_coverage.TABLE_GETFIELD = 0
opcodes_coverage.SETI = 0
opcodes_coverage.TABLE_SETFIELD = 0
opcodes_coverage.SETFIELD = 0
opcodes_coverage.GETFIELD = 0
opcodes_coverage.TOTAB = 0
opcodes_coverage.MOVETAB = 0
opcodes_coverage.SETUPVALT = 0
opcodes_coverage.TABLE_SELF_SK = 0
opcodes_coverage.TOTYPE = 0
opcodes_coverage.TOSTRING = 0
opcodes_coverage.TOCLOSURE = 0
opcodes_coverage.SELF_SK = 0
opcodes_coverage.DEFER = 0
local compile = function(f)
if ravi and ravi.jit() then
assert(ravi.compile(f))
end
return true
end
-- ================================================================
-- Following section is an extract from the code.lua test
-- These functions test bytecode generation, and also provide
-- helper routines that we use later on in other test cases
-- testing opcodes
function check (f, ...)
if not T then
return true
end
local arg = {...}
local c = T.listcode(f)
for i=1, #arg do
--print(arg[i], c[i])
opcodes_coverage[arg[i]] = opcodes_coverage[arg[i]]+1
assert(string.find(c[i], '- '..arg[i]..' *[AB][xs]?=%d'))
end
assert(c[#arg+2] == nil)
end
-- Test defer statement
do
local y = 0
local function x()
defer y = y + 1 end
defer y = y + 1 end
end
check(x, 'DEFER', 'CLOSURE', 'DEFER', 'CLOSURE', 'RETURN')
x()
assert(y == 2)
compile(x)
x()
assert(y == 4)
print 'Test 1 OK'
end
-- Test defer statement
do
local y = 0
local function x()
defer y = y + 1 end
error('raise error')
defer y = y + 2 end -- will not be called
end
pcall(x)
assert(y == 1)
compile(x)
pcall(x)
assert(y == 2)
print 'Test 2 OK'
end
-- Test defer statement
do
local y = 0
local function x()
defer y = y + 1 end
defer y = y + 2; error('err') end
defer y = y + 3 end
end
pcall(x)
assert(y == 6)
compile(x)
pcall(x)
assert(y == 12)
print 'Test 3 OK'
end
-- Test defer statement in tailcalls
do
local y = 0
local function x (n)
defer y = y + 1 end
if n > 0 then return x(n - 1) end
end
pcall(x, 3)
assert(y == 4)
compile(x)
pcall(x, 3)
assert(y == 8)
print 'Test 4 OK'
end
-- Simulate a test of resource closure with defer
do
local y = 0
local z = { count = 0 }
z.__index = z;
function z:new()
local object = {}
setmetatable(object, z)
return object
end
function z:open(arg)
if (arg) then
z.count = z.count + 1
return
end
y = 1
error('error opening')
end
function z.close()
z.count = z.count - 1
end
local function x(arg)
local f = z:new()
f:open(arg)
assert(z.count == 1)
defer f:close() end
end
x('filename')
assert(y == 0)
assert(z.count == 0)
pcall(x, false)
assert(z.count == 0)
assert(y == 1)
y = 0
compile(x)
compile(z.new)
compile(z.open)
compile(z.close)
x('filename')
assert(y == 0)
assert(z.count == 0)
pcall(x, false)
assert(z.count == 0)
assert(y == 1)
print 'Test 5 OK'
end
--- Test stack reallocation in defer statement
do
local function x(a) if a <= 0 then return else x(a-1) end end
local y = ravi.jit and 100 or 1000
local function z(...)
-- recursive call to make stack
defer x(y) end
return ...
end
do
local a,b,c = z(1,2,3)
assert(a == 1 and b == 2 and c == 3)
compile(x)
compile(z)
a,b,c = z(3,2,1)
assert(a == 3 and b == 2 and c == 1)
end
print 'Test 6 OK'
end
-- Adapted from Lua 5.4
local function stack(n) n = ((n == 0) or stack(n - 1)) end
local function func2close (f, x, y)
local obj = setmetatable({}, {__close = f})
if x then
return x, obj, y
else
return obj
end
end
do
local function t()
local a = {}
do
local b = false -- not to be closed
-- x is <close>
local x = setmetatable({"x"}, {__close = function (self)
a[#a + 1] = self[1] end})
defer getmetatable(x).__close(x) end
-- y is <close>
local w, y, z = func2close(function (self, err)
assert(err == nil); a[#a + 1] = "y"
end, 10, 20)
defer getmetatable(y).__close(y) end
local c = nil -- not to be closed
a[#a + 1] = "in"
assert(w == 10 and z == 20)
end
a[#a + 1] = "out"
assert(a[1] == "in" and a[2] == "y" and a[3] == "x" and a[4] == "out")
end
t()
compile(t)
t()
print 'Test 7 OK'
end
do
local function t()
local X = false
local x, closescope = func2close(function () stack(10); X = true end, 100)
assert(x == 100); x = 101; -- 'x' is not read-only
-- closing functions do not corrupt returning values
local function foo (x)
local _ = closescope
defer getmetatable(_).__close(_) end
return x, X, 23
end
local a, b, c = foo(1.5)
assert(a == 1.5 and b == false and c == 23 and X == true)
X = false
foo = function (x)
local _ = closescope
defer getmetatable(_).__close(_) end
local y = 15
return y
end
assert(foo() == 15 and X == true)
X = false
foo = function ()
local x = closescope
defer getmetatable(x).__close(x) end
return x
end
assert(foo() == closescope and X == true)
end
t()
compile(t)
t()
print 'Test 8 OK'
end
do
local function t()
-- calls cannot be tail in the scope of to-be-closed variables
local X, Y
local function foo ()
local _ = func2close(function () Y = 10 end)
defer getmetatable(_).__close(_) end
assert(X == true and Y == nil) -- 'X' not closed yet
return 1,2,3
end
local function bar ()
local _ = func2close(function () X = false end)
defer getmetatable(_).__close(_) end
X = true
do
return foo() -- not a tail call!
end
end
local a, b, c, d = bar()
assert(a == 1 and b == 2 and c == 3 and X == false and Y == 10 and d == nil)
return foo, bar
end
local f,b = t()
compile(f)
compile(b)
compile(t)
t()
print 'Test 9 OK'
end
do
local function t()
-- an error in a wrapped coroutine closes variables
local x = false
local y = false
local co = coroutine.wrap(function ()
local xv = func2close(function () x = true end)
defer getmetatable(xv).__close(xv) end
do
local yv = func2close(function () y = true end)
defer getmetatable(yv).__close(yv) end
coroutine.yield(100) -- yield doesn't close variable
end
coroutine.yield(200) -- yield doesn't close variable
error(23) -- error does
end)
local b = co()
assert(b == 100 and not x and not y)
b = co()
assert(b == 200 and not x and y)
local a, b = pcall(co)
assert(not a and b == 23 and x and y)
end
t()
compile(t)
t()
print 'Test 10 OK'
end
-- a suspended coroutine should not close its variables when collected
do
function t()
local co
co = coroutine.wrap(function()
-- should not run
local x = func2close(function () os.exit(false) end)
defer getmetatable(x).__close(x) end
co = nil
coroutine.yield()
end)
co() -- start coroutine
assert(co == nil) -- eventually it will be collected
collectgarbage()
end
t()
compile(t)
t()
print 'Test 11 OK'
end
do
local function t()
-- error in a wrapped coroutine raising errors when closing a variable
local x = 0
local co = coroutine.wrap(function ()
local xx = func2close(function () x = x + 1; error("@YYY") end)
defer getmetatable(xx).__close(xx) end
local xv = func2close(function () x = x + 1; error("@XXX") end)
defer getmetatable(xv).__close(xv) end
coroutine.yield(100)
error(200)
end)
assert(co() == 100); assert(x == 0)
local st, msg = pcall(co); assert(x == 2)
assert(not st and msg == 200) -- should get first error raised
local x = 0
local y = 0
co = coroutine.wrap(function ()
local xx = func2close(function () y = y + 1; error("YYY") end)
defer getmetatable(xx).__close(xx) end
local xv = func2close(function () x = x + 1; error("XXX") end)
defer getmetatable(xv).__close(xv) end
coroutine.yield(100)
return 200
end)
assert(co() == 100); assert(x == 0)
local st, msg = pcall(co)
assert(not st and string.find(msg, "%w+%.%w+:%d+: XXX"))
assert(x == 1 and y == 1)
end
t()
compile(t)
t()
print 'Test 12 OK'
end
print 'OK'

@ -1738,105 +1738,6 @@ print 'Test 77 OK'
--
-- Test defer statement
y = 0
function x()
defer y = y + 1 end
defer y = y + 1 end
end
check(x, 'DEFER', 'CLOSURE', 'DEFER', 'CLOSURE', 'RETURN')
x()
assert(y == 2)
compile(x)
x()
assert(y == 4)
print 'Test 78 OK'
-- Test defer statement
y = 0
function x()
defer y = y + 1 end
error('raise error')
defer y = y + 2 end -- will not be called
end
pcall(x)
assert(y == 1)
compile(x)
pcall(x)
assert(y == 2)
print 'Test 79 OK'
-- Test defer statement
y = 0
function x()
defer y = y + 1 end
defer y = y + 2; error('err') end
defer y = y + 3 end
end
pcall(x)
assert(y == 6)
compile(x)
pcall(x)
assert(y == 12)
print 'Test 80 OK'
-- Test defer statement in tailcalls
y = 0
function x (n)
defer y = y + 1 end
if n > 0 then return x(n - 1) end
end
pcall(x, 3)
assert(y == 4)
compile(x)
pcall(x, 3)
assert(y == 8)
print 'Test 81 OK'
-- Simulate a test of resource closure with defer
y = 0
z = { count = 0 }
z.__index = z;
function z:new()
local object = {}
setmetatable(object, z)
return object
end
function z:open(arg)
if (arg) then
z.count = z.count + 1
return
end
y = 1
error('error opening')
end
function z.close()
z.count = z.count - 1
end
function x(arg)
local f = z:new()
f:open(arg)
assert(z.count == 1)
defer f:close() end
end
x('filename')
assert(y == 0)
assert(z.count == 0)
pcall(x, false)
assert(z.count == 0)
assert(y == 1)
y = 0
compile(x)
compile(z.new)
compile(z.open)
compile(z.close)
x('filename')
assert(y == 0)
assert(z.count == 0)
pcall(x, false)
assert(z.count == 0)
assert(y == 1)
print 'Test 82 OK'
-- Create some slices and invoke GC
x = function ()
@ -1891,6 +1792,8 @@ compile(x)
x()
print 'Test 83 OK'
for k,v in pairs(opcodes_coverage)
do
print(k, v)

@ -44,6 +44,8 @@ run_lua53_tests "_port=true ravi.auto(true,1)" "Lua53 auto JIT all test failed"
run_ravi_tests language ravi_tests1.ravi "ravi.jit(false)"
run_ravi_tests language ravi_tests1.ravi "ravi.auto(true,1)"
run_ravi_tests language defer_tests.ravi "ravi.jit(false)"
run_ravi_tests language defer_tests.ravi "ravi.auto(true,1)"
run_ravi_tests language ravi_tests3.ravi "ravi.auto(true,1)"
run_ravi_tests language ravi_errors.ravi "ravi.auto(true,1)"
run_ravi_tests language basics.lua "ravi.auto(true,1)"

Loading…
Cancel
Save