From 6523585c66c04cea54df50013df8886b589847d8 Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Mon, 23 Jan 2012 23:36:30 +1000 Subject: Add luaproc and LuaJIT libraries. Two versions of LuaJIT, the stable release, and the dev version. Try the dev version first, until ih fails badly. --- libraries/LuaJIT-1.1.7/src/ljit_mem.c | 405 ++++++++++++++++++++++++++++++++++ 1 file changed, 405 insertions(+) create mode 100644 libraries/LuaJIT-1.1.7/src/ljit_mem.c (limited to 'libraries/LuaJIT-1.1.7/src/ljit_mem.c') diff --git a/libraries/LuaJIT-1.1.7/src/ljit_mem.c b/libraries/LuaJIT-1.1.7/src/ljit_mem.c new file mode 100644 index 0000000..73ade7f --- /dev/null +++ b/libraries/LuaJIT-1.1.7/src/ljit_mem.c @@ -0,0 +1,405 @@ +/* +** Memory management for machine code. +** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h +*/ + +#define ljit_mem_c +#define LUA_CORE + +#include + +#include "lua.h" + +#include "lmem.h" +#include "ldo.h" +#include "ljit.h" +#include "ljit_dasm.h" + + +/* +** Define this if you want to run LuaJIT with valgrind. You will get random +** errors if you don't. And these errors are usually not caught by valgrind! +** +** This macro evaluates to a no-op if not run with valgrind. I.e. you can +** use the same binary for regular runs, too (without a performance loss). +*/ +#ifdef USE_VALGRIND +#include +#define MCH_INVALIDATE(ptr, addr) VALGRIND_DISCARD_TRANSLATIONS(ptr, addr) +#else +#define MCH_INVALIDATE(ptr, addr) ((void)0) +#endif + + +/* ------------------------------------------------------------------------ */ + +#if defined(_WIN32) && !defined(LUAJIT_MCH_USE_MALLOC) + +/* Use a private heap with executable memory for Windows. */ +#include + +/* No need for serialization. There's already a lock per Lua universe. */ +#ifdef HEAP_CREATE_ENABLE_EXECUTE +#define MCH_HCFLAGS (HEAP_NO_SERIALIZE|HEAP_CREATE_ENABLE_EXECUTE) +#else +#define MCH_HCFLAGS (HEAP_NO_SERIALIZE|0x00040000) +#endif + +/* Free the whole mcode heap. */ +void luaJIT_freemcodeheap(jit_State *J) +{ + if (J->mcodeheap) HeapDestroy((HANDLE)J->mcodeheap); +} + +/* Allocate a code block from the mcode heap. */ +static void *mcode_alloc(jit_State *J, size_t sz) +{ + void *ptr; + if (J->mcodeheap == NULL) { + J->mcodeheap = (void *)HeapCreate(MCH_HCFLAGS, 0, 0); + if (J->mcodeheap == NULL) luaD_throw(J->L, LUA_ERRMEM); + } + ptr = HeapAlloc(J->mcodeheap, 0, (sz)); + if (ptr == NULL) luaD_throw(J->L, LUA_ERRMEM); + return ptr; +} + +#define mcode_free(L, J, p, sz) HeapFree(J->mcodeheap, 0, (p)) + +/* ------------------------------------------------------------------------ */ + +#elif defined(LUA_USE_POSIX) && !defined(LUAJIT_MCH_USE_MALLOC) + +/* +** Allocate EXECUTABLE memory with mmap() on POSIX systems. +** +** There is no standard way to reuse malloc(). So this is a very small, +** but also very naive memory allocator. This should be ok, because: +** +** 1. Most apps only allocate mcode while running and free all on exit. +** +** 2. Some apps regularly load/unload a bunch of modules ("stages"). +** Allocs/frees come in groups, so coalescing should work fine. +** +** If your app differs, then please elaborate and/or supply code. +** And no -- including a full blown malloc is NOT an option. +** +** Caveat: the mmap()'ed heaps are not freed until exit. +** This shouldn't be too difficult to add, but I didn't bother. +*/ + +#include +#include + +/* TODO: move this to luaconf.h */ +#define LUAJIT_MCH_CHUNKSIZE (1<<17) /* 128K */ + +#if defined(MAP_ANONYMOUS) +#define MCH_MMFLAGS (MAP_PRIVATE|MAP_ANONYMOUS) +#elif defined(MAP_ANON) +#define MCH_MMFLAGS (MAP_PRIVATE|MAP_ANON) +#else +/* I'm too lazy to add /dev/zero support for ancient systems. */ +#error "Your OS has no (easy) support for anonymous mmap(). Please upgrade." +#endif + +/* Chunk header. Used for the free chunk list / heap headers. */ +typedef struct MCodeHead { + struct MCodeHead *next; /* Next free chunk / 1st head: first free. */ + struct MCodeHead *prev; /* Prev free chunk / 1st head: next head. */ + size_t size; /* Size of free chunk / Size of heap. */ + size_t dummy; /* May or may not overlap with trailer. */ +} MCodeHead; + +/* Allocation granularity. Assumes sizeof(void *) >= sizeof(size_t). */ +#define MCH_GRANULARITY (4*sizeof(void *)) +#define MCH_ROUNDSIZE(x) (((x) + MCH_GRANULARITY-1) & -MCH_GRANULARITY) +#define MCH_ROUNDHEAP(x) (((x) + 4095) & -4096) +#define MCH_HEADERSIZE MCH_ROUNDSIZE(sizeof(MCodeHead)) + +/* Trailer flags. */ +#define MCH_USED 1 /* Next chunk is in use. */ +#define MCH_LAST 2 /* Next chunk is the last one. */ +#define MCH_FIRST 4 /* Next chunk is the first one. */ +/* Note: the last chunk of each heap doesn't have a trailer. */ + +/* Trailer macros. */ +#define MCH_PREVTRAILER(mh) ((size_t *)(mh) - 1) +#define MCH_TRAILER(mh, sz) ((size_t *)((char *)(mh) + (sz)) - 1) +#define MCH_TRFLAGS(tr) ((tr) & (MCH_USED|MCH_LAST)) +#define MCH_TRSIZE(tr) ((tr) & ~(MCH_USED|MCH_LAST)) + +/* Debugging memory allocators is ... oh well. */ +#ifdef MCH_DEBUG +#include +#define MCH_DBGF stderr +#define MCH_DBG(x) fprintf x +#else +#define MCH_DBG(x) ((void)0) +#endif + +/* Free the whole list of mcode heaps. */ +void luaJIT_freemcodeheap(jit_State *J) +{ + MCodeHead *mh = (MCodeHead *)J->mcodeheap; + while (mh) { + MCodeHead *prev = mh->prev; /* Heaps are in the prev chain. */ +#ifdef MCH_DEBUG + munmap((void *)mh, mh->size+4096); +#else + munmap((void *)mh, mh->size); +#endif + mh = prev; + } + J->mcodeheap = NULL; +} + +/* Allocate a new heap of at least the given size. */ +static void mcode_newheap(jit_State *J, size_t sz) +{ + MCodeHead *mh, *mhn, *fh; + void *ptr; + + /* Ensure minimum size or round up. */ + if (sz + MCH_HEADERSIZE <= LUAJIT_MCH_CHUNKSIZE) + sz = LUAJIT_MCH_CHUNKSIZE; + else + sz = MCH_ROUNDHEAP(sz + MCH_HEADERSIZE); + +#ifdef MCH_DEBUG + /* Allocate a new heap plus a guard page. */ + ptr = mmap(NULL, sz+4096, PROT_READ|PROT_WRITE|PROT_EXEC, MCH_MMFLAGS, -1, 0); + if (ptr == MAP_FAILED) luaD_throw(J->L, LUA_ERRMEM); + mprotect((char *)ptr+sz, 4096, PROT_NONE); +#else + /* Allocate a new heap. */ + ptr = mmap(NULL, sz, PROT_READ|PROT_WRITE|PROT_EXEC, MCH_MMFLAGS, -1, 0); + if (ptr == MAP_FAILED) luaD_throw(J->L, LUA_ERRMEM); +#endif + + /* Initialize free chunk. */ + fh = (MCodeHead *)((char *)ptr + MCH_HEADERSIZE); + fh->size = sz - MCH_HEADERSIZE; + *MCH_PREVTRAILER(fh) = MCH_LAST | MCH_FIRST; /* Zero size, no coalesce. */ + + /* Initialize new heap and make it the first heap. */ + mh = (MCodeHead *)J->mcodeheap; + J->mcodeheap = ptr; + mhn = (MCodeHead *)ptr; + mhn->prev = mh; /* Heaps are in the prev. chain. */ + mhn->size = sz; + mhn->next = fh; /* Start of free list is always in the first heap. */ + fh->prev = mhn; + if (mh) { + fh->next = mh->next; /* Old start of free list. */ + mh->next = NULL; /* Just in case. */ + } else { + fh->next = NULL; /* No other free chunks yet. */ + } + MCH_DBG((MCH_DBGF, "HEAP %p %5x\n", mhn, sz)); +} + +/* Allocate a code block. */ +static void *mcode_alloc(jit_State *J, size_t sz) +{ + sz = MCH_ROUNDSIZE(sz + sizeof(size_t)); + for ( ; ; ) { + MCodeHead *mh = (MCodeHead *)J->mcodeheap; + if (mh) { /* Got at least one heap so search free list. */ +#ifdef MCH_DEBUG + int slen = 0; + for (mh = mh->next; mh ; mh = mh->next, slen++) +#else + for (mh = mh->next; mh ; mh = mh->next) +#endif + if (mh->size >= sz) { /* Very naive first fit. */ + size_t *trailer = MCH_TRAILER(mh, sz); + size_t *ptrailer = MCH_PREVTRAILER(mh); + if (mh->size == sz) { /* Exact match: just unchain chunk. */ + mh->prev->next = mh->next; + if (mh->next) + mh->next->prev = mh->prev; + *ptrailer |= MCH_USED; + MCH_DBG((MCH_DBGF, "NEW %p %5x FIT #%d%s\n", + mh, sz, slen, (*ptrailer & MCH_LAST) ? " LAST" : "")); + } else { /* Chunk is larger: rechain remainder chunk. */ + MCodeHead *fh = (MCodeHead *)((char *)mh + sz); + size_t tr; + fh->size = mh->size - sz; + (fh->prev = mh->prev)->next = fh; + if ((fh->next = mh->next) != NULL) + fh->next->prev = fh; + tr = *ptrailer; + if (tr & MCH_LAST) { + *ptrailer = (tr & ~MCH_LAST) | MCH_USED; + *trailer = sz | MCH_LAST; + MCH_DBG((MCH_DBGF, "NEW %p %5x REST %p %5x #%d LAST\n", + mh, sz, fh, fh->size, slen)); + } else { + size_t *ftrailer = MCH_TRAILER(fh, fh->size); + *ftrailer = MCH_TRFLAGS(*ftrailer) | fh->size; + *ptrailer = tr | MCH_USED; + *trailer = sz; + MCH_DBG((MCH_DBGF, "NEW %p %5x REST %p %5x #%d\n", + mh, sz, fh, fh->size, slen)); + } + } + return (void *)mh; + } + } + /* No luck. Allocate a new heap. Next loop iteration will succeed. */ + mcode_newheap(J, sz); + } +} + +/* Free a code block. */ +static void mcode_free_(jit_State *J, void *ptr, size_t sz) +{ + MCodeHead *mh = (MCodeHead *)ptr; + size_t *trailer = MCH_TRAILER(mh, sz); + size_t *ptrailer = MCH_PREVTRAILER(mh); + size_t tr = *ptrailer; + +#ifdef MCH_DEBUG + if (!(tr & MCH_USED)) MCH_DBG((MCH_DBGF, "**unused %p %5x\n", ptr, sz)); +#endif + + if (!(tr & MCH_FIRST)) { + MCodeHead *ph = (MCodeHead *)((char *)mh - MCH_TRSIZE(tr)); + size_t *pptrailer = MCH_PREVTRAILER(ph); + if (!(*pptrailer & MCH_USED)) { /* Prev free? */ + if (!(tr & MCH_LAST) && !(*trailer & MCH_USED)) { /* Next free? */ + /* Coalesce with previous and next chunk. */ + MCodeHead *nh = (MCodeHead *)((char *)mh + sz); + MCH_DBG((MCH_DBGF, "free %p %5x PN %p %5x %p %5x%s\n", + mh, sz, ph, ph->size, nh, nh->size, + (*trailer & MCH_LAST) ? " last" : "")); + if ((nh->prev->next = nh->next) != NULL) + nh->next->prev = nh->prev; + ph->size += sz + nh->size; + if (*trailer & MCH_LAST) { + *pptrailer |= MCH_LAST; + } else { + trailer = MCH_TRAILER(nh, nh->size); + *trailer = MCH_TRFLAGS(*trailer) | ph->size; + } + return; + } + MCH_DBG((MCH_DBGF, "free %p %5x P- %p %5x%s\n", + mh, sz, ph, ph->size, + (tr & MCH_LAST) ? " last" : "")); + ph->size += sz; + if (tr & MCH_LAST) + *pptrailer |= MCH_LAST; + else + *trailer = MCH_TRFLAGS(*trailer) | ph->size; + return; + } + } + + if (!(tr & MCH_LAST) && !(*trailer & MCH_USED)) { /* Next free? */ + /* Coalesce with next chunk. */ + MCodeHead *nh = (MCodeHead *)((char *)mh + sz); + MCH_DBG((MCH_DBGF, "free %p %5x -N %p %5x%s\n", + mh, sz, nh, nh->size, (*trailer & MCH_LAST) ? " last" : "")); + (mh->prev = nh->prev)->next = mh; + if ((mh->next = nh->next)) + mh->next->prev = mh; + mh->size = nh->size + sz; + if (*trailer & MCH_LAST) { + *ptrailer = (tr & ~MCH_USED) | MCH_LAST; + } else { + trailer = MCH_TRAILER(mh, mh->size); + *trailer = MCH_TRFLAGS(*trailer) | mh->size; + *ptrailer = tr & ~MCH_USED; + } + } else { + /* No coalesce possible, just add to free list. */ + MCodeHead *fh = (MCodeHead *)J->mcodeheap; + MCH_DBG((MCH_DBGF, "free %p %5x --%s\n", + mh, sz, (tr & MCH_LAST) ? " last" : "")); + if ((mh->next = fh->next)) + mh->next->prev = mh; + fh->next = mh; + mh->prev = fh; + mh->size = sz; + *ptrailer = tr & ~MCH_USED; + } +} + +#define mcode_free(L, J, p, sz) \ + mcode_free_(J, (p), MCH_ROUNDSIZE((sz) + sizeof(size_t))) + +/* ------------------------------------------------------------------------ */ + +#else + +/* +** Fallback to Lua's alloc, i.e. probably malloc(). +** +** Note: the returned memory is usually not marked executable! +** Running the code will crash if the CPU/OS checks for this. +** E.g. on x86 CPUs that support the NX (No eXecute) bit. +*/ + +/* There's no heap to free, but the JSUB mcode is. */ +void luaJIT_freemcodeheap(jit_State *J) +{ + if (J->jsubmcode) luaM_freemem(J->L, J->jsubmcode, J->szjsubmcode); +} + +#define mcode_alloc(J, sz) luaM_realloc_(J->L, NULL, 0, (sz)) +#define mcode_free(L, J, p, sz) luaM_freemem(L, p, sz) + +#endif + +/* ------------------------------------------------------------------------ */ + +/* Free mcode. */ +void luaJIT_freemcode(jit_State *J, void *mcode, size_t sz) +{ + mcode_free(J->L, J, mcode, sz); +} + +/* Free JIT structures in function prototype. */ +void luaJIT_freeproto(lua_State *L, Proto *pt) +{ + char *mcode = (char *)pt->jit_mcode; + size_t sz = pt->jit_szmcode; + pt->jit_mcode = NULL; + pt->jit_szmcode = 0; + while (sz != 0) { /* Free whole chain of mcode blocks for this proto. */ + jit_MCTrailer next; + memcpy((void *)&next, JIT_MCTRAILER(mcode, sz), sizeof(jit_MCTrailer)); + MCH_INVALIDATE(mcode, sz); + mcode_free(L, G(L)->jit_state, mcode, sz); + mcode = next.mcode; + sz = next.sz; + } +} + +/* Link generated code. Return mcode address, size and status. */ +int luaJIT_link(jit_State *J, void **mcodep, size_t *szp) +{ + size_t sz; + void *mcode; + + /* Pass 2: link sections. */ + if ((J->dasmstatus = dasm_link(Dst, &sz))) return JIT_S_DASM_ERROR; + + /* Check for hardcoded limit on mcode size. */ + if (sz > LUAJIT_LIM_MCODE) return JIT_S_TOOLARGE; + + /* TODO: mark mcode readonly when we're done. */ + mcode = mcode_alloc(J, sz); + + /* Pass 3: encode sections. */ + if ((J->dasmstatus = dasm_encode(Dst, mcode)) != 0) { + mcode_free(J->L, J, mcode, sz); + return JIT_S_DASM_ERROR; + } + *mcodep = mcode; + *szp = sz; + return JIT_S_OK; +} + -- cgit v1.1