/* vim: ts=4 sw=4 sts=4 et tw=78 * * Copyright (c) 2011 James R. McKaskill * * This software is licensed under the stock MIT license: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * ---------------------------------------------------------------------------- */ #pragma once #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include #include #include #include #ifdef __cplusplus extern "C" { # include # include } # define EXTERN_C extern "C" #else # include # include # define EXTERN_C extern #endif #ifdef _WIN32 #include #else #include #include #include #include #endif #if __STDC_VERSION__+0 >= 199901L && !defined(__TINYC__) //< @r-lyeh: handle tcc case #include #define HAVE_COMPLEX #define HAVE_LONG_DOUBLE #endif #ifndef NDEBUG #define DASM_CHECKS #endif struct jit; #define Dst_DECL struct jit* Dst #define Dst_REF (Dst->ctx) #define DASM_EXTERN(a,b,c,d) get_extern(a,b,c,d) #include "dynasm/dasm_proto.h" #if defined LUA_FFI_BUILD_AS_DLL # define EXPORT __declspec(dllexport) #elif defined __GNUC__ # define EXPORT __attribute__((visibility("default"))) #else # define EXPORT #endif EXTERN_C EXPORT int luaopen_ffi(lua_State* L); static int lua_absindex2(lua_State* L, int idx) { return (LUA_REGISTRYINDEX <= idx && idx < 0) ? lua_gettop(L) + idx + 1 : idx; } /* use our own version of lua_absindex such that lua_absindex(L, 0) == 0 */ #define lua_absindex(L, idx) lua_absindex2(L, idx) #if LUA_VERSION_NUM == 501 static void lua_callk(lua_State *L, int nargs, int nresults, int ctx, lua_CFunction k) { lua_call(L, nargs, nresults); } /* ** set functions from list 'l' into table at top - 'nup'; each ** function gets the 'nup' elements at the top as upvalues. ** Returns with only the table at the stack. */ static void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { luaL_checkstack(L, nup, "too many upvalues"); for (; l && l->name; l++) { /* fill the table with given functions */ int i; for (i = 0; i < nup; i++) /* copy upvalues to the top */ lua_pushvalue(L, -nup); lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ lua_setfield(L, -(nup + 2), l->name); } lua_pop(L, nup); /* remove upvalues */ } #define lua_setuservalue lua_setfenv #define lua_getuservalue lua_getfenv #define lua_rawlen lua_objlen static char* luaL_prepbuffsize(luaL_Buffer* B, size_t sz) { if (sz > LUAL_BUFFERSIZE) { luaL_error(B->L, "string too long"); } return luaL_prepbuffer(B); } #endif /* architectures */ #if defined _WIN32 && defined UNDER_CE # define OS_CE #elif defined _WIN32 # define OS_WIN #elif defined __APPLE__ && defined __MACH__ # define OS_OSX #elif defined __linux__ # define OS_LINUX #elif defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__ # define OS_BSD #elif defined unix || defined __unix__ || defined __unix || defined _POSIX_VERSION || defined _XOPEN_VERSION # define OS_POSIX #endif /* architecture */ #if defined __i386__ || defined _M_IX86 # define ARCH_X86 #elif defined __amd64__ || defined _M_X64 # define ARCH_X64 #elif defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm # define ARCH_ARM #elif defined OS_LINUX && defined __TINYC__ //< @r-lyeh: tcc+linux # define ARCH_X64 //< @r-lyeh: tcc+linux #else # error #endif #ifdef _WIN32 # ifdef UNDER_CE static void* DoLoadLibraryA(const char* name) { wchar_t buf[MAX_PATH]; int sz = MultiByteToWideChar(CP_UTF8, 0, name, -1, buf, 512); if (sz > 0) { buf[sz] = 0; return LoadLibraryW(buf); } else { return NULL; } } # define LoadLibraryA DoLoadLibraryA # else # define GetProcAddressA GetProcAddress # endif # define LIB_FORMAT_1 "%s.dll" # define AllocPage(size) VirtualAlloc(NULL, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE) # define FreePage(data, size) VirtualFree(data, 0, MEM_RELEASE) # define EnableExecute(data, size) do {DWORD old; VirtualProtect(data, size, PAGE_EXECUTE, &old); FlushInstructionCache(GetCurrentProcess(), data, size);} while (0) # define EnableWrite(data, size) do {DWORD old; VirtualProtect(data, size, PAGE_READWRITE, &old);} while (0) #else # define LIB_FORMAT_1 "%s.so" # define LIB_FORMAT_2 "lib%s.so" # define LoadLibraryA(name) dlopen(name, RTLD_LAZY | RTLD_GLOBAL) # define GetProcAddressA(lib, name) dlsym(lib, name) # define AllocPage(size) mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0) # define FreePage(data, size) munmap(data, size) # define EnableExecute(data, size) mprotect(data, size, PROT_READ|PROT_EXEC) # define EnableWrite(data, size) mprotect(data, size, PROT_READ|PROT_WRITE) #endif #if defined ARCH_X86 || defined ARCH_X64 #define ALLOW_MISALIGNED_ACCESS #endif struct token; struct parser { int line; const char* next; const char* prev; unsigned align_mask; }; struct page { size_t size; size_t off; size_t freed; }; struct jit { lua_State* L; int32_t last_errno; dasm_State* ctx; size_t pagenum; struct page** pages; size_t align_page_size; void** globals; int function_extern; void* lua_dll; void* kernel32_dll; }; #define ALIGN_DOWN(PTR, MASK) \ (((uintptr_t) (PTR)) & (~ ((uintptr_t) (MASK)) )) #define ALIGN_UP(PTR, MASK) \ (( ((uintptr_t) (PTR)) + ((uintptr_t) (MASK)) ) & (~ ((uintptr_t) (MASK)) )) /* struct cdata/struct ctype */ #define PTR_ALIGN_MASK (sizeof(void*) - 1) #define FUNCTION_ALIGN_MASK (sizeof(void (*)()) - 1) #define DEFAULT_ALIGN_MASK 7 #ifdef OS_OSX /* TODO: figure out why the alignof trick doesn't work on OS X */ #define ALIGNED_DEFAULT 7 #elif defined __GNUC__ #define ALIGNED_DEFAULT (__alignof__(void* __attribute__((aligned))) - 1) #else #define ALIGNED_DEFAULT PTR_ALIGN_MASK #endif extern int jit_key; extern int ctype_mt_key; extern int cdata_mt_key; extern int cmodule_mt_key; extern int callback_mt_key; extern int constants_key; extern int types_key; extern int gc_key; extern int callbacks_key; extern int functions_key; extern int abi_key; extern int next_unnamed_key; extern int niluv_key; extern int asmname_key; int equals_upval(lua_State* L, int idx, int* key); void push_upval(lua_State* L, int* key); void set_upval(lua_State* L, int* key); struct jit* get_jit(lua_State* L); /* both ctype and cdata are stored as userdatas * * usr value is a table shared between the related subtypes which has: * name -> member ctype (for structs and unions) * +ves -> member ctype - in memory order (for structs) * +ves -> argument ctype (for function prototypes) * 0 -> return ctype (for function prototypes) * light userdata -> misc */ enum { C_CALL, STD_CALL, FAST_CALL, }; enum { INVALID_TYPE, VOID_TYPE, FLOAT_TYPE, DOUBLE_TYPE, LONG_DOUBLE_TYPE, COMPLEX_FLOAT_TYPE, COMPLEX_DOUBLE_TYPE, COMPLEX_LONG_DOUBLE_TYPE, BOOL_TYPE, INT8_TYPE, INT16_TYPE, INT32_TYPE, INT64_TYPE, INTPTR_TYPE, ENUM_TYPE, UNION_TYPE, STRUCT_TYPE, FUNCTION_TYPE, FUNCTION_PTR_TYPE, }; #define IS_CHAR_UNSIGNED (((char) -1) > 0) #define IS_COMPLEX(type) ((type) == COMPLEX_FLOAT_TYPE || (type) == COMPLEX_DOUBLE_TYPE) #define POINTER_BITS 2 #define POINTER_MAX ((1 << POINTER_BITS) - 1) #define ALIGNOF(S) ((int) ((char*) &S.v - (char*) &S - 1)) /* Note: if adding a new member that is associated with a struct/union * definition then it needs to be copied over in ctype.c:set_defined for when * we create types based off of the declaration alone. * * Since this is used as a header for every ctype and cdata, and we create a * ton of them on the stack, we try and minimise its size. */ struct ctype { size_t base_size; /* size of the base type in bytes */ union { /* valid if is_bitfield */ struct { /* size of bitfield in bits */ unsigned bit_size : 7; /* offset within the current byte between 0-63 */ unsigned bit_offset : 6; }; /* Valid if is_array */ size_t array_size; /* Valid for is_variable_struct or is_variable_array. If * variable_size_known (only used for is_variable_struct) then this is * the total increment otherwise this is the per element increment. */ size_t variable_increment; }; size_t offset; unsigned align_mask : 4; /* as (align bytes - 1) eg 7 gives 8 byte alignment */ unsigned pointers : POINTER_BITS; /* number of dereferences to get to the base type including +1 for arrays */ unsigned const_mask : POINTER_MAX + 1; /* const pointer mask, LSB is current pointer, +1 for the whether the base type is const */ unsigned type : 5; /* value given by type enum above */ unsigned is_reference : 1; unsigned is_array : 1; unsigned is_defined : 1; unsigned is_null : 1; unsigned has_member_name : 1; unsigned calling_convention : 2; unsigned has_var_arg : 1; unsigned is_variable_array : 1; /* set for variable array types where we don't know the variable size yet */ unsigned is_variable_struct : 1; unsigned variable_size_known : 1; /* used for variable structs after we know the variable size */ unsigned is_bitfield : 1; unsigned has_bitfield : 1; unsigned is_jitted : 1; unsigned is_packed : 1; unsigned is_unsigned : 1; }; #ifdef _MSC_VER __declspec(align(16)) #endif struct cdata { const struct ctype type #ifdef __GNUC__ __attribute__ ((aligned(16))) #endif ; }; typedef void (*cfunction)(void); #ifdef HAVE_COMPLEX typedef double complex complex_double; typedef float complex complex_float; #else typedef struct { double real, imag; } complex_double; typedef struct { float real, imag; } complex_float; static double creal(complex_double c) { return c.real; } static float crealf(complex_float c) { return c.real; } static double cimag(complex_double c) { return c.imag; } static float cimagf(complex_float c) { return c.imag; } #endif #define CALLBACK_FUNC_USR_IDX 1 void set_defined(lua_State* L, int ct_usr, struct ctype* ct); struct ctype* push_ctype(lua_State* L, int ct_usr, const struct ctype* ct); void* push_cdata(lua_State* L, int ct_usr, const struct ctype* ct); /* called from asm */ void push_callback(lua_State* L, cfunction f); void check_ctype(lua_State* L, int idx, struct ctype* ct); void* to_cdata(lua_State* L, int idx, struct ctype* ct); void* check_cdata(lua_State* L, int idx, struct ctype* ct); size_t ctype_size(lua_State* L, const struct ctype* ct); int parse_type(lua_State* L, struct parser* P, struct ctype* type); void parse_argument(lua_State* L, struct parser* P, int ct_usr, struct ctype* type, struct token* name, struct parser* asmname); void push_type_name(lua_State* L, int usr, const struct ctype* ct); int push_user_mt(lua_State* L, int ct_usr, const struct ctype* ct); int ffi_cdef(lua_State* L); void push_func_ref(lua_State* L, cfunction func); void free_code(struct jit* jit, lua_State* L, cfunction func); int x86_return_size(lua_State* L, int usr, const struct ctype* ct); void compile_function(lua_State* L, cfunction f, int ct_usr, const struct ctype* ct); cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctype* ct); void compile_globals(struct jit* jit, lua_State* L); int get_extern(struct jit* jit, uint8_t* addr, int idx, int type); /* WARNING: assembly needs to be updated for prototype changes of these functions */ int check_bool(lua_State* L, int idx); double check_double(lua_State* L, int idx); double check_complex_imag(lua_State* L, int idx); float check_float(lua_State* L, int idx); uint64_t check_uint64(lua_State* L, int idx); int64_t check_int64(lua_State* L, int idx); int32_t check_int32(lua_State* L, int idx); uint32_t check_uint32(lua_State* L, int idx); uintptr_t check_uintptr(lua_State* L, int idx); int32_t check_enum(lua_State* L, int idx, int to_usr, const struct ctype* tt); /* these two will always push a value so that we can create structs/functions on the fly */ void* check_typed_pointer(lua_State* L, int idx, int to_usr, const struct ctype* tt); cfunction check_typed_cfunction(lua_State* L, int idx, int to_usr, const struct ctype* tt); complex_double check_complex_double(lua_State* L, int idx); complex_float check_complex_float(lua_State* L, int idx); void unpack_varargs_stack(lua_State* L, int first, int last, char* to); void unpack_varargs_reg(lua_State* L, int first, int last, char* to); void unpack_varargs_stack_skip(lua_State* L, int first, int last, int ints_to_skip, int floats_to_skip, char* to); void unpack_varargs_float(lua_State* L, int first, int last, int max, char* to); void unpack_varargs_int(lua_State* L, int first, int last, int max, char* to);