25 mjit_copy_job_handler(
void *data)
32 CRITICAL_SECTION_START(3,
"in mjit_copy_job_handler");
38 CRITICAL_SECTION_FINISH(3,
"in mjit_copy_job_handler");
43 CRITICAL_SECTION_FINISH(3,
"in mjit_copy_job_handler");
53 for (i = 0; i < body->
ci_size; i++) {
54 *sink++ = calls[i].
cc;
57 *sink++ = kw_calls[i].
cc;
66 CRITICAL_SECTION_FINISH(3,
"in mjit_copy_job_handler");
69 extern int rb_thread_create_mjit_thread(
void (*worker_func)(
void));
75 get_uniq_filename(
unsigned long id,
const char *prefix,
const char *suffix)
77 char buff[70], *
str = buff;
78 int size = sprint_uniq_filename(buff,
sizeof(buff),
id, prefix, suffix);
82 if (
size <= (
int)
sizeof(buff)) {
86 sprint_uniq_filename(
str,
size,
id, prefix, suffix);
94 mjit_gc_start_hook(
void)
98 CRITICAL_SECTION_START(4,
"mjit_gc_start_hook");
100 verbose(4,
"Waiting wakeup from a worker for GC");
102 verbose(4,
"Getting wakeup from a worker for GC");
105 CRITICAL_SECTION_FINISH(4,
"mjit_gc_start_hook");
111 mjit_gc_exit_hook(
void)
115 CRITICAL_SECTION_START(4,
"mjit_gc_exit_hook");
117 verbose(4,
"Sending wakeup signal to workers after GC");
119 CRITICAL_SECTION_FINISH(4,
"mjit_gc_exit_hook");
124 mjit_update_references(
const rb_iseq_t *iseq)
129 CRITICAL_SECTION_START(4,
"mjit_update_references");
130 if (iseq->
body->jit_unit) {
142 list_for_each(&stale_units.head, unit,
unode) {
147 CRITICAL_SECTION_FINISH(4,
"mjit_update_references");
158 CRITICAL_SECTION_START(4,
"mjit_free_iseq");
159 if (mjit_copy_job.iseq ==
iseq) {
160 mjit_copy_job.iseq =
NULL;
171 list_for_each(&stale_units.head, unit,
unode) {
176 CRITICAL_SECTION_FINISH(4,
"mjit_free_iseq");
187 list_for_each_safe(&
list->head, unit, next,
unode) {
188 list_del(&unit->
unode);
191 if (
list == &stale_units) {
197 mjit_warning(
"failed to close handle for u%d: %s", unit->
id, dlerror());
199 clean_object_files(unit);
212 struct mjit_cont *prev, *next;
217 static struct mjit_cont *first_cont;
224 struct mjit_cont *cont;
226 cont =
ZALLOC(
struct mjit_cont);
229 CRITICAL_SECTION_START(3,
"in mjit_cont_new");
230 if (first_cont ==
NULL) {
231 cont->next = cont->prev =
NULL;
235 cont->next = first_cont;
236 first_cont->prev = cont;
239 CRITICAL_SECTION_FINISH(3,
"in mjit_cont_new");
246 mjit_cont_free(
struct mjit_cont *cont)
248 CRITICAL_SECTION_START(3,
"in mjit_cont_new");
249 if (cont == first_cont) {
250 first_cont = cont->next;
251 if (first_cont !=
NULL)
252 first_cont->prev =
NULL;
255 cont->prev->next = cont->next;
256 if (cont->next !=
NULL)
257 cont->next->prev = cont->prev;
259 CRITICAL_SECTION_FINISH(3,
"in mjit_cont_new");
268 struct mjit_cont *cont, *next;
270 for (cont = first_cont; cont !=
NULL; cont = next) {
286 unit->
id = current_unit_num++;
320 struct mjit_cont *cont;
321 int delete_num, units_num = active_units.length;
325 list_for_each_safe(&active_units.head, unit, next, unode) {
327 remove_from_list(unit, &active_units);
333 list_for_each(&active_units.head, unit, unode) {
338 mark_ec_units(th->
ec);
340 for (cont = first_cont; cont !=
NULL; cont = cont->next) {
341 mark_ec_units(cont->ec);
348 delete_num = active_units.length / 10;
349 for (; active_units.length >
mjit_opts.max_cache_size - delete_num;) {
352 list_for_each(&active_units.head, unit, unode) {
356 if (worst ==
NULL || worst->iseq->body->total_calls > unit->
iseq->
body->total_calls) {
364 verbose(2,
"Unloading unit %d (calls=%lu)", worst->id, worst->iseq->body->total_calls);
366 remove_from_list(worst, &active_units);
370 if (units_num == active_units.length &&
mjit_opts.wait) {
372 verbose(1,
"No units can be unloaded -- incremented max-cache-size to %d for --jit-wait",
mjit_opts.max_cache_size);
375 verbose(1,
"Too many JIT code -- %d units unloaded", units_num - active_units.length);
380 mjit_add_iseq_to_process(
const rb_iseq_t *iseq,
const struct rb_mjit_compile_info *compile_info)
385 iseq->
body->jit_func = (mjit_func_t)NOT_READY_JIT_ISEQ_FUNC;
390 if (compile_info !=
NULL)
391 iseq->
body->jit_unit->compile_info = *compile_info;
393 CRITICAL_SECTION_START(3,
"in add_iseq_to_process");
394 add_to_list(iseq->
body->jit_unit, &unit_queue);
395 if (active_units.length >=
mjit_opts.max_cache_size) {
398 verbose(3,
"Sending wakeup signal to workers in mjit_add_iseq_to_process");
400 CRITICAL_SECTION_FINISH(3,
"in add_iseq_to_process");
406 rb_mjit_add_iseq_to_process(
const rb_iseq_t *iseq)
408 mjit_add_iseq_to_process(iseq,
NULL);
412 #define MJIT_WAIT_TIMEOUT_SECONDS 60
421 while (body->jit_func == (mjit_func_t)NOT_READY_JIT_ISEQ_FUNC) {
423 if (tries / 1000 > MJIT_WAIT_TIMEOUT_SECONDS || pch_status ==
PCH_FAILED) {
424 CRITICAL_SECTION_START(3,
"in rb_mjit_wait_call to set jit_func");
425 body->jit_func = (mjit_func_t)NOT_COMPILED_JIT_ISEQ_FUNC;
426 CRITICAL_SECTION_FINISH(3,
"in rb_mjit_wait_call to set jit_func");
431 CRITICAL_SECTION_START(3,
"in rb_mjit_wait_call for a client wakeup");
433 CRITICAL_SECTION_FINISH(3,
"in rb_mjit_wait_call for a client wakeup");
447 return body->jit_func(ec, ec->
cfp);
450 struct rb_mjit_compile_info*
454 return &body->jit_unit->compile_info;
458 rb_mjit_recompile_iseq(
const rb_iseq_t *iseq)
466 CRITICAL_SECTION_START(3,
"in rb_mjit_recompile_iseq");
467 remove_from_list(iseq->
body->jit_unit, &active_units);
468 iseq->
body->jit_func = (
void *)NOT_ADDED_JIT_ISEQ_FUNC;
469 add_to_list(iseq->
body->jit_unit, &stale_units);
470 CRITICAL_SECTION_FINISH(3,
"in rb_mjit_recompile_iseq");
472 mjit_add_iseq_to_process(iseq, &iseq->
body->jit_unit->compile_info);
474 mjit_wait(iseq->
body);
482 init_header_filename(
void)
489 const char *basedir =
"";
493 static const char libpathflag[] =
500 const size_t libpathflag_len =
sizeof(libpathflag) - 1;
508 if (
getenv(
"MJIT_SEARCH_BUILD_DIR")) {
518 else if (hdr[0] !=
'/') {
519 verbose(1,
"Non-absolute header file path: %s", hdr);
522 verbose(1,
"Non-file header file path: %s", hdr);
524 else if ((st.st_uid !=
getuid()) || (st.st_mode & 022) ||
526 verbose(1,
"Unsafe header file: uid=%ld mode=%#o %s",
527 (
long)st.st_uid, (
unsigned)st.st_mode, hdr);
536 verbose(3,
"MJIT_HEADER: %s", hdr);
538 if (!header_file)
return false;
547 const size_t header_name_len =
sizeof(header_name) - 1;
549 header_file =
xmalloc(baselen + header_name_len + 1);
551 p =
append_str2(p, header_name, header_name_len + 1);
554 verbose(1,
"Cannot access header file: %s", header_file);
566 const size_t pch_name_len =
sizeof(pch_name) - 1;
568 pch_file =
xmalloc(baselen + pch_name_len + 1);
572 verbose(1,
"Cannot access precompiled header file: %s", pch_file);
585 libruby_pathflag = p =
xmalloc(libpathflag_len + baselen + 1);
595 valid_class_serials_add_i(
ID key,
VALUE v,
void *unused)
612 system_default_tmpdir(
void)
616 WCHAR tmppath[_MAX_PATH];
619 int blen = WideCharToMultiByte(CP_UTF8, 0, tmppath,
len,
NULL, 0,
NULL,
NULL);
620 char *tmpdir =
xmalloc(blen + 1);
621 WideCharToMultiByte(CP_UTF8, 0, tmppath,
len, tmpdir, blen,
NULL,
NULL);
625 #elif defined _CS_DARWIN_USER_TEMP_DIR
627 size_t len = confstr(_CS_DARWIN_USER_TEMP_DIR, path,
sizeof(path));
630 if (
len >
sizeof(path)) {
631 confstr(_CS_DARWIN_USER_TEMP_DIR, tmpdir,
len);
643 check_tmpdir(
const char *dir)
647 if (!dir)
return FALSE;
650 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
659 if (!(st.st_mode & S_ISVTX))
return FALSE;
673 # define RETURN_ENV(name) \
674 if (check_tmpdir(tmpdir = getenv(name))) return ruby_strdup(tmpdir)
675 RETURN_ENV(
"TMPDIR");
677 tmpdir = system_default_tmpdir();
678 if (check_tmpdir(tmpdir))
return tmpdir;
684 #define MIN_CACHE_SIZE 10
686 #define DEFAULT_MAX_CACHE_SIZE 100
688 #define DEFAULT_MIN_CALLS_TO_ADD 10000
694 stop_worker_p =
false;
695 worker_stopped =
false;
704 verbose(1,
"Failure in MJIT thread initialization\n");
712 ruby_strndup(
const char *
str,
size_t n)
723 split_flags(
const char *flags)
728 for (; flags !=
NULL; flags = next) {
729 next =
strchr(flags,
' ');
736 buf[i++] = ruby_strndup(flags, next - flags);
741 char **ret =
xmalloc(
sizeof(
char *) * (i + 1));
751 mjit_init(
const struct mjit_options *opts)
759 mjit_opts.min_calls = DEFAULT_MIN_CALLS_TO_ADD;
761 mjit_opts.max_cache_size = DEFAULT_MAX_CACHE_SIZE;
762 if (
mjit_opts.max_cache_size < MIN_CACHE_SIZE)
763 mjit_opts.max_cache_size = MIN_CACHE_SIZE;
771 cc_path = CC_COMMON_ARGS[0];
772 verbose(2,
"MJIT: CC defaults to %s", cc_path);
773 cc_common_args =
xmalloc(
sizeof(CC_COMMON_ARGS));
774 memcpy((
void *)cc_common_args, CC_COMMON_ARGS,
sizeof(CC_COMMON_ARGS));
775 cc_added_args = split_flags(opts->debug_flags);
776 xfree(opts->debug_flags);
779 for (
size_t i = 0, j = 0; i <
sizeof(CC_COMMON_ARGS) /
sizeof(
char *); i++) {
780 if (CC_COMMON_ARGS[i] && strncmp(
"-save-temps", CC_COMMON_ARGS[i],
strlen(
"-save-temps")) == 0)
782 cc_common_args[j] = CC_COMMON_ARGS[i];
787 tmp_dir = system_tmpdir();
788 verbose(2,
"MJIT: tmp_dir is %s", tmp_dir);
790 if (!init_header_filename()) {
792 verbose(1,
"Failure in MJIT header file name initialization\n");
795 pch_owner_pid = getpid();
826 while (!worker_stopped) {
827 verbose(3,
"Sending cancel signal to worker");
828 CRITICAL_SECTION_START(3,
"in stop_worker");
829 stop_worker_p =
true;
831 CRITICAL_SECTION_FINISH(3,
"in stop_worker");
838 mjit_pause(
bool wait_p)
843 if (worker_stopped) {
853 while (unit_queue.length > 0 && active_units.length <
mjit_opts.max_cache_size) {
854 CRITICAL_SECTION_START(3,
"in mjit_pause for a worker wakeup");
856 CRITICAL_SECTION_FINISH(3,
"in mjit_pause for a worker wakeup");
872 if (!worker_stopped) {
876 if (!start_worker()) {
889 list_for_each_safe(&
list->head, unit, next,
unode) {
890 #ifndef _MSC_VER // Actually mswin does not reach here since it doesn't have fork
894 #if defined(_WIN32) // mswin doesn't reach here either. This is for MinGW.
895 if (unit->so_file) unit->so_file =
NULL;
916 mjit_child_after_fork(
void)
923 skip_cleaning_object_files(&active_units);
936 mjit_finish(
bool close_handle_p)
942 verbose(2,
"Stopping worker thread");
943 CRITICAL_SECTION_START(3,
"in mjit_finish to wakeup from pch");
950 verbose(3,
"Waiting wakeup from make_pch");
953 CRITICAL_SECTION_FINISH(3,
"in mjit_finish to wakeup from pch");
964 #ifndef _MSC_VER // mswin has prebuilt precompiled header
965 if (!
mjit_opts.save_temps && getpid() == pch_owner_pid)
966 remove_file(pch_file);
970 xfree((
void *)cc_common_args); cc_common_args =
NULL;
971 for (
char **flag = cc_added_args; *flag !=
NULL; flag++)
973 xfree((
void *)cc_added_args); cc_added_args =
NULL;
978 free_list(&unit_queue, close_handle_p);
979 free_list(&active_units, close_handle_p);
980 free_list(&compact_units, close_handle_p);
981 free_list(&stale_units, close_handle_p);
985 verbose(1,
"Successful MJIT finish");
995 CRITICAL_SECTION_START(4,
"mjit_mark");
997 CRITICAL_SECTION_FINISH(4,
"mjit_mark");
1004 CRITICAL_SECTION_START(4,
"mjit_mark");
1005 list_for_each(&unit_queue.head, unit,
unode) {
1008 CRITICAL_SECTION_FINISH(4,
"mjit_mark rb_gc_mark");
1014 CRITICAL_SECTION_START(4,
"mjit_mark rb_gc_mark");
1017 CRITICAL_SECTION_FINISH(4,
"mjit_mark");
1036 mjit_remove_class_serial(
rb_serial_t class_serial)
1041 CRITICAL_SECTION_START(3,
"in mjit_remove_class_serial");
1043 CRITICAL_SECTION_FINISH(3,
"in mjit_remove_class_serial");