summaryrefslogtreecommitdiff
path: root/mjit_worker.c
diff options
context:
space:
mode:
authorTakashi Kokubun <takashikkbn@gmail.com>2020-11-22 15:10:44 (GMT)
committerGitHub <noreply@github.com>2020-11-22 15:10:44 (GMT)
commitfa1250a506e9b6a1bcbf664f6b7b9c06e045d9b9 (patch)
tree794ba06e9a6ddee9d7cf07e2759d189684657c33 /mjit_worker.c
parent175952bf0779f236be643880f8a04b9d46dcd083 (diff)
Stop leaving .c files for JIT compaction in /tmp (#3802)
* Re-generate C files for JIT compaction every time * Refactor in_jit return logic * Just write code in a single file * Add a TODO comment [ci skip]
Notes
Notes: Merged-By: k0kubun <takashikkbn@gmail.com>
Diffstat (limited to 'mjit_worker.c')
-rw-r--r--mjit_worker.c106
1 files changed, 52 insertions, 54 deletions
diff --git a/mjit_worker.c b/mjit_worker.c
index d376134..2271bbe 100644
--- a/mjit_worker.c
+++ b/mjit_worker.c
@@ -153,14 +153,6 @@ struct rb_mjit_unit {
// Dlopen handle of the loaded object file.
void *handle;
rb_iseq_t *iseq;
-#if USE_JIT_COMPACTION
- // This value is always set for `compact_all_jit_code`. Also used for lazy deletion.
- char *c_file;
- // true if it's inherited from parent Ruby process and lazy deletion should be skipped.
- // `c_file = NULL` can't be used to skip lazy deletion because `c_file` could be used
- // by child for `compact_all_jit_code`.
- bool c_file_inherited_p;
-#endif
#if defined(_WIN32)
// DLL cannot be removed while loaded on Windows. If this is set, it'll be lazily deleted.
char *so_file;
@@ -397,23 +389,10 @@ remove_file(const char *filename)
}
}
-// Lazily delete .c and/or .so files.
+// Lazily delete .so files.
static void
clean_temp_files(struct rb_mjit_unit *unit)
{
-#if USE_JIT_COMPACTION
- if (unit->c_file) {
- char *c_file = unit->c_file;
-
- unit->c_file = NULL;
- // For compaction, unit->c_file is always set when compilation succeeds.
- // So save_temps needs to be checked here.
- if (!mjit_opts.save_temps && !unit->c_file_inherited_p)
- remove_file(c_file);
- free(c_file);
- }
-#endif
-
#if defined(_WIN32)
if (unit->so_file) {
char *so_file = unit->so_file;
@@ -921,13 +900,57 @@ compile_compact_jit_code(char* c_file)
compile_prelude(f);
- struct rb_mjit_unit *cur = 0;
- list_for_each(&active_units.head, cur, unode) {
- fprintf(f, "#include \"%s\"\n", cur->c_file);
+ // wait until mjit_gc_exit_hook is called
+ CRITICAL_SECTION_START(3, "before mjit_compile to wait GC finish");
+ while (in_gc) {
+ verbose(3, "Waiting wakeup from GC");
+ rb_native_cond_wait(&mjit_gc_wakeup, &mjit_engine_mutex);
+ }
+ // We need to check again here because we could've waited on GC above
+ bool iseq_gced = false;
+ struct rb_mjit_unit *child_unit = 0;
+ list_for_each(&active_units.head, child_unit, unode) {
+ if (child_unit->iseq == NULL) iseq_gced = true;
+ }
+ in_jit = !iseq_gced;
+ CRITICAL_SECTION_FINISH(3, "before mjit_compile to wait GC finish");
+ if (!in_jit) {
+ fclose(f);
+ if (!mjit_opts.save_temps)
+ remove_file(c_file);
+ return false;
+ }
+
+ // This entire loop lock GC so that we do not need to consider a case that
+ // ISeq is GC-ed in a middle of re-compilation. It takes 3~4ms with 100 methods
+ // on my machine. It's not too bad compared to compilation time of C (7200~8000ms),
+ // but it might be larger if we use a larger --jit-max-cache.
+ //
+ // TODO: Consider using a more granular lock after we implement inlining across
+ // compacted functions (not done yet).
+ bool success = true;
+ list_for_each(&active_units.head, child_unit, unode) {
+ char funcname[MAXPATHLEN];
+ sprint_funcname(funcname, child_unit);
+
+ long iseq_lineno = 0;
+ if (FIXNUM_P(child_unit->iseq->body->location.first_lineno))
+ // FIX2INT may fallback to rb_num2long(), which is a method call and dangerous in MJIT worker. So using only FIX2LONG.
+ iseq_lineno = FIX2LONG(child_unit->iseq->body->location.first_lineno);
+ fprintf(f, "\n/* %s@%s:%ld */\n", RSTRING_PTR(child_unit->iseq->body->location.label),
+ RSTRING_PTR(rb_iseq_path(child_unit->iseq)), iseq_lineno);
+ success &= mjit_compile(f, child_unit->iseq, funcname, child_unit->id);
}
+ // release blocking mjit_gc_start_hook
+ CRITICAL_SECTION_START(3, "after mjit_compile to wakeup client for GC");
+ in_jit = false;
+ verbose(3, "Sending wakeup signal to client in a mjit-worker for GC");
+ rb_native_cond_signal(&mjit_client_wakeup);
+ CRITICAL_SECTION_FINISH(3, "in worker to wakeup client for GC");
+
fclose(f);
- return true;
+ return success;
}
// Compile all cached .c files and build a single .so file. Reload all JIT func from it.
@@ -1046,10 +1069,6 @@ compile_prelude(FILE *f)
const char *s = pch_file;
const char *e = header_name_end(s);
-# if USE_JIT_COMPACTION
- fprintf(f, "#ifndef MJIT_PCH\n");
- fprintf(f, "#define MJIT_PCH\n");
-# endif
fprintf(f, "#include \"");
// print pch_file except .gch for gcc, but keep .pch for mswin
for (; s < e; s++) {
@@ -1060,9 +1079,6 @@ compile_prelude(FILE *f)
fputc(*s, f);
}
fprintf(f, "\"\n");
-# if USE_JIT_COMPACTION
- fprintf(f, "#endif\n");
-# endif
#endif
#ifdef _WIN32
@@ -1102,19 +1118,13 @@ convert_unit_to_func(struct rb_mjit_unit *unit)
verbose(3, "Waiting wakeup from GC");
rb_native_cond_wait(&mjit_gc_wakeup, &mjit_engine_mutex);
}
-
// We need to check again here because we could've waited on GC above
- if (unit->iseq == NULL) {
+ in_jit = (unit->iseq != NULL);
+ CRITICAL_SECTION_FINISH(3, "before mjit_compile to wait GC finish");
+ if (!in_jit) {
fclose(f);
if (!mjit_opts.save_temps)
remove_file(c_file);
- in_jit = false; // just being explicit for return
- }
- else {
- in_jit = true;
- }
- CRITICAL_SECTION_FINISH(3, "before mjit_compile to wait GC finish");
- if (!in_jit) {
return (mjit_func_t)NOT_COMPILED_JIT_ISEQ_FUNC;
}
@@ -1149,20 +1159,8 @@ convert_unit_to_func(struct rb_mjit_unit *unit)
double start_time = real_ms_time();
success = compile_c_to_so(c_file, so_file);
-#if USE_JIT_COMPACTION
- if (success) {
- // Always set c_file for compaction. The value is also used for lazy deletion.
- unit->c_file = strdup(c_file);
- if (unit->c_file == NULL) {
- mjit_warning("failed to allocate memory to remember '%s' (%s), removing it...", c_file, strerror(errno));
- }
- }
- if (!mjit_opts.save_temps && unit->c_file == NULL)
- remove_file(c_file);
-#else
if (!mjit_opts.save_temps)
remove_file(c_file);
-#endif
double end_time = real_ms_time();
if (!success) {