bc: W^X for AArch64 Mac OS

This commit is contained in:
Matthew Flatt 2020-11-28 14:25:47 -07:00
parent 64378caa1d
commit bd193e46f1
8 changed files with 79 additions and 18 deletions

View File

@ -4258,6 +4258,7 @@ static Scheme_Object *ffi_callback_or_curry(const char *who, int curry, int argc
ffi_abi abi; ffi_abi abi;
int is_atomic; int is_atomic;
int nargs, i; int nargs, i;
ffi_status ffi_ok;
/* ffi_closure objects are problematic when used with a moving GC. The /* ffi_closure objects are problematic when used with a moving GC. The
* problem is that memory that is GC-visible can move at any time. The * problem is that memory that is GC-visible can move at any time. The
* solution is to use an immobile-box, which an immobile pointer (in a simple * solution is to use an immobile-box, which an immobile pointer (in a simple
@ -4361,20 +4362,25 @@ static Scheme_Object *ffi_callback_or_curry(const char *who, int curry, int argc
} else } else
do_callback = ffi_do_callback; do_callback = ffi_do_callback;
/* malloc space for everything needed, so a single free gets rid of this */ /* malloc space for everything needed, so a single free gets rid of this */
cl_cif_args = cl_cif_args = scheme_malloc_code(sizeof(closure_and_cif) + nargs*sizeof(ffi_cif*));
scheme_malloc_code(sizeof(closure_and_cif) + nargs*sizeof(ffi_cif*)); scheme_thread_code_start_write();
cl = &(cl_cif_args->closure); /* cl is the same as cl_cif_args */ cl = &(cl_cif_args->closure); /* cl is the same as cl_cif_args */
cif = &(cl_cif_args->cif); cif = &(cl_cif_args->cif);
atypes = (ffi_type **)(((char*)cl_cif_args) + sizeof(closure_and_cif)); atypes = (ffi_type **)(((char*)cl_cif_args) + sizeof(closure_and_cif));
for (i=0, p=itypes; i<nargs; i++, p=SCHEME_CDR(p)) { for (i=0, p=itypes; i<nargs; i++, p=SCHEME_CDR(p)) {
if (NULL == (base = get_ctype_base(SCHEME_CAR(p)))) if (NULL == (base = get_ctype_base(SCHEME_CAR(p)))) {
scheme_thread_code_end_write();
scheme_wrong_contract(who, "(listof ctype?)", ARGPOS(1), argc, argv); scheme_wrong_contract(who, "(listof ctype?)", ARGPOS(1), argc, argv);
if (CTYPE_PRIMLABEL(base) == FOREIGN_void) }
if (CTYPE_PRIMLABEL(base) == FOREIGN_void) {
scheme_thread_code_end_write();
wrong_void(who, SCHEME_CAR(p), 1, ARGPOS(1), argc, argv); wrong_void(who, SCHEME_CAR(p), 1, ARGPOS(1), argc, argv);
}
atypes[i] = CTYPE_ARG_PRIMTYPE(base); atypes[i] = CTYPE_ARG_PRIMTYPE(base);
} }
if (ffi_prep_cif(cif, abi, nargs, rtype, atypes) != FFI_OK) if (ffi_prep_cif(cif, abi, nargs, rtype, atypes) != FFI_OK)
scheme_signal_error("internal error: ffi_prep_cif did not return FFI_OK"); scheme_signal_error("internal error: ffi_prep_cif did not return FFI_OK");
scheme_thread_code_end_write();
data = (ffi_callback_struct*)scheme_malloc_tagged(sizeof(ffi_callback_struct)); data = (ffi_callback_struct*)scheme_malloc_tagged(sizeof(ffi_callback_struct));
data->so.type = ffi_callback_tag; data->so.type = ffi_callback_tag;
data->callback = (cl_cif_args); data->callback = (cl_cif_args);
@ -4411,9 +4417,11 @@ static Scheme_Object *ffi_callback_or_curry(const char *who, int curry, int argc
callback_data = (void *)tmp; callback_data = (void *)tmp;
} }
# endif /* MZ_USE_MZRT */ # endif /* MZ_USE_MZRT */
scheme_thread_code_start_write();
cl_cif_args->data = callback_data; cl_cif_args->data = callback_data;
if (ffi_prep_closure_loc(cl, cif, do_callback, (void*)(cl_cif_args->data), cl) ffi_ok = ffi_prep_closure_loc(cl, cif, do_callback, (void*)(cl_cif_args->data), cl);
!= FFI_OK) scheme_thread_code_end_write();
if (ffi_ok != FFI_OK)
scheme_signal_error scheme_signal_error
("internal error: ffi_prep_closure did not return FFI_OK"); ("internal error: ffi_prep_closure did not return FFI_OK");
# ifdef MZ_USE_MZRT # ifdef MZ_USE_MZRT
@ -5361,8 +5369,8 @@ void scheme_init_foreign(Scheme_Startup_Env *env)
int scheme_is_cpointer(Scheme_Object *cp) int scheme_is_cpointer(Scheme_Object *cp)
{ {
return (SCHEME_FALSEP(cp) return (SCHEME_FALSEP(cp)
|| SCHEME_CPTRP(cp) || SCHEME_CPTRP(x)
|| SCHEME_BYTE_STRINGP(cp) || SCHEME_BYTE_STRINGP(x)
|| (SCHEME_CHAPERONE_STRUCTP(cp) || (SCHEME_CHAPERONE_STRUCTP(cp)
&& scheme_struct_type_property_ref(scheme_cpointer_property, cp))); && scheme_struct_type_property_ref(scheme_cpointer_property, cp)));
} }

View File

@ -3415,6 +3415,7 @@ static Scheme_Object *ffi_callback_or_curry(const char *who, int curry, int argc
ffi_abi abi; ffi_abi abi;
int is_atomic; int is_atomic;
int nargs, i; int nargs, i;
ffi_status ffi_ok;
/* ffi_closure objects are problematic when used with a moving GC. The /* ffi_closure objects are problematic when used with a moving GC. The
* problem is that memory that is GC-visible can move at any time. The * problem is that memory that is GC-visible can move at any time. The
* solution is to use an immobile-box, which an immobile pointer (in a simple * solution is to use an immobile-box, which an immobile pointer (in a simple
@ -3518,20 +3519,25 @@ static Scheme_Object *ffi_callback_or_curry(const char *who, int curry, int argc
} else } else
do_callback = ffi_do_callback; do_callback = ffi_do_callback;
/* malloc space for everything needed, so a single free gets rid of this */ /* malloc space for everything needed, so a single free gets rid of this */
cl_cif_args = cl_cif_args = scheme_malloc_code(sizeof(closure_and_cif) + nargs*sizeof(ffi_cif*));
scheme_malloc_code(sizeof(closure_and_cif) + nargs*sizeof(ffi_cif*)); scheme_thread_code_start_write();
cl = &(cl_cif_args->closure); /* cl is the same as cl_cif_args */ cl = &(cl_cif_args->closure); /* cl is the same as cl_cif_args */
cif = &(cl_cif_args->cif); cif = &(cl_cif_args->cif);
atypes = (ffi_type **)(((char*)cl_cif_args) + sizeof(closure_and_cif)); atypes = (ffi_type **)(((char*)cl_cif_args) + sizeof(closure_and_cif));
for (i=0, p=itypes; i<nargs; i++, p=SCHEME_CDR(p)) { for (i=0, p=itypes; i<nargs; i++, p=SCHEME_CDR(p)) {
if (NULL == (base = get_ctype_base(SCHEME_CAR(p)))) if (NULL == (base = get_ctype_base(SCHEME_CAR(p)))) {
scheme_thread_code_end_write();
scheme_wrong_contract(who, "(listof ctype?)", ARGPOS(1), argc, argv); scheme_wrong_contract(who, "(listof ctype?)", ARGPOS(1), argc, argv);
if (CTYPE_PRIMLABEL(base) == FOREIGN_void) }
if (CTYPE_PRIMLABEL(base) == FOREIGN_void) {
scheme_thread_code_end_write();
wrong_void(who, SCHEME_CAR(p), 1, ARGPOS(1), argc, argv); wrong_void(who, SCHEME_CAR(p), 1, ARGPOS(1), argc, argv);
}
atypes[i] = CTYPE_ARG_PRIMTYPE(base); atypes[i] = CTYPE_ARG_PRIMTYPE(base);
} }
if (ffi_prep_cif(cif, abi, nargs, rtype, atypes) != FFI_OK) if (ffi_prep_cif(cif, abi, nargs, rtype, atypes) != FFI_OK)
scheme_signal_error("internal error: ffi_prep_cif did not return FFI_OK"); scheme_signal_error("internal error: ffi_prep_cif did not return FFI_OK");
scheme_thread_code_end_write();
@cmake["data" ffi-callback @cmake["data" ffi-callback
"cl_cif_args" "(curry ? NULL : argv[ARGPOS(0)])" "argv[ARGPOS(1)]" "argv[ARGPOS(2)]" "cl_cif_args" "(curry ? NULL : argv[ARGPOS(0)])" "argv[ARGPOS(1)]" "argv[ARGPOS(2)]"
"sync"] "sync"]
@ -3564,9 +3570,11 @@ static Scheme_Object *ffi_callback_or_curry(const char *who, int curry, int argc
callback_data = (void *)tmp; callback_data = (void *)tmp;
} }
} }
scheme_thread_code_start_write();
cl_cif_args->data = callback_data; cl_cif_args->data = callback_data;
if (ffi_prep_closure_loc(cl, cif, do_callback, (void*)(cl_cif_args->data), cl) ffi_ok = ffi_prep_closure_loc(cl, cif, do_callback, (void*)(cl_cif_args->data), cl);
!= FFI_OK) scheme_thread_code_end_write();
if (ffi_ok != FFI_OK)
scheme_signal_error scheme_signal_error
("internal error: ffi_prep_closure did not return FFI_OK"); ("internal error: ffi_prep_closure did not return FFI_OK");
@@IFDEF{MZ_USE_MZRT}{ @@IFDEF{MZ_USE_MZRT}{

View File

@ -232,8 +232,7 @@ static void os_protect_pages(void *p, size_t len, int writeable)
} }
retval = vm_protect(task_self, (vm_address_t)p, len, FALSE, retval = vm_protect(task_self, (vm_address_t)p, len, FALSE,
writeable ? VM_PROT_ALL (VM_PROT_READ | (writeable ? VM_PROT_WRITE : 0)));
: (VM_PROT_READ | VM_PROT_EXECUTE));
if(retval != KERN_SUCCESS) { if(retval != KERN_SUCCESS) {
GCPRINT(GCOUTF, "WARNING: couldn't protect %li bytes of page %p%s\n", GCPRINT(GCOUTF, "WARNING: couldn't protect %li bytes of page %p%s\n",
len, p, mach_error_string(retval)); len, p, mach_error_string(retval));

View File

@ -159,6 +159,9 @@ typedef struct Thread_Local_Variables {
void *jit_buffer_cache_; void *jit_buffer_cache_;
intptr_t jit_buffer_cache_size_; intptr_t jit_buffer_cache_size_;
int jit_buffer_cache_registered_; int jit_buffer_cache_registered_;
#ifdef MZ_USE_MAP_JIT
int jit_code_write_enabled_;
#endif
int scheme_continuation_application_count_; int scheme_continuation_application_count_;
int scheme_cont_capture_count_; int scheme_cont_capture_count_;
int scheme_prompt_capture_count_; int scheme_prompt_capture_count_;
@ -544,6 +547,7 @@ XFORM_GC_VARIABLE_STACK_THROUGH_THREAD_LOCAL;
#define jit_buffer_cache XOA (scheme_get_thread_local_variables()->jit_buffer_cache_) #define jit_buffer_cache XOA (scheme_get_thread_local_variables()->jit_buffer_cache_)
#define jit_buffer_cache_size XOA (scheme_get_thread_local_variables()->jit_buffer_cache_size_) #define jit_buffer_cache_size XOA (scheme_get_thread_local_variables()->jit_buffer_cache_size_)
#define jit_buffer_cache_registered XOA (scheme_get_thread_local_variables()->jit_buffer_cache_registered_) #define jit_buffer_cache_registered XOA (scheme_get_thread_local_variables()->jit_buffer_cache_registered_)
#define jit_code_write_enabled XOA (scheme_get_thread_local_variables()->jit_code_write_enabled_)
#define scheme_continuation_application_count XOA (scheme_get_thread_local_variables()->scheme_continuation_application_count_) #define scheme_continuation_application_count XOA (scheme_get_thread_local_variables()->scheme_continuation_application_count_)
#define scheme_cont_capture_count XOA (scheme_get_thread_local_variables()->scheme_cont_capture_count_) #define scheme_cont_capture_count XOA (scheme_get_thread_local_variables()->scheme_cont_capture_count_)
#define scheme_prompt_capture_count XOA (scheme_get_thread_local_variables()->scheme_prompt_capture_count_) #define scheme_prompt_capture_count XOA (scheme_get_thread_local_variables()->scheme_prompt_capture_count_)

View File

@ -654,6 +654,7 @@
# define SCHEME_ARCH "arm" # define SCHEME_ARCH "arm"
# elif defined(__arm64__) # elif defined(__arm64__)
# define SCHEME_ARCH "aarch64" # define SCHEME_ARCH "aarch64"
# define MZ_USE_MAP_JIT
# elif defined(__x86_64__) # elif defined(__x86_64__)
# define SCHEME_ARCH "x86_64" # define SCHEME_ARCH "x86_64"
# else # else

View File

@ -255,6 +255,7 @@ void *scheme_generate_one(mz_jit_state *old_jitter,
} else { } else {
buffer = scheme_malloc_permanent_code(size); buffer = scheme_malloc_permanent_code(size);
} }
scheme_thread_code_start_write();
RECORD_CODE_SIZE(size); RECORD_CODE_SIZE(size);
} else if (old_jitter) { } else if (old_jitter) {
/* this is a recursive generate, so use leftover space in /* this is a recursive generate, so use leftover space in
@ -299,6 +300,7 @@ void *scheme_generate_one(mz_jit_state *old_jitter,
then switch over to long-jump mode. */ then switch over to long-jump mode. */
if (check_long_mode((uintptr_t)buffer, size)) { if (check_long_mode((uintptr_t)buffer, size)) {
/* start over */ /* start over */
scheme_thread_code_end_write();
scheme_performance_record_end("jit", &perf_state); scheme_performance_record_end("jit", &perf_state);
return scheme_generate_one(old_jitter, generate, data, gcable, return scheme_generate_one(old_jitter, generate, data, gcable,
save_ptr, ndata); save_ptr, ndata);
@ -352,6 +354,7 @@ void *scheme_generate_one(mz_jit_state *old_jitter,
if (!use_long_jumps) { if (!use_long_jumps) {
if (check_long_mode((uintptr_t)buffer, size)) { if (check_long_mode((uintptr_t)buffer, size)) {
/* start over */ /* start over */
scheme_thread_code_end_write();
scheme_performance_record_end("jit", &perf_state); scheme_performance_record_end("jit", &perf_state);
return scheme_generate_one(old_jitter, generate, data, gcable, return scheme_generate_one(old_jitter, generate, data, gcable,
save_ptr, ndata); save_ptr, ndata);
@ -417,6 +420,7 @@ void *scheme_generate_one(mz_jit_state *old_jitter,
/* That was in the permanent area, so return: */ /* That was in the permanent area, so return: */
jit_flush_code(buffer, jit_get_raw_ip()); jit_flush_code(buffer, jit_get_raw_ip());
scheme_performance_record_end("jit", &perf_state); scheme_performance_record_end("jit", &perf_state);
scheme_thread_code_end_write();
return buffer; return buffer;
} else { } else {
/* Allocate permanent area and jit again: */ /* Allocate permanent area and jit again: */

View File

@ -947,6 +947,8 @@ THREAD_LOCAL_DECL(intptr_t scheme_code_page_total);
THREAD_LOCAL_DECL(intptr_t scheme_code_total); THREAD_LOCAL_DECL(intptr_t scheme_code_total);
THREAD_LOCAL_DECL(intptr_t scheme_code_count); THREAD_LOCAL_DECL(intptr_t scheme_code_count);
THREAD_LOCAL_DECL(int jit_code_write_enabled);
#if defined(MZ_CODE_ALLOC_USE_MPROTECT) && !defined(MAP_ANON) #if defined(MZ_CODE_ALLOC_USE_MPROTECT) && !defined(MAP_ANON)
static int fd, fd_created; static int fd, fd_created;
#endif #endif
@ -957,6 +959,22 @@ static int fd, fd_created;
# define MAYBE_PROT_EXEC PROT_EXEC # define MAYBE_PROT_EXEC PROT_EXEC
#endif #endif
#ifdef MZ_USE_MAP_JIT
# define MAYBE_MAP_JIT MAP_JIT
void scheme_thread_code_start_write(void) {
if (jit_code_write_enabled == 0)
pthread_jit_write_protect_np(0);
jit_code_write_enabled++;
}
void scheme_thread_code_end_write(void) {
--jit_code_write_enabled;
if (jit_code_write_enabled == 0)
pthread_jit_write_protect_np(1);
}
#else
# define MAYBE_MAP_JIT 0
#endif
#define LOG_CODE_MALLOC(lvl, s) /* if (lvl > 1) s */ #define LOG_CODE_MALLOC(lvl, s) /* if (lvl > 1) s */
#define CODE_PAGE_OF(p) ((void *)(((uintptr_t)p) & ~(page_size - 1))) #define CODE_PAGE_OF(p) ((void *)(((uintptr_t)p) & ~(page_size - 1)))
@ -1031,13 +1049,13 @@ static void *malloc_page(intptr_t size)
} }
#else #else
# ifdef MAP_ANON # ifdef MAP_ANON
r = mmap(NULL, size, PROT_READ | PROT_WRITE | MAYBE_PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0); r = mmap(NULL, size, PROT_READ | PROT_WRITE | MAYBE_PROT_EXEC, MAP_PRIVATE | MAYBE_MAP_JIT | MAP_ANON, -1, 0);
# else # else
if (!fd_created) { if (!fd_created) {
fd_created = 1; fd_created = 1;
fd = open("/dev/zero", O_RDWR); fd = open("/dev/zero", O_RDWR);
} }
r = mmap(NULL, size, PROT_READ | PROT_WRITE | MAYBE_PROT_EXEC, MAP_PRIVATE, fd, 0); r = mmap(NULL, size, PROT_READ | PROT_WRITE | MAYBE_PROT_EXEC, MAP_PRIVATE | MAYBE_MAP_JIT, fd, 0);
# endif # endif
if (r == (void *)-1) if (r == (void *)-1)
r = NULL; r = NULL;
@ -1144,6 +1162,8 @@ void *scheme_malloc_code(intptr_t size)
intptr_t size2, bucket, sz, page_size; intptr_t size2, bucket, sz, page_size;
void *p, *pg, *prev; void *p, *pg, *prev;
scheme_thread_code_start_write();
if (size < CODE_HEADER_SIZE) { if (size < CODE_HEADER_SIZE) {
/* ensure CODE_HEADER_SIZE alignment /* ensure CODE_HEADER_SIZE alignment
and room for free-list pointers */ and room for free-list pointers */
@ -1213,6 +1233,8 @@ void *scheme_malloc_code(intptr_t size)
LOG_CODE_MALLOC(0, printf("allocated %ld (->%ld / %ld)\n", size, size2, bucket)); LOG_CODE_MALLOC(0, printf("allocated %ld (->%ld / %ld)\n", size, size2, bucket));
} }
scheme_thread_code_end_write();
return p; return p;
#else #else
return malloc(size); /* good luck! */ return malloc(size); /* good luck! */
@ -1267,6 +1289,8 @@ void scheme_free_code(void *p)
int per_page, n; int per_page, n;
void *prev; void *prev;
scheme_thread_code_start_write();
page_size = get_page_size(); page_size = get_page_size();
size = *(intptr_t *)CODE_PAGE_OF(p); size = *(intptr_t *)CODE_PAGE_OF(p);
@ -1345,6 +1369,8 @@ void scheme_free_code(void *p)
} }
} }
scheme_thread_code_end_write();
#else #else
free(p); free(p);
#endif #endif
@ -1356,6 +1382,8 @@ void scheme_free_all_code(void)
void *p, *next; void *p, *next;
intptr_t page_size; intptr_t page_size;
scheme_thread_code_start_write();
page_size = get_page_size(); page_size = get_page_size();
for (p = code_allocation_page_list; p; p = next) { for (p = code_allocation_page_list; p; p = next) {
@ -1368,6 +1396,8 @@ void scheme_free_all_code(void)
code_allocation_page_list = NULL; code_allocation_page_list = NULL;
free_page(free_list, page_size); free_page(free_list, page_size);
scheme_thread_code_end_write();
#endif #endif
} }

View File

@ -285,6 +285,13 @@ void scheme_clear_ephemerons(void);
#define SCHEME_PAIR_COPY_FLAGS(dest, src) (SCHEME_PAIR_FLAGS((dest)) |= (SCHEME_PAIR_FLAGS((src)) & PAIR_FLAG_MASK)) #define SCHEME_PAIR_COPY_FLAGS(dest, src) (SCHEME_PAIR_FLAGS((dest)) |= (SCHEME_PAIR_FLAGS((src)) & PAIR_FLAG_MASK))
#ifdef MZ_USE_MAP_JIT
XFORM_NONGCING void scheme_thread_code_start_write(void);
XFORM_NONGCING void scheme_thread_code_end_write(void);
#else
# define scheme_thread_code_start_write() do { } while (0)
# define scheme_thread_code_end_write() do { } while (0)
#endif
/*========================================================================*/ /*========================================================================*/
/* initialization */ /* initialization */