diff --git a/src/Makefile b/src/Makefile index 278324a1..2e8cb84e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -307,7 +307,13 @@ else ifneq (,$(findstring stack-protector,$(shell $(TARGET_CC) -dumpspecs))) TARGET_XCFLAGS+= -fno-stack-protector endif - ifneq (SunOS,$(TARGET_SYS)) + ifeq (SunOS,$(TARGET_SYS)) + TARGET_XSHLDFLAGS= -shared -fPIC -Wl,-h,$(TARGET_SONAME) -zdefs + ifeq (x64,$(TARGET_LJARCH)) + TARGET_XLDFLAGS+= -Wl,-M,luajit-solaris64.mapfile + TARGET_XLIBS+= -lumem + endif + else ifneq (PS3,$(TARGET_SYS)) TARGET_XLDFLAGS+= -Wl,-E endif diff --git a/src/Makefile.dep b/src/Makefile.dep index 5d91723a..89e557ac 100644 --- a/src/Makefile.dep +++ b/src/Makefile.dep @@ -66,7 +66,7 @@ lj_ccallback.o: lj_ccallback.c lj_obj.h lua.h luaconf.h lj_def.h \ lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_state.h lj_frame.h \ lj_bc.h lj_ctype.h lj_cconv.h lj_ccall.h lj_ccallback.h lj_target.h \ lj_target_*.h lj_mcode.h lj_jit.h lj_ir.h lj_trace.h lj_dispatch.h \ - lj_traceerr.h lj_vm.h + lj_traceerr.h lj_vm.h lj_alloc.h lj_cconv.o: lj_cconv.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ lj_err.h lj_errmsg.h lj_tab.h lj_ctype.h lj_gc.h lj_cdata.h lj_cconv.h \ lj_ccallback.h @@ -130,7 +130,7 @@ lj_load.o: lj_load.c lua.h luaconf.h lauxlib.h lj_obj.h lj_def.h \ lj_bc.h lj_vm.h lj_lex.h lj_bcdump.h lj_parse.h lj_mcode.o: lj_mcode.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ lj_gc.h lj_jit.h lj_ir.h lj_mcode.h lj_trace.h lj_dispatch.h lj_bc.h \ - lj_traceerr.h lj_vm.h + lj_traceerr.h lj_vm.h lj_alloc.h lj_meta.o: lj_meta.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h lj_frame.h lj_bc.h \ lj_vm.h lj_strscan.h diff --git a/src/lj_alloc.c b/src/lj_alloc.c index 82b4e5b1..eeec3a5c 100644 --- a/src/lj_alloc.c +++ b/src/lj_alloc.c @@ -34,6 +34,16 @@ #ifndef LUAJIT_USE_SYSMALLOC +#if LJ_TARGET_SOLARIS +#include +#include +#include +#include +#include +#include +#include +#endif + #define MAX_SIZE_T (~(size_t)0) #define MALLOC_ALIGNMENT ((size_t)8U) @@ -235,6 +245,237 @@ static LJ_AINLINE void *CALL_MMAP(size_t size) return CMFAIL; } +#elif LJ_TARGET_SOLARIS + +#define MMAP_REGION_START ((uintptr_t)0x10000) +#define MMAP_REGION_END ((uintptr_t)0x70280000) + +struct lj_memseg +{ + struct lj_memseg *next; + void *ptr; + size_t size; +}; + +static volatile vmem_t *vmp = NULL; +static volatile umem_cache_t *memseg_cache = NULL; + +static pthread_mutex_t s_mmap_init_mutex = PTHREAD_MUTEX_INITIALIZER; + +static void INIT_MMAP(void) +{ + size_t pagesize; + void *p; + static char memseg_cache_name[] = "luajit_memseg"; + + if (vmp != NULL) { + return; + } + + pthread_mutex_lock(&s_mmap_init_mutex); + + if (vmp != NULL) { + goto out; + } + + pagesize = sysconf(_SC_PAGESIZE); + + /* init umem */ + if ((p = umem_alloc(1, UMEM_DEFAULT)) != NULL) { + umem_free(p, 1); + } + + /* reserve virtual space */ + if (mmap((void *) MMAP_REGION_START, + MMAP_REGION_END - MMAP_REGION_START, + PROT_NONE, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE | MAP_FIXED, + -1, 0) == MAP_FAILED) { + fprintf(stderr, "INIT_MMAP(): mmap() failed: %s [%d]\n", strerror(errno), errno); + goto out; + } + + /* create vmem arena */ + vmp = vmem_create( + "luajit", + (void *) MMAP_REGION_START, /* start */ + MMAP_REGION_END - MMAP_REGION_START, /* size */ + pagesize, /* quantum */ + NULL, NULL, NULL, 0, + VM_NOSLEEP | VMC_NO_QCACHE | VMC_IDENTIFIER); + + if (vmp == NULL) { + fprintf(stderr, "INIT_MMAP(): vmem arena creation failed\n"); + goto out; + } + + /* create memseg cache */ + memseg_cache = umem_cache_create(memseg_cache_name, sizeof(struct lj_memseg), 0, + NULL, NULL, NULL, NULL, NULL, 0); + + if (memseg_cache == NULL) { + fprintf(stderr, "INIT_MMAP(): memseg cache creation failed\n"); + vmem_destroy((vmem_t *) vmp); + vmp = NULL; + goto out; + } + + out: + pthread_mutex_unlock(&s_mmap_init_mutex); +} + +void * +lj_mmap(size_t size, int prot) +{ + void *addr; + + /* allocate address space */ + addr = vmem_alloc((vmem_t *) vmp, size, VM_NOSLEEP); + if (LJ_UNLIKELY(addr == NULL)) { + fprintf(stderr, "lj_mmap(): vmem_alloc(%lu) failed\n", size); + return MAP_FAILED; + } + + /* back by pages */ + if (LJ_UNLIKELY(mmap(addr, size, prot, MMAP_FLAGS | MAP_FIXED, -1, 0) == MAP_FAILED)) { + fprintf(stderr, "lj_mmap(): mmap(%p, %lu, %d) failed: %s [%d]\n", addr, size, prot, + strerror(errno), errno); + vmem_free((vmem_t *) vmp, addr, size); + return MAP_FAILED; + } + + return addr; +} + + +struct munmap_ctx +{ + void *ptr; + size_t size; + struct lj_memseg head; + int partial; +}; + +static void +munmap_walker(void *arg, void *ptr, size_t size) +{ + struct munmap_ctx *ctx = (struct munmap_ctx *)arg; + struct lj_memseg *seg; + if (ctx->partial || + ((char *)ptr + size <= (char *)ctx->ptr) || + ((char *)ctx->ptr + ctx->size <= (char *)ptr)) { + return; + } + + if ((char *)ptr < (char *)ctx->ptr || + (char *)ctx->ptr + ctx->size < (char *)ptr + size) { + /* found partial free, remember it in ctx */ + ctx->partial = 1; + ctx->ptr = ptr; + ctx->size = size; + return; + } + + if (ctx->head.ptr == NULL) { + seg = &ctx->head; + } + else { + seg = umem_cache_alloc((umem_cache_t *) memseg_cache, UMEM_DEFAULT); + if (seg == NULL) { + fprintf(stderr, "munmap_walker: umem_cache_alloc() returned NULL\n"); + return; + } + } + + seg->ptr = ptr; + seg->size = size; + seg->next = ctx->head.next; + + ctx->head.next = seg; +} + +int +lj_munmap(void *ptr, size_t size) +{ + struct munmap_ctx ctx; + struct lj_memseg *seg; + + ctx.ptr = ptr; + ctx.size = size; + ctx.head.ptr = NULL; + ctx.head.next = &ctx.head; + ctx.partial = 0; + + vmem_walk((vmem_t *) vmp, VMEM_ALLOC, &munmap_walker, &ctx); + + if (LJ_UNLIKELY(ctx.head.ptr == NULL)) { // oops! + fprintf(stderr, "lj_munmap: no segment found for (%p, %lu)\n", ptr, size); + return 0; + } + + if (size == ctx.head.size) { + if (LJ_UNLIKELY(munmap(ptr, size) != 0)) { + fprintf(stderr, "munmap(%p, %lu) failed: %s [%d]\n", ptr, size, strerror(errno), errno); + return -1; + } + vmem_free((vmem_t *) vmp, ptr, size); + return 0; + } + + if (ctx.partial) { + fprintf(stderr, "lj_munmap(%p, %lu): partial free of segment (%p, %lu)\n", + ptr, size, ctx.ptr, ctx.size); + + /* free allocated segs */ + for (seg = ctx.head.next; seg != &ctx.head;) { + struct lj_memseg *next_seg = seg->next; + umem_cache_free((umem_cache_t *) memseg_cache, seg); + seg = next_seg; + } + + return -1; + } + + /* ok, no partial free */ + for (seg = &ctx.head;;) { + struct lj_memseg *next_seg = seg->next; + + if (LJ_UNLIKELY(munmap(seg->ptr, seg->size) != 0)) { + fprintf(stderr, "munmap(%p, %lu) failed: %s [%d]\n", ptr, size, strerror(errno), errno); + } + + vmem_free((vmem_t *) vmp, seg->ptr, seg->size); + + if (seg != &ctx.head) { + umem_cache_free((umem_cache_t *) memseg_cache, seg); + } + + if (next_seg == &ctx.head) { + break; + } + + seg = next_seg; + } + + return 0; +} + +static LJ_AINLINE void *CALL_MMAP(size_t size) +{ + int olderr = errno; + void *ptr = lj_mmap(size, MMAP_PROT); + errno = olderr; + return (ptr != MAP_FAILED ? ptr : CMFAIL); +} + +static LJ_AINLINE int CALL_MUNMAP(void *ptr, size_t size) +{ + int olderr = errno; + int ret = lj_munmap(ptr, size); + errno = olderr; + return ret; +} + #else #error "NYI: need an equivalent of MAP_32BIT for this 64 bit OS" @@ -254,9 +495,12 @@ static LJ_AINLINE void *CALL_MMAP(size_t size) #endif -#define INIT_MMAP() ((void)0) #define DIRECT_MMAP(s) CALL_MMAP(s) +#if !LJ_TARGET_SOLARIS || !LJ_64 + +#define INIT_MMAP() ((void)0) + static LJ_AINLINE int CALL_MUNMAP(void *ptr, size_t size) { int olderr = errno; @@ -264,6 +508,7 @@ static LJ_AINLINE int CALL_MUNMAP(void *ptr, size_t size) errno = olderr; return ret; } +#endif #if LJ_TARGET_LINUX /* Need to define _GNU_SOURCE to get the mremap prototype. */ diff --git a/src/lj_alloc.h b/src/lj_alloc.h index f87a7cf3..1b462e58 100644 --- a/src/lj_alloc.h +++ b/src/lj_alloc.h @@ -12,6 +12,12 @@ LJ_FUNC void *lj_alloc_create(void); LJ_FUNC void lj_alloc_destroy(void *msp); LJ_FUNC void *lj_alloc_f(void *msp, void *ptr, size_t osize, size_t nsize); + +#if LJ_TARGET_SOLARIS && LJ_64 +LJ_FUNC void *lj_mmap(size_t size, int prot); +LJ_FUNC int lj_munmap(void *ptr, size_t size); +#endif + #endif #endif diff --git a/src/lj_api.c b/src/lj_api.c index edb2d620..55f0fd78 100644 --- a/src/lj_api.c +++ b/src/lj_api.c @@ -495,6 +495,9 @@ LUALIB_API int luaL_checkoption(lua_State *L, int idx, const char *def, if (strcmp(lst[i], s) == 0) return (int)i; lj_err_argv(L, idx, LJ_ERR_INVOPTM, s); +#ifdef SOLARIS_STD_UNWINDER + return 0; +#endif } LUA_API size_t lua_objlen(lua_State *L, int idx) diff --git a/src/lj_arch.h b/src/lj_arch.h index 9ea10d0f..b5fa9c8a 100644 --- a/src/lj_arch.h +++ b/src/lj_arch.h @@ -33,6 +33,7 @@ #define LUAJIT_OS_OSX 3 #define LUAJIT_OS_BSD 4 #define LUAJIT_OS_POSIX 5 +#define LUAJIT_OS_SOLARIS 6 /* Select native target if no target defined. */ #ifndef LUAJIT_TARGET @@ -69,8 +70,10 @@ #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \ defined(__NetBSD__) || defined(__OpenBSD__) #define LUAJIT_OS LUAJIT_OS_BSD -#elif (defined(__sun__) && defined(__svr4__)) || defined(__CYGWIN__) +#elif defined(__CYGWIN__) #define LUAJIT_OS LUAJIT_OS_POSIX +#elif (defined(__sun__) && defined(__svr4__)) +#define LUAJIT_OS LUAJIT_OS_SOLARIS #else #define LUAJIT_OS LUAJIT_OS_OTHER #endif @@ -88,6 +91,8 @@ #define LJ_OS_NAME "BSD" #elif LUAJIT_OS == LUAJIT_OS_POSIX #define LJ_OS_NAME "POSIX" +#elif LUAJUT_OS == LUAJIT_OS_SOLARIS +#define LJ_OS_NAME "Solaris" #else #define LJ_OS_NAME "Other" #endif @@ -96,6 +101,7 @@ #define LJ_TARGET_LINUX (LUAJIT_OS == LUAJIT_OS_LINUX) #define LJ_TARGET_OSX (LUAJIT_OS == LUAJIT_OS_OSX) #define LJ_TARGET_IOS (LJ_TARGET_OSX && LUAJIT_TARGET == LUAJIT_ARCH_ARM) +#define LJ_TARGET_SOLARIS (LUAJIT_OS == LUAJIT_OS_SOLARIS) #define LJ_TARGET_POSIX (LUAJIT_OS > LUAJIT_OS_WINDOWS) #define LJ_TARGET_DLOPEN LJ_TARGET_POSIX diff --git a/src/lj_ccallback.c b/src/lj_ccallback.c index a3a0d798..b1f4b150 100644 --- a/src/lj_ccallback.c +++ b/src/lj_ccallback.c @@ -20,6 +20,7 @@ #include "lj_mcode.h" #include "lj_trace.h" #include "lj_vm.h" +#include "lj_alloc.h" /* -- Target-specific handling of callback slots -------------------------- */ @@ -228,8 +229,12 @@ static void callback_mcode_new(CTState *cts) if (!p) lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV); #elif LJ_TARGET_POSIX +#if LJ_TARGET_SOLARIS && LJ_64 + p = lj_mmap(sz, (PROT_READ|PROT_WRITE)); +#else p = mmap(NULL, sz, (PROT_READ|PROT_WRITE), MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); +#endif if (p == MAP_FAILED) lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV); #else @@ -259,7 +264,11 @@ void lj_ccallback_mcode_free(CTState *cts) VirtualFree(p, 0, MEM_RELEASE); UNUSED(sz); #elif LJ_TARGET_POSIX +#if LJ_TARGET_SOLARIS && LJ_64 + lj_munmap(p, sz); +#else munmap(p, sz); +#endif #else lj_mem_free(cts->g, p, sz); #endif diff --git a/src/lj_def.h b/src/lj_def.h index 250729f7..a8d3eb80 100644 --- a/src/lj_def.h +++ b/src/lj_def.h @@ -113,10 +113,18 @@ typedef uintptr_t BloomFilter; #if defined(__GNUC__) +#if SOLARIS_STD_UNWINDER +#define LJ_NORET +#else #define LJ_NORET __attribute__((noreturn)) +#endif #define LJ_ALIGN(n) __attribute__((aligned(n))) #define LJ_INLINE inline +#if !defined(__FreeBSD__) #define LJ_AINLINE inline __attribute__((always_inline)) +#else +#define LJ_AINLINE inline +#endif #define LJ_NOINLINE __attribute__((noinline)) #if defined(__ELF__) || defined(__MACH__) diff --git a/src/lj_err.c b/src/lj_err.c index 4a33a233..b87a5718 100644 --- a/src/lj_err.c +++ b/src/lj_err.c @@ -236,7 +236,11 @@ LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions, if (version != 1) return _URC_FATAL_PHASE1_ERROR; UNUSED(uexclass); +#if SOLARIS_STD_UNWINDER + cf = (void *)((char *)_Unwind_GetCFA(ctx) - 80); +#else cf = (void *)_Unwind_GetCFA(ctx); +#endif L = cframe_L(cf); if ((actions & _UA_SEARCH_PHASE)) { #if LJ_UNWIND_EXT diff --git a/src/lj_mcode.c b/src/lj_mcode.c index cb79e8cd..77096cf9 100644 --- a/src/lj_mcode.c +++ b/src/lj_mcode.c @@ -16,6 +16,7 @@ #endif #if LJ_HASJIT || LJ_HASFFI #include "lj_vm.h" +#include "lj_alloc.h" #endif /* -- OS-specific functions ----------------------------------------------- */ @@ -98,7 +99,13 @@ static void mcode_setprot(void *p, size_t sz, DWORD prot) static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, int prot) { +/* Solaris/X64 ignores hint and returns memory above 1<<48 so use custom + mmap()-er that maps to low 2G */ +#if LJ_TARGET_SOLARIS && LJ_64 + void *p = lj_mmap(sz, prot); +#else void *p = mmap((void *)hint, sz, prot, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); +#endif if (p == MAP_FAILED) { if (!hint) lj_trace_err(J, LJ_TRERR_MCODEAL); p = NULL; @@ -109,7 +116,11 @@ static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, int prot) static void mcode_free(jit_State *J, void *p, size_t sz) { UNUSED(J); +#if LJ_TARGET_SOLARIS && LJ_64 + lj_munmap(p, sz); +#else munmap(p, sz); +#endif } static void mcode_setprot(void *p, size_t sz, int prot) diff --git a/src/luajit-solaris64.mapfile b/src/luajit-solaris64.mapfile new file mode 100644 index 00000000..348b010e --- /dev/null +++ b/src/luajit-solaris64.mapfile @@ -0,0 +1,2 @@ +# 2G - 256M +text = V0x70280000; diff --git a/src/luajit.c b/src/luajit.c index 37b0deb3..2dd0bf1c 100644 --- a/src/luajit.c +++ b/src/luajit.c @@ -553,10 +553,11 @@ static int pmain(lua_State *L) return 0; } +static struct Smain s; + int main(int argc, char **argv) { int status; - struct Smain s; lua_State *L = lua_open(); /* create state */ if (L == NULL) { l_message(argv[0], "cannot create state: not enough memory"); diff --git a/src/vm_x86.dasc b/src/vm_x86.dasc index b4674e2b..f25dfd30 100644 --- a/src/vm_x86.dasc +++ b/src/vm_x86.dasc @@ -6152,7 +6152,11 @@ static void emit_asm_debug(BuildCtx *ctx) ".LEFDE1:\n\n", (int)ctx->codesz - fcofs); #endif #if (defined(__sun__) && defined(__svr4__)) +#if LJ_64 + fprintf(ctx->fp, "\t.section .eh_frame,\"a\",@unwind\n"); +#else fprintf(ctx->fp, "\t.section .eh_frame,\"aw\",@progbits\n"); +#endif #else fprintf(ctx->fp, "\t.section .eh_frame,\"a\",@progbits\n"); #endif