parent
cc518ebf73
commit
e9abdb44ff
@ -0,0 +1,160 @@
|
||||
LLVM Notes
|
||||
==========
|
||||
|
||||
The notes below apply to LLVM 3.5.1 unless noted otherwise. All reflect my understanding - so if anything here is incorrect please log an issue and I will correct.
|
||||
|
||||
Structs and Unions
|
||||
------------------
|
||||
LLVM does not support defining union types so we need to basically use a ``struct`` of appropriate size and cast it as we need. The main thing to be careful about is to ensure that the ``struct`` is of the same size as the ``union``.
|
||||
|
||||
An example is::
|
||||
|
||||
///*
|
||||
//** Information about a call.
|
||||
//** When a thread yields, 'func' is adjusted to pretend that the
|
||||
//** top function has only the yielded values in its stack; in that
|
||||
//** case, the actual 'func' value is saved in field 'extra'.
|
||||
//** When a function calls another with a continuation, 'extra' keeps
|
||||
//** the function index so that, in case of errors, the continuation
|
||||
//** function can be called with the correct top.
|
||||
//*/
|
||||
// typedef struct CallInfo {
|
||||
// StkId func; /* function index in the stack */
|
||||
// StkId top; /* top for this function */
|
||||
// struct CallInfo *previous, *next; /* dynamic call link */
|
||||
// union {
|
||||
// struct { /* only for Lua functions */
|
||||
// StkId base; /* base for this function */
|
||||
// const Instruction *savedpc;
|
||||
// } l;
|
||||
// struct { /* only for C functions */
|
||||
// lua_KFunction k; /* continuation in case of yields */
|
||||
// ptrdiff_t old_errfunc;
|
||||
// lua_KContext ctx; /* context info. in case of yields */
|
||||
// } c;
|
||||
// } u;
|
||||
// ptrdiff_t extra;
|
||||
// short nresults; /* expected number of results from this function */
|
||||
// lu_byte callstatus;
|
||||
//} CallInfo;
|
||||
|
||||
Above the union ``u`` has two members of unequal size. To handle this I created the following two sub-types of equal size - note the extra dummy field in the first type::
|
||||
|
||||
|
||||
elements.clear();
|
||||
elements.push_back(StkIdT); /* base */
|
||||
elements.push_back(pInstructionT); /* savedpc */
|
||||
elements.push_back(
|
||||
C_ptrdiff_t); /* dummy to make this same size as the other member */
|
||||
CallInfo_lT = llvm::StructType::create(elements);
|
||||
|
||||
elements.clear();
|
||||
elements.push_back(plua_KFunctionT); /* k */
|
||||
elements.push_back(C_ptrdiff_t); /* old_errfunc */
|
||||
elements.push_back(lua_KContextT); /* ctx */
|
||||
CallInfo_cT = llvm::StructType::create(elements);
|
||||
|
||||
Then as I intend to use the ``u.l`` field more often, I used the following definition for ``CallInfo``::
|
||||
|
||||
CallInfoT = llvm::StructType::create(context, "ravi.CallInfo");
|
||||
pCallInfoT = llvm::PointerType::get(CallInfoT, 0);
|
||||
elements.clear();
|
||||
elements.push_back(StkIdT); /* func */
|
||||
elements.push_back(StkIdT); /* top */
|
||||
elements.push_back(pCallInfoT); /* previous */
|
||||
elements.push_back(pCallInfoT); /* next */
|
||||
elements.push_back(
|
||||
CallInfo_lT); /* u.l - as we will typically access the lua call details
|
||||
*/
|
||||
elements.push_back(C_ptrdiff_t); /* extra */
|
||||
elements.push_back(llvm::Type::getInt16Ty(context)); /* nresults */
|
||||
elements.push_back(lu_byteT); /* callstatus */
|
||||
CallInfoT->setBody(elements);
|
||||
|
||||
JIT Compilation Error on Windows
|
||||
--------------------------------
|
||||
On Windows when we attempt to JIT compile we get an error saying incompatible object format
|
||||
Reading posts on mailining lists I found that the issue is that COEFF
|
||||
format is not supported and therefore we need to set -elf as the object
|
||||
format::
|
||||
|
||||
#include "llvm/Support/Host.h"
|
||||
|
||||
/* some code */
|
||||
|
||||
#ifdef _WIN32
|
||||
auto triple = llvm::sys::getProcessTriple();
|
||||
module->setTargetTriple(triple + "-elf");
|
||||
#endif
|
||||
|
||||
Memory Management
|
||||
-----------------
|
||||
It appears that most things in LLVM are owned by the parent object and when the parent object is deleted the children go too. So in my code the main objects I delete are the ``ExecutionEngine`` and ``Module``. Once a module is associated with an engine then only the engine needs to be explicitly deleted is my understanding.
|
||||
|
||||
It doesn't help that the tutorial available does not attempt to delete objects / release memory!
|
||||
|
||||
MCJIT Engines, Modules and Functions
|
||||
------------------------------------
|
||||
Functions live inside Modules but once a Module is finalized (compiled) then no further functions can be added to it. Although an ``MCJIT`` instance (engine) can support multiples modules, the recommendation is to ensure each module is assigned its own engine. The rationale for this is not explained.
|
||||
|
||||
Struct Assign
|
||||
-------------
|
||||
My understanding is that to perform assignment of a struct value, one must call the intrinsic ``memcpy`` function. Example of code that does this::
|
||||
|
||||
llvm::Value *src;
|
||||
llvm::Value *dest;
|
||||
|
||||
// First get the declaration for the inttrinsic memcpy
|
||||
llvm::SmallVector<llvm::Type *, 3> vec;
|
||||
vec.push_back(def->types->C_pcharT); /* i8 */
|
||||
vec.push_back(def->types->C_pcharT); /* i8 */
|
||||
vec.push_back(def->types->C_intT);
|
||||
llvm::Function *f = llvm::Intrinsic::getDeclaration(
|
||||
def->raviF->module(), llvm::Intrinsic::memcpy, vec);
|
||||
lua_assert(f);
|
||||
|
||||
// Cast src and dest to i8*
|
||||
llvm::Value *dest_ptr =
|
||||
def->builder->CreateBitCast(dest, def->types->C_pcharT);
|
||||
llvm::Value *src_ptr = def->builder->CreateBitCast(src, def->types->C_pcharT);
|
||||
|
||||
// Create call to intrinsic memcpy
|
||||
values_.clear();
|
||||
values_.push_back(dest_ptr);
|
||||
values_.push_back(src_ptr);
|
||||
values_.push_back(llvm::ConstantInt::get(def->types->C_intT, sizeof(TValue)));
|
||||
values_.push_back(
|
||||
llvm::ConstantInt::get(def->types->C_intT, sizeof(L_Umaxalign)));
|
||||
values_.push_back(def->types->kFalse);
|
||||
def->builder->CreateCall(f, values_);
|
||||
|
||||
Note that the call to memcpy supply an alignment.
|
||||
|
||||
Accessing ``extern`` functions from JIT compiled code
|
||||
-----------------------------------------------------
|
||||
|
||||
If the JITed function needs to access ``extern`` functions that are statically linked and not exported as dynamic symbols (e.g. in Visual C++) then we need some extra steps.
|
||||
From reading posts on the subject it appears that the way to do this is to add a global mapping in the ``ExecutionEngine`` by calling the
|
||||
``addGlobalMapping()`` method. However this doesn't work with MCJIT due to a bug! So we need to use a workaround. Apparently there are two
|
||||
solutions:
|
||||
|
||||
* Create a custom memory manager that resolves the ``extern`` functions.
|
||||
* Add the symbol to the global symbols by calling ``llvm::sys::DynamicLibrary::AddSymbol()``.
|
||||
|
||||
I am using the latter approach for now.
|
||||
|
||||
GEP instruction
|
||||
---------------
|
||||
The GEP instruction cannot compute addresses of fields in a pointer member - as the pointer needs to be 'loaded' first. This is explained in the `GEP FAQ <http://llvm.org/docs/GetElementPtr.html#id6>`_.
|
||||
|
||||
|
||||
Links
|
||||
-----
|
||||
* `Mapping High Level Constructs to LLVM IR <http://llvm.lyngvig.org/Articles/Mapping-High-Level-Constructs-to-LLVM-IR>`_
|
||||
* `IRBuilder Sample <https://github.com/eliben/llvm-clang-samples/blob/master/src_llvm/experimental/build_llvm_ir.cpp>`_
|
||||
* `Using MCJIT with Kaleidoscope <http://blog.llvm.org/2013/07/using-mcjit-with-kaleidoscope-tutorial.html>`_
|
||||
* `Object format issue on Windows <http://lists.cs.uiuc.edu/pipermail/llvmdev/2013-December/068407.html>`_
|
||||
* `ExecutionEngine::addGlobalMapping() bug in MCJIT <http://llvm.org/bugs/show_bug.cgi?id=20656>`_
|
||||
* `LLVM Notes <http://nondot.org/sabre/LLVMNotes/>`_
|
||||
|
||||
|
@ -0,0 +1,162 @@
|
||||
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;
|
||||
L->top = ci->top;
|
||||
luaC_checkGC(L); /* stack grow uses memory */
|
||||
if (L->hookmask & LUA_MASKCALL)
|
||||
callhook(L, ci);
|
||||
if (p->ravi_jit.jit_status == 0) {
|
||||
/* not compiled */
|
||||
raviV_compile(L, p);
|
||||
}
|
||||
if (p->ravi_jit.jit_status == 2) {
|
||||
/* compiled */
|
||||
lua_assert(p->ravi_jit.jit_function != NULL);
|
||||
(*p->ravi_jit.jit_function)(L);
|
||||
lua_assert(L->ci == prevci);
|
||||
ci = L->ci;
|
||||
lua_assert(isLua(ci));
|
||||
lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
default: { /* not a function */
|
||||
|
||||
/* omitted */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Note that the above returns 1 if compiled function is called so that the behaviour in ``lvm.c`` is similar to that when a C function is called.
|
||||
|
@ -0,0 +1,707 @@
|
||||
Lua Types in LLVM
|
||||
=================
|
||||
|
||||
We need to map Lua types to equivalent type definitions in LLVM. In Ravi we do hold all the type definitions in a struct as shown below::
|
||||
|
||||
struct LuaLLVMTypes {
|
||||
|
||||
llvm::Type *C_intptr_t;
|
||||
llvm::Type *C_size_t;
|
||||
llvm::Type *C_ptrdiff_t;
|
||||
|
||||
llvm::Type *lua_NumberT;
|
||||
llvm::Type *lua_IntegerT;
|
||||
llvm::Type *lua_UnsignedT;
|
||||
llvm::Type *lua_KContextT;
|
||||
|
||||
llvm::FunctionType *lua_CFunctionT;
|
||||
llvm::PointerType *plua_CFunctionT;
|
||||
|
||||
llvm::FunctionType *lua_KFunctionT;
|
||||
llvm::PointerType *plua_KFunctionT;
|
||||
|
||||
llvm::FunctionType *lua_HookT;
|
||||
llvm::PointerType *plua_HookT;
|
||||
|
||||
llvm::FunctionType *lua_AllocT;
|
||||
llvm::PointerType *plua_AllocT;
|
||||
|
||||
llvm::Type *l_memT;
|
||||
llvm::Type *lu_memT;
|
||||
|
||||
llvm::Type *lu_byteT;
|
||||
llvm::Type *L_UmaxalignT;
|
||||
llvm::Type *C_pcharT;
|
||||
|
||||
llvm::Type *C_intT;
|
||||
|
||||
llvm::StructType *lua_StateT;
|
||||
llvm::PointerType *plua_StateT;
|
||||
|
||||
llvm::StructType *global_StateT;
|
||||
llvm::PointerType *pglobal_StateT;
|
||||
|
||||
llvm::StructType *ravi_StateT;
|
||||
llvm::PointerType *pravi_StateT;
|
||||
|
||||
llvm::StructType *GCObjectT;
|
||||
llvm::PointerType *pGCObjectT;
|
||||
|
||||
llvm::StructType *ValueT;
|
||||
llvm::StructType *TValueT;
|
||||
llvm::PointerType *pTValueT;
|
||||
|
||||
llvm::StructType *TStringT;
|
||||
llvm::PointerType *pTStringT;
|
||||
llvm::PointerType *ppTStringT;
|
||||
|
||||
llvm::StructType *UdataT;
|
||||
llvm::StructType *TableT;
|
||||
llvm::PointerType *pTableT;
|
||||
|
||||
llvm::StructType *UpvaldescT;
|
||||
llvm::PointerType *pUpvaldescT;
|
||||
|
||||
llvm::Type *ravitype_tT;
|
||||
llvm::StructType *LocVarT;
|
||||
llvm::PointerType *pLocVarT;
|
||||
|
||||
llvm::Type *InstructionT;
|
||||
llvm::PointerType *pInstructionT;
|
||||
llvm::StructType *LClosureT;
|
||||
llvm::PointerType *pLClosureT;
|
||||
llvm::PointerType *ppLClosureT;
|
||||
llvm::PointerType *pppLClosureT;
|
||||
|
||||
llvm::StructType *RaviJITProtoT;
|
||||
llvm::PointerType *pRaviJITProtoT;
|
||||
|
||||
llvm::StructType *ProtoT;
|
||||
llvm::PointerType *pProtoT;
|
||||
llvm::PointerType *ppProtoT;
|
||||
|
||||
llvm::StructType *UpValT;
|
||||
llvm::PointerType *pUpValT;
|
||||
|
||||
llvm::StructType *CClosureT;
|
||||
llvm::PointerType *pCClosureT;
|
||||
|
||||
llvm::StructType *TKeyT;
|
||||
llvm::PointerType *pTKeyT;
|
||||
|
||||
llvm::StructType *NodeT;
|
||||
llvm::PointerType *pNodeT;
|
||||
|
||||
llvm::StructType *lua_DebugT;
|
||||
llvm::PointerType *plua_DebugT;
|
||||
|
||||
llvm::StructType *lua_longjumpT;
|
||||
llvm::PointerType *plua_longjumpT;
|
||||
|
||||
llvm::StructType *MbufferT;
|
||||
llvm::StructType *stringtableT;
|
||||
|
||||
llvm::PointerType *StkIdT;
|
||||
|
||||
llvm::StructType *CallInfoT;
|
||||
llvm::StructType *CallInfo_cT;
|
||||
llvm::StructType *CallInfo_lT;
|
||||
llvm::PointerType *pCallInfoT;
|
||||
|
||||
llvm::FunctionType *jitFunctionT;
|
||||
|
||||
llvm::FunctionType *luaD_poscallT;
|
||||
|
||||
};
|
||||
|
||||
The actual definition of the types above is shown below::
|
||||
|
||||
static_assert(std::is_floating_point<lua_Number>::value &&
|
||||
sizeof(lua_Number) == sizeof(double),
|
||||
"lua_Number is not a double");
|
||||
lua_NumberT = llvm::Type::getDoubleTy(context);
|
||||
|
||||
static_assert(std::is_integral<lua_Integer>::value,
|
||||
"lua_Integer is not an integer type");
|
||||
lua_IntegerT = llvm::Type::getIntNTy(context, sizeof(lua_Integer) * 8);
|
||||
|
||||
static_assert(sizeof(lua_Integer) == sizeof(lua_Unsigned),
|
||||
"lua_Integer and lua_Unsigned are of different size");
|
||||
lua_UnsignedT = lua_IntegerT;
|
||||
|
||||
C_intptr_t = llvm::Type::getIntNTy(context, sizeof(intptr_t) * 8);
|
||||
C_size_t = llvm::Type::getIntNTy(context, sizeof(size_t) * 8);
|
||||
C_ptrdiff_t = llvm::Type::getIntNTy(context, sizeof(ptrdiff_t) * 8);
|
||||
C_intT = llvm::Type::getIntNTy(context, sizeof(int) * 8);
|
||||
|
||||
static_assert(sizeof(size_t) == sizeof(lu_mem),
|
||||
"lu_mem size is not same as size_t");
|
||||
lu_memT = C_size_t;
|
||||
|
||||
static_assert(sizeof(ptrdiff_t) == sizeof(l_mem),
|
||||
"l_mem size is not same as ptrdiff_t");
|
||||
l_memT = C_ptrdiff_t;
|
||||
|
||||
static_assert(sizeof(L_Umaxalign) == sizeof(double),
|
||||
"L_Umaxalign is not same size as double");
|
||||
L_UmaxalignT = llvm::Type::getDoubleTy(context);
|
||||
|
||||
lu_byteT = llvm::Type::getInt8Ty(context);
|
||||
C_pcharT = llvm::Type::getInt8PtrTy(context);
|
||||
|
||||
InstructionT = C_intT;
|
||||
pInstructionT = llvm::PointerType::get(InstructionT, 0);
|
||||
|
||||
lua_StateT = llvm::StructType::create(context, "ravi.lua_State");
|
||||
plua_StateT = llvm::PointerType::get(lua_StateT, 0);
|
||||
|
||||
lua_KContextT = C_ptrdiff_t;
|
||||
|
||||
std::vector<llvm::Type *> elements;
|
||||
elements.push_back(plua_StateT);
|
||||
lua_CFunctionT = llvm::FunctionType::get(C_intT, elements, false);
|
||||
plua_CFunctionT = llvm::PointerType::get(lua_CFunctionT, 0);
|
||||
|
||||
jitFunctionT = lua_CFunctionT;
|
||||
|
||||
elements.clear();
|
||||
elements.push_back(plua_StateT);
|
||||
elements.push_back(C_intT);
|
||||
elements.push_back(lua_KContextT);
|
||||
lua_KFunctionT = llvm::FunctionType::get(C_intT, elements, false);
|
||||
plua_KFunctionT = llvm::PointerType::get(lua_KFunctionT, 0);
|
||||
|
||||
elements.clear();
|
||||
elements.push_back(llvm::Type::getInt8PtrTy(context));
|
||||
elements.push_back(llvm::Type::getInt8PtrTy(context));
|
||||
elements.push_back(C_size_t);
|
||||
elements.push_back(C_size_t);
|
||||
lua_AllocT = llvm::FunctionType::get(llvm::Type::getInt8PtrTy(context),
|
||||
elements, false);
|
||||
plua_AllocT = llvm::PointerType::get(lua_AllocT, 0);
|
||||
|
||||
lua_DebugT = llvm::StructType::create(context, "ravi.lua_Debug");
|
||||
plua_DebugT = llvm::PointerType::get(lua_DebugT, 0);
|
||||
|
||||
elements.clear();
|
||||
elements.push_back(plua_StateT);
|
||||
elements.push_back(plua_DebugT);
|
||||
lua_HookT = llvm::FunctionType::get(llvm::Type::getInt8PtrTy(context),
|
||||
elements, false);
|
||||
plua_HookT = llvm::PointerType::get(lua_HookT, 0);
|
||||
|
||||
// struct GCObject {
|
||||
// GCObject *next;
|
||||
// lu_byte tt;
|
||||
// lu_byte marked
|
||||
// };
|
||||
GCObjectT = llvm::StructType::create(context, "ravi.GCObject");
|
||||
pGCObjectT = llvm::PointerType::get(GCObjectT, 0);
|
||||
elements.clear();
|
||||
elements.push_back(pGCObjectT);
|
||||
elements.push_back(lu_byteT);
|
||||
elements.push_back(lu_byteT);
|
||||
GCObjectT->setBody(elements);
|
||||
|
||||
static_assert(sizeof(Value) == sizeof(lua_Number),
|
||||
"Value type is larger than lua_Number");
|
||||
// In LLVM unions should be set to the largest member
|
||||
// So in the case of a Value this is the double type
|
||||
// union Value {
|
||||
// GCObject *gc; /* collectable objects */
|
||||
// void *p; /* light userdata */
|
||||
// int b; /* booleans */
|
||||
// lua_CFunction f; /* light C functions */
|
||||
// lua_Integer i; /* integer numbers */
|
||||
// lua_Number n; /* float numbers */
|
||||
// };
|
||||
ValueT = llvm::StructType::create(context, "ravi.Value");
|
||||
elements.clear();
|
||||
elements.push_back(lua_NumberT);
|
||||
ValueT->setBody(elements);
|
||||
|
||||
// struct TValue {
|
||||
// union Value value_;
|
||||
// int tt_;
|
||||
// };
|
||||
TValueT = llvm::StructType::create(context, "ravi.TValue");
|
||||
elements.clear();
|
||||
elements.push_back(ValueT);
|
||||
elements.push_back(C_intT);
|
||||
TValueT->setBody(elements);
|
||||
pTValueT = llvm::PointerType::get(TValueT, 0);
|
||||
|
||||
StkIdT = pTValueT;
|
||||
|
||||
///*
|
||||
//** Header for string value; string bytes follow the end of this structure
|
||||
//** (aligned according to 'UTString'; see next).
|
||||
//*/
|
||||
// typedef struct TString {
|
||||
// GCObject *next;
|
||||
// lu_byte tt;
|
||||
// lu_byte marked
|
||||
// lu_byte extra; /* reserved words for short strings; "has hash" for longs
|
||||
// */
|
||||
// unsigned int hash;
|
||||
// size_t len; /* number of characters in string */
|
||||
// struct TString *hnext; /* linked list for hash table */
|
||||
// } TString;
|
||||
|
||||
///*
|
||||
//** Ensures that address after this type is always fully aligned.
|
||||
//*/
|
||||
// typedef union UTString {
|
||||
// L_Umaxalign dummy; /* ensures maximum alignment for strings */
|
||||
// TString tsv;
|
||||
//} UTString;
|
||||
TStringT = llvm::StructType::create(context, "ravi.TString");
|
||||
pTStringT = llvm::PointerType::get(TStringT, 0);
|
||||
ppTStringT = llvm::PointerType::get(pTStringT, 0);
|
||||
elements.clear();
|
||||
elements.push_back(pGCObjectT);
|
||||
elements.push_back(lu_byteT);
|
||||
elements.push_back(lu_byteT);
|
||||
elements.push_back(lu_byteT); /* extra */
|
||||
elements.push_back(C_intT); /* hash */
|
||||
elements.push_back(C_size_t); /* len */
|
||||
elements.push_back(pTStringT); /* hnext */
|
||||
TStringT->setBody(elements);
|
||||
|
||||
// Table
|
||||
TableT = llvm::StructType::create(context, "ravi.Table");
|
||||
pTableT = llvm::PointerType::get(TableT, 0);
|
||||
|
||||
///*
|
||||
//** Header for userdata; memory area follows the end of this structure
|
||||
//** (aligned according to 'UUdata'; see next).
|
||||
//*/
|
||||
// typedef struct Udata {
|
||||
// GCObject *next;
|
||||
// lu_byte tt;
|
||||
// lu_byte marked
|
||||
// lu_byte ttuv_; /* user value's tag */
|
||||
// struct Table *metatable;
|
||||
// size_t len; /* number of bytes */
|
||||
// union Value user_; /* user value */
|
||||
//} Udata;
|
||||
UdataT = llvm::StructType::create(context, "ravi.Udata");
|
||||
elements.clear();
|
||||
elements.push_back(pGCObjectT);
|
||||
elements.push_back(lu_byteT);
|
||||
elements.push_back(lu_byteT);
|
||||
elements.push_back(lu_byteT); /* ttuv_ */
|
||||
elements.push_back(pTableT); /* metatable */
|
||||
elements.push_back(C_size_t); /* len */
|
||||
elements.push_back(ValueT); /* user_ */
|
||||
UdataT->setBody(elements);
|
||||
|
||||
///*
|
||||
//** Description of an upvalue for function prototypes
|
||||
//*/
|
||||
// typedef struct Upvaldesc {
|
||||
// TString *name; /* upvalue name (for debug information) */
|
||||
// lu_byte instack; /* whether it is in stack */
|
||||
// lu_byte idx; /* index of upvalue (in stack or in outer function's list)
|
||||
// */
|
||||
//}Upvaldesc;
|
||||
UpvaldescT = llvm::StructType::create(context, "ravi.Upvaldesc");
|
||||
elements.clear();
|
||||
elements.push_back(pTStringT);
|
||||
elements.push_back(lu_byteT);
|
||||
elements.push_back(lu_byteT);
|
||||
UpvaldescT->setBody(elements);
|
||||
pUpvaldescT = llvm::PointerType::get(UpvaldescT, 0);
|
||||
|
||||
///*
|
||||
//** Description of a local variable for function prototypes
|
||||
//** (used for debug information)
|
||||
//*/
|
||||
// typedef struct LocVar {
|
||||
// TString *varname;
|
||||
// int startpc; /* first point where variable is active */
|
||||
// int endpc; /* first point where variable is dead */
|
||||
// ravitype_t ravi_type; /* RAVI type of the variable - RAVI_TANY if unknown
|
||||
// */
|
||||
//} LocVar;
|
||||
ravitype_tT = llvm::Type::getIntNTy(context, sizeof(ravitype_t) * 8);
|
||||
LocVarT = llvm::StructType::create(context, "ravi.LocVar");
|
||||
elements.clear();
|
||||
elements.push_back(pTStringT); /* varname */
|
||||
elements.push_back(C_intT); /* startpc */
|
||||
elements.push_back(C_intT); /* endpc */
|
||||
elements.push_back(ravitype_tT); /* ravi_type */
|
||||
LocVarT->setBody(elements);
|
||||
pLocVarT = llvm::PointerType::get(LocVarT, 0);
|
||||
|
||||
LClosureT = llvm::StructType::create(context, "ravi.LClosure");
|
||||
pLClosureT = llvm::PointerType::get(LClosureT, 0);
|
||||
ppLClosureT = llvm::PointerType::get(pLClosureT, 0);
|
||||
pppLClosureT = llvm::PointerType::get(ppLClosureT, 0);
|
||||
|
||||
RaviJITProtoT = llvm::StructType::create(context, "ravi.RaviJITProto");
|
||||
pRaviJITProtoT = llvm::PointerType::get(RaviJITProtoT, 0);
|
||||
|
||||
///*
|
||||
//** 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;
|
||||
|
||||
ProtoT = llvm::StructType::create(context, "ravi.Proto");
|
||||
pProtoT = llvm::PointerType::get(ProtoT, 0);
|
||||
ppProtoT = llvm::PointerType::get(pProtoT, 0);
|
||||
elements.clear();
|
||||
elements.push_back(pGCObjectT);
|
||||
elements.push_back(lu_byteT);
|
||||
elements.push_back(lu_byteT);
|
||||
elements.push_back(lu_byteT); /* numparams */
|
||||
elements.push_back(lu_byteT); /* is_vararg */
|
||||
elements.push_back(lu_byteT); /* maxstacksize */
|
||||
elements.push_back(C_intT); /* sizeupvalues */
|
||||
elements.push_back(C_intT); /* sizek */
|
||||
elements.push_back(C_intT); /* sizecode */
|
||||
elements.push_back(C_intT); /* sizelineinfo */
|
||||
elements.push_back(C_intT); /* sizep */
|
||||
elements.push_back(C_intT); /* sizelocvars */
|
||||
elements.push_back(C_intT); /* linedefined */
|
||||
elements.push_back(C_intT); /* lastlinedefined */
|
||||
elements.push_back(pTValueT); /* k */
|
||||
elements.push_back(pInstructionT); /* code */
|
||||
elements.push_back(ppProtoT); /* p */
|
||||
elements.push_back(llvm::PointerType::get(C_intT, 0)); /* lineinfo */
|
||||
elements.push_back(pLocVarT); /* locvars */
|
||||
elements.push_back(pUpvaldescT); /* upvalues */
|
||||
elements.push_back(pLClosureT); /* cache */
|
||||
elements.push_back(pTStringT); /* source */
|
||||
elements.push_back(pGCObjectT); /* gclist */
|
||||
elements.push_back(pRaviJITProtoT); /* ravi_jit */
|
||||
ProtoT->setBody(elements);
|
||||
|
||||
///*
|
||||
//** Lua Upvalues
|
||||
//*/
|
||||
// typedef struct UpVal UpVal;
|
||||
UpValT = llvm::StructType::create(context, "ravi.UpVal");
|
||||
pUpValT = llvm::PointerType::get(UpValT, 0);
|
||||
|
||||
///*
|
||||
//** Closures
|
||||
//*/
|
||||
|
||||
//#define ClosureHeader \
|
||||
//CommonHeader; lu_byte nupvalues; GCObject *gclist
|
||||
|
||||
// typedef struct CClosure {
|
||||
// ClosureHeader;
|
||||
// lua_CFunction f;
|
||||
// TValue upvalue[1]; /* list of upvalues */
|
||||
//} CClosure;
|
||||
|
||||
CClosureT = llvm::StructType::create(context, "ravi.CClosure");
|
||||
elements.clear();
|
||||
elements.push_back(pGCObjectT);
|
||||
elements.push_back(lu_byteT);
|
||||
elements.push_back(lu_byteT);
|
||||
elements.push_back(lu_byteT); /* nupvalues */
|
||||
elements.push_back(pGCObjectT); /* gclist */
|
||||
elements.push_back(plua_CFunctionT); /* f */
|
||||
elements.push_back(llvm::ArrayType::get(TValueT, 1));
|
||||
CClosureT->setBody(elements);
|
||||
pCClosureT = llvm::PointerType::get(CClosureT, 0);
|
||||
|
||||
// typedef struct LClosure {
|
||||
// ClosureHeader;
|
||||
// struct Proto *p;
|
||||
// UpVal *upvals[1]; /* list of upvalues */
|
||||
//} LClosure;
|
||||
elements.clear();
|
||||
elements.push_back(pGCObjectT);
|
||||
elements.push_back(lu_byteT);
|
||||
elements.push_back(lu_byteT);
|
||||
elements.push_back(lu_byteT); /* nupvalues */
|
||||
elements.push_back(pGCObjectT); /* gclist */
|
||||
elements.push_back(pProtoT); /* p */
|
||||
elements.push_back(llvm::ArrayType::get(pUpValT, 1));
|
||||
LClosureT->setBody(elements);
|
||||
|
||||
///*
|
||||
//** Tables
|
||||
//*/
|
||||
|
||||
// typedef union TKey {
|
||||
// struct {
|
||||
// TValuefields;
|
||||
// int next; /* for chaining (offset for next node) */
|
||||
// } nk;
|
||||
// TValue tvk;
|
||||
//} TKey;
|
||||
TKeyT = llvm::StructType::create(context, "ravi.TKey");
|
||||
elements.clear();
|
||||
elements.push_back(ValueT);
|
||||
elements.push_back(C_intT);
|
||||
elements.push_back(C_intT); /* next */
|
||||
TKeyT->setBody(elements);
|
||||
pTKeyT = llvm::PointerType::get(TKeyT, 0);
|
||||
|
||||
// typedef struct Node {
|
||||
// TValue i_val;
|
||||
// TKey i_key;
|
||||
//} Node;
|
||||
NodeT = llvm::StructType::create(context, "ravi.Node");
|
||||
elements.clear();
|
||||
elements.push_back(TValueT); /* i_val */
|
||||
elements.push_back(TKeyT); /* i_key */
|
||||
NodeT->setBody(elements);
|
||||
pNodeT = llvm::PointerType::get(NodeT, 0);
|
||||
|
||||
// typedef struct Table {
|
||||
// CommonHeader;
|
||||
// lu_byte flags; /* 1<<p means tagmethod(p) is not present */
|
||||
// lu_byte lsizenode; /* log2 of size of 'node' array */
|
||||
// unsigned int sizearray; /* size of 'array' array */
|
||||
// TValue *array; /* array part */
|
||||
// Node *node;
|
||||
// Node *lastfree; /* any free position is before this position */
|
||||
// struct Table *metatable;
|
||||
// GCObject *gclist;
|
||||
// ravitype_t ravi_array_type; /* RAVI specialization */
|
||||
// unsigned int ravi_array_len; /* RAVI len specialization */
|
||||
//} Table;
|
||||
elements.clear();
|
||||
elements.push_back(pGCObjectT);
|
||||
elements.push_back(lu_byteT);
|
||||
elements.push_back(lu_byteT);
|
||||
elements.push_back(lu_byteT); /* flags */
|
||||
elements.push_back(lu_byteT); /* lsizenode */
|
||||
elements.push_back(C_intT); /* sizearray */
|
||||
elements.push_back(pTValueT); /* array part */
|
||||
elements.push_back(pNodeT); /* node */
|
||||
elements.push_back(pNodeT); /* lastfree */
|
||||
elements.push_back(pTableT); /* metatable */
|
||||
elements.push_back(pGCObjectT); /* gclist */
|
||||
elements.push_back(ravitype_tT); /* ravi_array_type */
|
||||
elements.push_back(C_intT); /* ravi_array_len */
|
||||
TableT->setBody(elements);
|
||||
|
||||
// struct lua_longjmp; /* defined in ldo.c */
|
||||
lua_longjumpT = llvm::StructType::create(context, "ravi.lua_longjmp");
|
||||
plua_longjumpT = llvm::PointerType::get(lua_longjumpT, 0);
|
||||
|
||||
// lzio.h
|
||||
// typedef struct Mbuffer {
|
||||
// char *buffer;
|
||||
// size_t n;
|
||||
// size_t buffsize;
|
||||
//} Mbuffer;
|
||||
MbufferT = llvm::StructType::create(context, "ravi.Mbuffer");
|
||||
elements.clear();
|
||||
elements.push_back(llvm::Type::getInt8PtrTy(context)); /* buffer */
|
||||
elements.push_back(C_size_t); /* n */
|
||||
elements.push_back(C_size_t); /* buffsize */
|
||||
MbufferT->setBody(elements);
|
||||
|
||||
// typedef struct stringtable {
|
||||
// TString **hash;
|
||||
// int nuse; /* number of elements */
|
||||
// int size;
|
||||
//} stringtable;
|
||||
stringtableT = llvm::StructType::create(context, "ravi.stringtable");
|
||||
elements.clear();
|
||||
elements.push_back(ppTStringT); /* hash */
|
||||
elements.push_back(C_intT); /* nuse */
|
||||
elements.push_back(C_intT); /* size */
|
||||
stringtableT->setBody(elements);
|
||||
|
||||
///*
|
||||
//** Information about a call.
|
||||
//** When a thread yields, 'func' is adjusted to pretend that the
|
||||
//** top function has only the yielded values in its stack; in that
|
||||
//** case, the actual 'func' value is saved in field 'extra'.
|
||||
//** When a function calls another with a continuation, 'extra' keeps
|
||||
//** the function index so that, in case of errors, the continuation
|
||||
//** function can be called with the correct top.
|
||||
//*/
|
||||
// typedef struct CallInfo {
|
||||
// StkId func; /* function index in the stack */
|
||||
// StkId top; /* top for this function */
|
||||
// struct CallInfo *previous, *next; /* dynamic call link */
|
||||
// union {
|
||||
// struct { /* only for Lua functions */
|
||||
// StkId base; /* base for this function */
|
||||
// const Instruction *savedpc;
|
||||
// } l;
|
||||
// struct { /* only for C functions */
|
||||
// lua_KFunction k; /* continuation in case of yields */
|
||||
// ptrdiff_t old_errfunc;
|
||||
// lua_KContext ctx; /* context info. in case of yields */
|
||||
// } c;
|
||||
// } u;
|
||||
// ptrdiff_t extra;
|
||||
// short nresults; /* expected number of results from this function */
|
||||
// lu_byte callstatus;
|
||||
//} CallInfo;
|
||||
|
||||
elements.clear();
|
||||
elements.push_back(StkIdT); /* base */
|
||||
elements.push_back(pInstructionT); /* savedpc */
|
||||
elements.push_back(
|
||||
C_ptrdiff_t); /* dummy to make this same size as the other member */
|
||||
CallInfo_lT = llvm::StructType::create(elements);
|
||||
|
||||
elements.clear();
|
||||
elements.push_back(plua_KFunctionT); /* k */
|
||||
elements.push_back(C_ptrdiff_t); /* old_errfunc */
|
||||
elements.push_back(lua_KContextT); /* ctx */
|
||||
CallInfo_cT = llvm::StructType::create(elements);
|
||||
|
||||
CallInfoT = llvm::StructType::create(context, "ravi.CallInfo");
|
||||
pCallInfoT = llvm::PointerType::get(CallInfoT, 0);
|
||||
elements.clear();
|
||||
elements.push_back(StkIdT); /* func */
|
||||
elements.push_back(StkIdT); /* top */
|
||||
elements.push_back(pCallInfoT); /* previous */
|
||||
elements.push_back(pCallInfoT); /* next */
|
||||
elements.push_back(
|
||||
CallInfo_lT); /* u.l - as we will typically access the lua call details
|
||||
*/
|
||||
elements.push_back(C_ptrdiff_t); /* extra */
|
||||
elements.push_back(llvm::Type::getInt16Ty(context)); /* nresults */
|
||||
elements.push_back(lu_byteT); /* callstatus */
|
||||
CallInfoT->setBody(elements);
|
||||
|
||||
// typedef struct ravi_State ravi_State;
|
||||
|
||||
ravi_StateT = llvm::StructType::create(context, "ravi.ravi_State");
|
||||
pravi_StateT = llvm::PointerType::get(ravi_StateT, 0);
|
||||
|
||||
///*
|
||||
//** 'global state', shared by all threads of this state
|
||||
//*/
|
||||
// typedef struct global_State {
|
||||
// lua_Alloc frealloc; /* function to reallocate memory */
|
||||
// void *ud; /* auxiliary data to 'frealloc' */
|
||||
// lu_mem totalbytes; /* number of bytes currently allocated - GCdebt */
|
||||
// l_mem GCdebt; /* bytes allocated not yet compensated by the collector */
|
||||
// lu_mem GCmemtrav; /* memory traversed by the GC */
|
||||
// lu_mem GCestimate; /* an estimate of the non-garbage memory in use */
|
||||
// stringtable strt; /* hash table for strings */
|
||||
// TValue l_registry;
|
||||
// unsigned int seed; /* randomized seed for hashes */
|
||||
// lu_byte currentwhite;
|
||||
// lu_byte gcstate; /* state of garbage collector */
|
||||
// lu_byte gckind; /* kind of GC running */
|
||||
// lu_byte gcrunning; /* true if GC is running */
|
||||
// GCObject *allgc; /* list of all collectable objects */
|
||||
// GCObject **sweepgc; /* current position of sweep in list */
|
||||
// GCObject *finobj; /* list of collectable objects with finalizers */
|
||||
// GCObject *gray; /* list of gray objects */
|
||||
// GCObject *grayagain; /* list of objects to be traversed atomically */
|
||||
// GCObject *weak; /* list of tables with weak values */
|
||||
// GCObject *ephemeron; /* list of ephemeron tables (weak keys) */
|
||||
// GCObject *allweak; /* list of all-weak tables */
|
||||
// GCObject *tobefnz; /* list of userdata to be GC */
|
||||
// GCObject *fixedgc; /* list of objects not to be collected */
|
||||
// struct lua_State *twups; /* list of threads with open upvalues */
|
||||
// Mbuffer buff; /* temporary buffer for string concatenation */
|
||||
// unsigned int gcfinnum; /* number of finalizers to call in each GC step */
|
||||
// int gcpause; /* size of pause between successive GCs */
|
||||
// int gcstepmul; /* GC 'granularity' */
|
||||
// lua_CFunction panic; /* to be called in unprotected errors */
|
||||
// struct lua_State *mainthread;
|
||||
// const lua_Number *version; /* pointer to version number */
|
||||
// TString *memerrmsg; /* memory-error message */
|
||||
// TString *tmname[TM_N]; /* array with tag-method names */
|
||||
// struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
|
||||
// /* RAVI */
|
||||
// ravi_State *ravi_state;
|
||||
//} global_State;
|
||||
|
||||
global_StateT = llvm::StructType::create(context, "ravi.global_State");
|
||||
pglobal_StateT = llvm::PointerType::get(global_StateT, 0);
|
||||
|
||||
///*
|
||||
//** 'per thread' state
|
||||
//*/
|
||||
// struct lua_State {
|
||||
// CommonHeader;
|
||||
// lu_byte status;
|
||||
// StkId top; /* first free slot in the stack */
|
||||
// global_State *l_G;
|
||||
// CallInfo *ci; /* call info for current function */
|
||||
// const Instruction *oldpc; /* last pc traced */
|
||||
// StkId stack_last; /* last free slot in the stack */
|
||||
// StkId stack; /* stack base */
|
||||
// UpVal *openupval; /* list of open upvalues in this stack */
|
||||
// GCObject *gclist;
|
||||
// struct lua_State *twups; /* list of threads with open upvalues */
|
||||
// struct lua_longjmp *errorJmp; /* current error recover point */
|
||||
// CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
|
||||
// lua_Hook hook;
|
||||
// ptrdiff_t errfunc; /* current error handling function (stack index) */
|
||||
// int stacksize;
|
||||
// int basehookcount;
|
||||
// int hookcount;
|
||||
// unsigned short nny; /* number of non-yieldable calls in stack */
|
||||
// unsigned short nCcalls; /* number of nested C calls */
|
||||
// lu_byte hookmask;
|
||||
// lu_byte allowhook;
|
||||
//};
|
||||
elements.clear();
|
||||
elements.push_back(pGCObjectT);
|
||||
elements.push_back(lu_byteT);
|
||||
elements.push_back(lu_byteT);
|
||||
elements.push_back(lu_byteT); /* status */
|
||||
elements.push_back(StkIdT); /* top */
|
||||
elements.push_back(pglobal_StateT); /* l_G */
|
||||
elements.push_back(pCallInfoT); /* ci */
|
||||
elements.push_back(pInstructionT); /* oldpc */
|
||||
elements.push_back(StkIdT); /* stack_last */
|
||||
elements.push_back(StkIdT); /* stack */
|
||||
elements.push_back(pUpValT); /* openupval */
|
||||
elements.push_back(pGCObjectT); /* gclist */
|
||||
elements.push_back(plua_StateT); /* twups */
|
||||
elements.push_back(plua_longjumpT); /* errorJmp */
|
||||
elements.push_back(CallInfoT); /* base_ci */
|
||||
elements.push_back(plua_HookT); /* hook */
|
||||
elements.push_back(C_ptrdiff_t); /* errfunc */
|
||||
elements.push_back(C_intT); /* stacksize */
|
||||
elements.push_back(C_intT); /* basehookcount */
|
||||
elements.push_back(C_intT); /* hookcount */
|
||||
elements.push_back(llvm::Type::getInt16Ty(context)); /* nny */
|
||||
elements.push_back(llvm::Type::getInt16Ty(context)); /* nCcalls */
|
||||
elements.push_back(lu_byteT); /* hookmask */
|
||||
elements.push_back(lu_byteT); /* allowhook */
|
||||
lua_StateT->setBody(elements);
|
||||
|
||||
// int luaD_poscall (lua_State *L, StkId firstResult)
|
||||
elements.clear();
|
||||
elements.push_back(plua_StateT);
|
||||
elements.push_back(StkIdT);
|
||||
luaD_poscallT = llvm::FunctionType::get(C_intT, elements, false);
|
||||
|
||||
|
Loading…
Reference in new issue