29extern int rb_thread_create_mjit_thread(
void (*worker_func)(
void));
35get_uniq_filename(
unsigned long id,
const char *
prefix,
const char *
suffix)
37 char buff[70], *
str = buff;
42 if (
size <= (
int)
sizeof(buff)) {
54mjit_gc_start_hook(
void)
58 CRITICAL_SECTION_START(4,
"mjit_gc_start_hook");
60 verbose(4,
"Waiting wakeup from a worker for GC");
62 verbose(4,
"Getting wakeup from a worker for GC");
65 CRITICAL_SECTION_FINISH(4,
"mjit_gc_start_hook");
71mjit_gc_exit_hook(
void)
75 CRITICAL_SECTION_START(4,
"mjit_gc_exit_hook");
79 verbose(4,
"Sending wakeup signal to workers after GC");
82 CRITICAL_SECTION_FINISH(4,
"mjit_gc_exit_hook");
87mjit_update_references(
const rb_iseq_t *iseq)
92 CRITICAL_SECTION_START(4,
"mjit_update_references");
93 if (iseq->
body->jit_unit) {
105 list_for_each(&stale_units.head, unit,
unode) {
110 CRITICAL_SECTION_FINISH(4,
"mjit_update_references");
121 CRITICAL_SECTION_START(4,
"mjit_free_iseq");
133 list_for_each(&stale_units.head, unit,
unode) {
138 CRITICAL_SECTION_FINISH(4,
"mjit_free_iseq");
149 list_for_each_safe(&list->
head, unit, next,
unode) {
150 list_del(&unit->
unode);
153 if (list == &stale_units) {
159 mjit_warning(
"failed to close handle for u%d: %s", unit->
id, dlerror());
161 clean_temp_files(unit);
186 CRITICAL_SECTION_START(3,
"in mjit_cont_new");
187 if (first_cont ==
NULL) {
192 cont->
next = first_cont;
193 first_cont->
prev = cont;
196 CRITICAL_SECTION_FINISH(3,
"in mjit_cont_new");
205 CRITICAL_SECTION_START(3,
"in mjit_cont_new");
206 if (cont == first_cont) {
207 first_cont = cont->
next;
208 if (first_cont !=
NULL)
216 CRITICAL_SECTION_FINISH(3,
"in mjit_cont_new");
227 for (cont = first_cont; cont !=
NULL; cont =
next) {
243 unit->
id = current_unit_num++;
256 iseq->
body->jit_func = (mjit_func_t)NOT_READY_JIT_ISEQ_FUNC;
265 CRITICAL_SECTION_START(3,
"in add_iseq_to_process");
267 add_to_list(
iseq->
body->jit_unit, &unit_queue);
268 if (active_units.length >=
mjit_opts.max_cache_size) {
272 verbose(3,
"Sending wakeup signal to workers in mjit_add_iseq_to_process");
274 CRITICAL_SECTION_FINISH(3,
"in add_iseq_to_process");
283 mjit_add_iseq_to_process(
iseq,
NULL,
false);
287#define MJIT_WAIT_TIMEOUT_SECONDS 60
296 while (body->jit_func == (mjit_func_t)NOT_READY_JIT_ISEQ_FUNC) {
298 if (tries / 1000 > MJIT_WAIT_TIMEOUT_SECONDS || pch_status ==
PCH_FAILED) {
299 CRITICAL_SECTION_START(3,
"in rb_mjit_wait_call to set jit_func");
300 body->jit_func = (mjit_func_t)NOT_COMPILED_JIT_ISEQ_FUNC;
301 CRITICAL_SECTION_FINISH(3,
"in rb_mjit_wait_call to set jit_func");
302 mjit_warning(
"timed out to wait for JIT finish");
306 CRITICAL_SECTION_START(3,
"in rb_mjit_wait_call for a client wakeup");
308 CRITICAL_SECTION_FINISH(3,
"in rb_mjit_wait_call for a client wakeup");
322 return body->jit_func(ec, ec->
cfp);
325struct rb_mjit_compile_info*
329 return &body->jit_unit->compile_info;
343 remove_from_list(iseq->
body->jit_unit, &active_units);
344 add_to_list(iseq->
body->jit_unit, &stale_units);
345 mjit_add_iseq_to_process(iseq, &iseq->
body->jit_unit->compile_info,
false);
346 mjit_wait(iseq->
body);
352 CRITICAL_SECTION_START(3,
"in rb_mjit_recompile_iseq");
353 iseq->
body->jit_unit->stale_p =
true;
354 iseq->
body->jit_func = (mjit_func_t)NOT_ADDED_JIT_ISEQ_FUNC;
355 pending_stale_p =
true;
356 CRITICAL_SECTION_FINISH(3,
"in rb_mjit_recompile_iseq");
362rb_mjit_recompile_send(
const rb_iseq_t *iseq)
364 rb_mjit_iseq_compile_info(iseq->
body)->disable_send_cache =
true;
365 mjit_recompile(iseq);
370rb_mjit_recompile_ivar(
const rb_iseq_t *iseq)
372 rb_mjit_iseq_compile_info(iseq->
body)->disable_ivar_cache =
true;
373 mjit_recompile(iseq);
378rb_mjit_recompile_exivar(
const rb_iseq_t *iseq)
380 rb_mjit_iseq_compile_info(iseq->
body)->disable_exivar_cache =
true;
381 mjit_recompile(iseq);
386rb_mjit_recompile_inlining(
const rb_iseq_t *iseq)
388 rb_mjit_iseq_compile_info(iseq->
body)->disable_inlining =
true;
389 mjit_recompile(iseq);
394rb_mjit_recompile_const(
const rb_iseq_t *iseq)
396 rb_mjit_iseq_compile_info(iseq->
body)->disable_const_cache =
true;
397 mjit_recompile(iseq);
404init_header_filename(
void)
411 const char *basedir =
"";
415 static const char libpathflag[] =
422 const size_t libpathflag_len =
sizeof(libpathflag) - 1;
430 if (
getenv(
"MJIT_SEARCH_BUILD_DIR")) {
438 verbose(1,
"No MJIT_HEADER");
440 else if (hdr[0] !=
'/') {
441 verbose(1,
"Non-absolute header file path: %s", hdr);
444 verbose(1,
"Non-file header file path: %s", hdr);
446 else if ((st.st_uid !=
getuid()) || (st.st_mode & 022) ||
448 verbose(1,
"Unsafe header file: uid=%ld mode=%#o %s",
449 (
long)st.st_uid, (
unsigned)st.st_mode, hdr);
458 verbose(3,
"MJIT_HEADER: %s", hdr);
460 if (!header_file)
return false;
469 const size_t header_name_len =
sizeof(header_name) - 1;
471 header_file =
xmalloc(baselen + header_name_len + 1);
473 p =
append_str2(p, header_name, header_name_len + 1);
476 verbose(1,
"Cannot access header file: %s", header_file);
488 const size_t pch_name_len =
sizeof(pch_name) - 1;
490 pch_file =
xmalloc(baselen + pch_name_len + 1);
494 verbose(1,
"Cannot access precompiled header file: %s", pch_file);
507 libruby_pathflag = p =
xmalloc(libpathflag_len + baselen + 1);
517valid_class_serials_add_i(
ID key,
VALUE v,
void *unused)
534system_default_tmpdir(
void)
538 WCHAR tmppath[_MAX_PATH];
541 int blen = WideCharToMultiByte(CP_UTF8, 0, tmppath,
len,
NULL, 0,
NULL,
NULL);
542 char *tmpdir =
xmalloc(blen + 1);
543 WideCharToMultiByte(CP_UTF8, 0, tmppath,
len, tmpdir, blen,
NULL,
NULL);
547#elif defined _CS_DARWIN_USER_TEMP_DIR
549 size_t len = confstr(_CS_DARWIN_USER_TEMP_DIR, path,
sizeof(path));
552 if (
len >
sizeof(path)) {
553 confstr(_CS_DARWIN_USER_TEMP_DIR, tmpdir,
len);
565check_tmpdir(
const char *dir)
569 if (!dir)
return FALSE;
572# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
581 if (!(st.st_mode & S_ISVTX))
return FALSE;
595# define RETURN_ENV(name) \
596 if (check_tmpdir(tmpdir = getenv(name))) return ruby_strdup(tmpdir)
597 RETURN_ENV(
"TMPDIR");
599 tmpdir = system_default_tmpdir();
600 if (check_tmpdir(tmpdir))
return tmpdir;
606#define MIN_CACHE_SIZE 10
608#define DEFAULT_MAX_CACHE_SIZE 100
610#define DEFAULT_MIN_CALLS_TO_ADD 10000
616 stop_worker_p =
false;
617 worker_stopped =
false;
626 verbose(1,
"Failure in MJIT thread initialization\n");
634ruby_strndup(
const char *
str,
size_t n)
645split_flags(
const char *flags)
650 for (; flags !=
NULL; flags = next) {
651 next =
strchr(flags,
' ');
658 buf[i++] = ruby_strndup(flags, next - flags);
663 char **ret =
xmalloc(
sizeof(
char *) * (i + 1));
673mjit_init(
const struct mjit_options *opts)
681 mjit_opts.min_calls = DEFAULT_MIN_CALLS_TO_ADD;
683 mjit_opts.max_cache_size = DEFAULT_MAX_CACHE_SIZE;
684 if (
mjit_opts.max_cache_size < MIN_CACHE_SIZE)
685 mjit_opts.max_cache_size = MIN_CACHE_SIZE;
693 cc_path = CC_COMMON_ARGS[0];
694 verbose(2,
"MJIT: CC defaults to %s", cc_path);
695 cc_common_args =
xmalloc(
sizeof(CC_COMMON_ARGS));
696 memcpy((
void *)cc_common_args, CC_COMMON_ARGS,
sizeof(CC_COMMON_ARGS));
697 cc_added_args = split_flags(opts->debug_flags);
698 xfree(opts->debug_flags);
701 for (
size_t i = 0, j = 0; i <
sizeof(CC_COMMON_ARGS) /
sizeof(
char *); i++) {
702 if (CC_COMMON_ARGS[i] && strncmp(
"-save-temps", CC_COMMON_ARGS[i],
strlen(
"-save-temps")) == 0)
704 cc_common_args[j] = CC_COMMON_ARGS[i];
709 tmp_dir = system_tmpdir();
710 verbose(2,
"MJIT: tmp_dir is %s", tmp_dir);
712 if (!init_header_filename()) {
714 verbose(1,
"Failure in MJIT header file name initialization\n");
717 pch_owner_pid = getpid();
752 while (!worker_stopped) {
753 verbose(3,
"Sending cancel signal to worker");
754 CRITICAL_SECTION_START(3,
"in stop_worker");
755 stop_worker_p =
true;
757 CRITICAL_SECTION_FINISH(3,
"in stop_worker");
764mjit_pause(
bool wait_p)
769 if (worker_stopped) {
779 while (unit_queue.length > 0 && active_units.length <
mjit_opts.max_cache_size) {
780 CRITICAL_SECTION_START(3,
"in mjit_pause for a worker wakeup");
782 CRITICAL_SECTION_FINISH(3,
"in mjit_pause for a worker wakeup");
798 if (!worker_stopped) {
802 if (!start_worker()) {
815 list_for_each_safe(&list->
head, unit, next,
unode) {
817 if (unit->so_file) unit->so_file =
NULL;
838mjit_child_after_fork(
void)
845 skip_cleaning_object_files(&active_units);
852#define MJIT_COUNTER 0
855mjit_dump_total_calls(
void)
858 fprintf(stderr,
"[MJIT_COUNTER] total_calls of active_units:\n");
859 list_for_each(&active_units.head, unit,
unode) {
874mjit_finish(
bool close_handle_p)
880 verbose(2,
"Stopping worker thread");
881 CRITICAL_SECTION_START(3,
"in mjit_finish to wakeup from pch");
888 verbose(3,
"Waiting wakeup from make_pch");
891 CRITICAL_SECTION_FINISH(3,
"in mjit_finish to wakeup from pch");
903 mjit_dump_total_calls();
907 if (!
mjit_opts.save_temps && getpid() == pch_owner_pid)
908 remove_file(pch_file);
912 xfree((
void *)cc_common_args); cc_common_args =
NULL;
913 for (
char **flag = cc_added_args; *flag !=
NULL; flag++)
915 xfree((
void *)cc_added_args); cc_added_args =
NULL;
920 free_list(&unit_queue, close_handle_p);
921 free_list(&active_units, close_handle_p);
922 free_list(&compact_units, close_handle_p);
923 free_list(&stale_units, close_handle_p);
927 verbose(1,
"Successful MJIT finish");
949 CRITICAL_SECTION_START(4,
"mjit_mark");
951 if (compiling_iseqs !=
NULL) {
952 while (compiling_iseqs[length]) length++;
954 length += active_units.length;
959 if (compiling_iseqs !=
NULL) {
960 while (compiling_iseqs[i]) {
961 iseqs[i] = compiling_iseqs[i];
965 list_for_each(&active_units.head, unit,
unode) {
966 iseqs[i] = unit->
iseq;
970 CRITICAL_SECTION_FINISH(4,
"mjit_mark");
972 for (i = 0; i < length; i++) {
973 if (iseqs[i] ==
NULL)
986 if (body->jit_unit && (cc_entries = body->jit_unit->cc_entries) !=
NULL) {
988 for (
unsigned int i = 0; i < body->jit_unit->cc_entries_size; i++) {
990 if (cc !=
NULL && vm_cc_markable(cc)) {
1018 CRITICAL_SECTION_START(3,
"in mjit_remove_class_serial");
1020 CRITICAL_SECTION_FINISH(3,
"in mjit_remove_class_serial");
#define RUBY_ASSERT_ALWAYS(expr)
A variant of RUBY_ASSERT that does not interface with RUBY_DEBUG.
void rb_fiber_init_mjit_cont(struct rb_fiber_struct *fiber)
#define RB_DEBUG_COUNTER_INC(type)
char * strchr(char *, char)
char str[HTML_ESCAPE_MAX_LEN+1]
#define RSTRING_LEN(string)
#define RSTRING_PTR(string)
int rb_path_check(const char *path)
VALUE rb_gc_location(VALUE value)
void rb_gc_mark(VALUE ptr)
void rb_gc_register_mark_object(VALUE obj)
Inform the garbage collector that object is a live Ruby object that should not be moved.
#define RUBY_MARK_LEAVE(msg)
#define RUBY_MARK_ENTER(msg)
void rb_raise(VALUE exc, const char *fmt,...)
VALUE rb_cObject
Object class.
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
unsigned char suffix[65536]
unsigned short prefix[65536]
VALUE rb_hash_delete_entry(VALUE hash, VALUE key)
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
void rb_id_table_foreach(struct rb_id_table *tbl, rb_id_table_foreach_func_t *func, void *data)
rb_id_table_iterator_result
Thin wrapper to ruby/config.h.
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
void rb_thread_wait_for(struct timeval)
char * ruby_strdup(const char *)
Internal header for Class.
#define RCLASS_CONST_TBL(c)
Internal header for Fiber.
Internal header for File.
Internal header for Hash.
VALUE rb_vm_top_self(void)
VALUE rb_iseq_path(const rb_iseq_t *iseq)
#define ALLOCA_N(type, n)
#define MJIT_HEADER_INSTALL_DIR
#define MJIT_MIN_HEADER_NAME
#define append_str(p, str)
#define append_str2(p, str, len)
struct mjit_options mjit_opts
#define StringValuePtr(v)
VALUE ruby_archlibdir_path
unsigned LONG_LONG rb_serial_t
size_t strlen(const char *)
rb_execution_context_t * ec
rb_iseq_location_t location
struct rb_iseq_constant_body * body
struct rb_mjit_compile_info compile_info
void rb_native_cond_initialize(rb_nativethread_cond_t *cond)
void rb_native_cond_broadcast(rb_nativethread_cond_t *cond)
void rb_native_mutex_initialize(rb_nativethread_lock_t *lock)
void rb_native_mutex_destroy(rb_nativethread_lock_t *lock)
void rb_native_cond_destroy(rb_nativethread_cond_t *cond)
void rb_native_cond_wait(rb_nativethread_cond_t *cond, rb_nativethread_lock_t *mutex)
#define RUBY_VM_CHECK_INTS(ec)
Internal header to suppres / mandate warnings.
UINT rb_w32_system_tmpdir(WCHAR *path, UINT len)
#define access(path, mode)