[core] Allocate JIT buffers with mmap on linux. From: Mark Glines --- config/gen/makefiles/root.in | 4 ++- config/gen/platform/generic/memexec.c | 21 ++++++++++++++-- src/jit.h | 8 +++++- src/jit/i386/exec_dep.c | 44 +++++++++++++++++++++++++++++++++ src/jit/i386/exec_dep.h | 3 ++ src/jit/i386/jit_defs.c | 7 +++++ src/jit/i386/jit_emit.h | 2 +- tools/build/nativecall.pl | 15 +++++++++++ 8 files changed, 96 insertions(+), 8 deletions(-) diff --git a/config/gen/makefiles/root.in b/config/gen/makefiles/root.in index 29e2c6f..7042889 100644 --- a/config/gen/makefiles/root.in +++ b/config/gen/makefiles/root.in @@ -1054,7 +1054,7 @@ $(SRC_DIR)/jit_cpu$(O) : $(GENERAL_H_FILES) $(SRC_DIR)/jit_emit.h $(SRC_DIR)/exec$(O) : $(GENERAL_H_FILES) @TEMP_exec_h@ $(SRC_DIR)/jit_emit.h -$(SRC_DIR)/exec_dep$(O) : $(GENERAL_H_FILES) @TEMP_exec_h@ $(SRC_DIR)/jit_emit.h +$(SRC_DIR)/exec_dep$(O) : $(GENERAL_H_FILES) @TEMP_exec_h@ $(SRC_DIR)/jit_emit.h $(SRC_DIR)/pmc/managedstruct.c $(SRC_DIR)/exec_cpu$(O) : $(GENERAL_H_FILES) @TEMP_exec_h@ $(SRC_DIR)/jit_emit.h @@ -1187,7 +1187,7 @@ $(SRC_DIR)/dataypes$(O) : $(GENERAL_H_FILES) $(SRC_DIR)/dataypes.c $(SRC_DIR)/exit$(O) : $(GENERAL_H_FILES) $(SRC_DIR)/exit.c -$(SRC_DIR)/nci$(O) : $(GENERAL_H_FILES) $(SRC_DIR)/nci.c $(SRC_DIR)/nci.str +$(SRC_DIR)/nci$(O) : $(GENERAL_H_FILES) $(SRC_DIR)/nci.c $(SRC_DIR)/nci.str $(SRC_DIR)/pmc/pmc_managedstruct.h $(SRC_DIR)/vtables$(O) : $(GENERAL_H_FILES) $(SRC_DIR)/vtables.c diff --git a/config/gen/platform/generic/memexec.c b/config/gen/platform/generic/memexec.c index ebcb911..aa82081 100644 --- a/config/gen/platform/generic/memexec.c +++ b/config/gen/platform/generic/memexec.c @@ -22,6 +22,9 @@ Memory protection stuff */ #ifdef PARROT_HAS_EXEC_PROTECT + +#define PARROT_EXEC_PERMS PROT_READ|PROT_WRITE|PROT_EXEC + /* =item C @@ -39,9 +42,15 @@ mem_alloc_executable(size_t size) void *p; size_t pagesize = sysconf(_SC_PAGESIZE); size = (size + pagesize - 1) & ~(pagesize-1); +#ifdef WIN32 if (posix_memalign(&p, pagesize, size)) return NULL; - mprotect(p, size, PROT_READ|PROT_WRITE|PROT_EXEC); + mprotect(p, size, PARROT_EXEC_PERMS); +#else /* !WIN32 */ + p = mmap(NULL, size, PARROT_EXEC_PERMS, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + if (!p) + return NULL; +#endif /* WIN32 */ return p; } @@ -58,7 +67,11 @@ Free a buffer allocated with mem_alloc_executable(). void mem_free_executable(void *p, size_t size) { +#ifdef WIN32 free(p); +#else /* !WIN32 */ + munmap(p, size); +#endif /* WIN32 */ } /* @@ -80,6 +93,7 @@ mem_realloc_executable(void* oldp, size_t oldsize, size_t newsize) void *newp; size_t pagesize = sysconf(_SC_PAGESIZE); size_t roundup; +#ifdef WIN32 temp = realloc(oldp, newsize); if (temp == NULL) return NULL; @@ -88,10 +102,13 @@ mem_realloc_executable(void* oldp, size_t oldsize, size_t newsize) if (posix_memalign(&newp, pagesize, roundup)) newp = NULL; if (newp) { - mprotect(newp, roundup, PROT_READ|PROT_WRITE|PROT_EXEC); + mprotect(newp, roundup, PARROT_EXEC_PERMS); memcpy(newp, temp, newsize); } free(temp); +#else /* !WIN32 */ + temp = mremap(oldp, oldsize, newsize, PARROT_EXEC_PERMS); +#endif /* WIN32 */ return newp; } #endif diff --git a/src/jit.h b/src/jit.h index 39b444c..27fe7ac 100644 --- a/src/jit.h +++ b/src/jit.h @@ -321,7 +321,13 @@ parrot_build_asm(PARROT_INTERP, /* * NCI interface */ -void *Parrot_jit_build_call_func(Interp *, PMC *, STRING *); +void *Parrot_jit_build_call_func(Interp *, PMC *, STRING *, int *); +/* custom pmc callback functions */ +void Parrot_jit_free_buffer(PARROT_INTERP, void *ptr, void *priv); +PMC* Parrot_jit_clone_buffer(PARROT_INTERP, PMC *pmc, void *priv); +struct jit_buffer_private_data { + int size; +}; #endif /* PARROT_JIT_H_GUARD */ diff --git a/src/jit/i386/exec_dep.c b/src/jit/i386/exec_dep.c index 0756ac3..d62dec8 100644 --- a/src/jit/i386/exec_dep.c +++ b/src/jit/i386/exec_dep.c @@ -16,6 +16,7 @@ */ #include "parrot/parrot.h" +#include "pmc/pmc_managedstruct.h" #include "jit.h" #define JIT_EMIT 1 #include "jit_emit.h" @@ -186,6 +187,49 @@ offset_fixup(Parrot_exec_objfile_t *obj) } } +void +Parrot_jit_free_buffer(PARROT_INTERP, void *ptr, void *priv) { + struct jit_buffer_private_data *jit = (struct jit_buffer_private_data*)priv; + mem_free_executable(ptr, jit->size); + free(priv); +} + +PMC * +Parrot_jit_clone_buffer(PARROT_INTERP, PMC *pmc, void *priv) { + struct jit_buffer_private_data *jit = (struct jit_buffer_private_data*)priv; + PMC *rv = pmc_new(interp, pmc->vtable->base_type); + void *tmp, *tmp2; + + VTABLE_init(interp, rv); + /* copy the attributes */ + GETATTR_ManagedStruct_custom_free_func(interp, pmc, tmp); + SETATTR_ManagedStruct_custom_free_func(interp, rv , tmp); + GETATTR_ManagedStruct_custom_clone_func(interp, pmc, tmp); + SETATTR_ManagedStruct_custom_clone_func(interp, rv , tmp); + GETATTR_ManagedStruct_custom_free_priv(interp, pmc, tmp); + if(tmp) { + tmp2 = mem_sys_allocate(sizeof(struct jit_buffer_private_data)); + memcpy(tmp2, tmp, sizeof(struct jit_buffer_private_data)); + SETATTR_ManagedStruct_custom_free_priv(interp, rv , tmp2); + } + GETATTR_ManagedStruct_custom_clone_priv(interp, pmc, tmp); + if(tmp) { + tmp2 = mem_sys_allocate(sizeof(struct jit_buffer_private_data)); + memcpy(tmp2, tmp, sizeof(struct jit_buffer_private_data)); + SETATTR_ManagedStruct_custom_clone_priv(interp, rv , tmp2); + } + + /* copy the execmem buffer */ + if (PARROT_MANAGEDSTRUCT(pmc)->ptr) { + void *newptr, *ptr = PARROT_MANAGEDSTRUCT(pmc)->ptr; + newptr = mem_alloc_executable(jit->size); + memcpy(newptr, ptr, jit->size); + PARROT_MANAGEDSTRUCT(rv)->ptr = newptr; + } + + return rv; +} + /* * Local variables: * c-file-style: "parrot" diff --git a/src/jit/i386/exec_dep.h b/src/jit/i386/exec_dep.h index d8a7d92..b081f1c 100644 --- a/src/jit/i386/exec_dep.h +++ b/src/jit/i386/exec_dep.h @@ -33,6 +33,9 @@ void Parrot_exec_normal_op(Parrot_jit_info_t *jit_info, PARROT_INTERP) void Parrot_exec_restart_op(Parrot_jit_info_t *jit_info, PARROT_INTERP) __attribute__nonnull__(2); +void Parrot_jit_free_buffer(PARROT_INTERP, void *ptr, void *priv); +PMC* Parrot_jit_clone_buffer(PARROT_INTERP, PMC *pmc, void *priv); + #define ASSERT_ARGS_offset_fixup __attribute__unused__ int _ASSERT_ARGS_CHECK = 0 #define ASSERT_ARGS_Parrot_exec_cpcf_op __attribute__unused__ int _ASSERT_ARGS_CHECK = \ PARROT_ASSERT_ARG(interp) diff --git a/src/jit/i386/jit_defs.c b/src/jit/i386/jit_defs.c index 0278a71..5d60a97 100644 --- a/src/jit/i386/jit_defs.c +++ b/src/jit/i386/jit_defs.c @@ -2116,10 +2116,13 @@ calc_signature_needs(const char *sig, int *strings) * The generate function for a specific signature looks quite similar to * an optimized compile of src/nci.c:pcf_x_yy(). In case of any troubles * just compare the disassembly. + * + * If a non-NULL sizeptr is passed, the integer it points to will be written + * with the size of the allocated execmem buffer. */ void * -Parrot_jit_build_call_func(PARROT_INTERP, PMC *pmc_nci, STRING *signature) +Parrot_jit_build_call_func(PARROT_INTERP, PMC *pmc_nci, STRING *signature, int *sizeptr) { Parrot_jit_info_t jit_info; char *pc; @@ -2453,6 +2456,8 @@ Parrot_jit_build_call_func(PARROT_INTERP, PMC *pmc_nci, STRING *signature) PARROT_ASSERT(pc - jit_info.arena.start <= JIT_ALLOC_SIZE); /* could shrink arena.start here to used size */ PObj_active_destroy_SET(pmc_nci); + if (sizeptr) + *sizeptr = JIT_ALLOC_SIZE; return (void *)D2FPTR(jit_info.arena.start); } diff --git a/src/jit/i386/jit_emit.h b/src/jit/i386/jit_emit.h index f6f29fe..4ea814e 100644 --- a/src/jit/i386/jit_emit.h +++ b/src/jit/i386/jit_emit.h @@ -1879,7 +1879,7 @@ int count_regs(PARROT_INTERP, char *sig, char *sig_start); size_t calc_signature_needs(const char *sig, int *strings); void * Parrot_jit_build_call_func(PARROT_INTERP, PMC *pmc_nci, - STRING *signature); + STRING *signature, int *sizeptr); /* * register usage diff --git a/tools/build/nativecall.pl b/tools/build/nativecall.pl index 5d878d5..4c542f8 100644 --- a/tools/build/nativecall.pl +++ b/tools/build/nativecall.pl @@ -195,8 +195,10 @@ sub print_head { #include "parrot/parrot.h" #include "parrot/hash.h" #include "parrot/oplib/ops.h" +#include "pmc/pmc_managedstruct.h" #include "pmc/pmc_nci.h" #include "nci.str" +#include "jit.h" /* HEADERIZER HFILE: none */ /* HEADERIZER STOP */ @@ -554,11 +556,22 @@ $put_pointer return F2DPTR(VTABLE_get_pointer(interp, b)); } else { - void * const result = Parrot_jit_build_call_func(interp, pmc_nci, signature); + int jit_size; + void * const result = Parrot_jit_build_call_func(interp, pmc_nci, signature, &jit_size); if (result) { + struct jit_buffer_private_data *priv; *jitted = 1; temp_pmc = pmc_new(interp, enum_class_ManagedStruct); VTABLE_set_pointer(interp, temp_pmc, (void *)result); +#ifdef PARROT_HAS_EXEC_PROTECT + priv = (struct jit_buffer_private_data *) + mem_sys_allocate(sizeof(struct jit_buffer_private_data)); + priv->size = jit_size; + SETATTR_ManagedStruct_custom_free_func(interp, temp_pmc, Parrot_jit_free_buffer); + SETATTR_ManagedStruct_custom_free_priv(interp, temp_pmc, priv); + SETATTR_ManagedStruct_custom_clone_func(interp, temp_pmc, Parrot_jit_clone_buffer); + SETATTR_ManagedStruct_custom_clone_priv(interp, temp_pmc, priv); +#endif /* PARROT_HAS_EXEC_PROTECT */ VTABLE_set_pmc_keyed_str(interp, HashPointer, jit_key_name, temp_pmc); return result; }