Skip to content

Commit b726c06

Browse files
committed
Allow hooking a different method after --mjit=pause
The interface is similar to RubyVM::ISeq.translate; it's used if defined. Same as --mjit=pause, this is an undocumented feature for MJIT experiments.
1 parent 341b40b commit b726c06

File tree

2 files changed

+39
-10
lines changed

2 files changed

+39
-10
lines changed

mjit.c

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,14 +1404,39 @@ mjit_target_iseq_p(const rb_iseq_t *iseq)
14041404
&& strcmp("<internal:mjit>", RSTRING_PTR(rb_iseq_path(iseq))) != 0;
14051405
}
14061406

1407+
// RubyVM::MJIT
1408+
static VALUE rb_mMJIT = 0;
1409+
// RubyVM::MJIT::C
1410+
VALUE rb_mMJITC = 0;
1411+
// RubyVM::MJIT::Compiler
1412+
VALUE rb_mMJITCompiler = 0;
1413+
1414+
// [experimental] Call custom RubyVM::MJIT.compile if defined
1415+
static void
1416+
mjit_hook_custom_compile(const rb_iseq_t *iseq)
1417+
{
1418+
bool original_call_p = mjit_call_p;
1419+
mjit_call_p = false; // Avoid impacting JIT metrics by itself
1420+
1421+
VALUE iseq_class = rb_funcall(rb_mMJITC, rb_intern("rb_iseq_t"), 0);
1422+
VALUE iseq_ptr = rb_funcall(iseq_class, rb_intern("new"), 1, ULONG2NUM((size_t)iseq));
1423+
VALUE jit_func = rb_funcall(rb_mMJIT, rb_intern("compile"), 1, iseq_ptr);
1424+
ISEQ_BODY(iseq)->jit_func = (mjit_func_t)NUM2ULONG(jit_func);
1425+
1426+
mjit_call_p = original_call_p;
1427+
}
1428+
14071429
// If recompile_p is true, the call is initiated by mjit_recompile.
14081430
// This assumes the caller holds CRITICAL_SECTION when recompile_p is true.
14091431
static void
14101432
mjit_add_iseq_to_process(const rb_iseq_t *iseq, const struct rb_mjit_compile_info *compile_info, bool recompile_p)
14111433
{
1412-
// TODO: Support non-main Ractors
1413-
if (!mjit_enabled || pch_status == PCH_FAILED || !rb_ractor_main_p())
1434+
if (!mjit_enabled || pch_status == PCH_FAILED || !rb_ractor_main_p()) // TODO: Support non-main Ractors
14141435
return;
1436+
if (mjit_opts.custom) {
1437+
mjit_hook_custom_compile(iseq);
1438+
return;
1439+
}
14151440
if (!mjit_target_iseq_p(iseq)) {
14161441
ISEQ_BODY(iseq)->jit_func = (mjit_func_t)NOT_COMPILED_JIT_ISEQ_FUNC; // skip mjit_wait
14171442
return;
@@ -1804,11 +1829,6 @@ const struct ruby_opt_message mjit_option_messages[] = {
18041829
};
18051830
#undef M
18061831

1807-
// RubyVM::MJIT::Compiler
1808-
VALUE rb_mMJITCompiler = 0;
1809-
// RubyVM::MJIT::C
1810-
VALUE rb_mMJITC = 0;
1811-
18121832
// Initialize MJIT. Start a thread creating the precompiled header and
18131833
// processing ISeqs. The function should be called first for using MJIT.
18141834
// If everything is successful, MJIT_INIT_P will be TRUE.
@@ -1819,7 +1839,7 @@ mjit_init(const struct mjit_options *opts)
18191839
mjit_opts = *opts;
18201840

18211841
// MJIT doesn't support miniruby, but it might reach here by MJIT_FORCE_ENABLE.
1822-
VALUE rb_mMJIT = rb_const_get(rb_cRubyVM, rb_intern("MJIT"));
1842+
rb_mMJIT = rb_const_get(rb_cRubyVM, rb_intern("MJIT"));
18231843
if (!rb_const_defined(rb_mMJIT, rb_intern("Compiler"))) {
18241844
verbose(1, "Disabling MJIT because RubyVM::MJIT::Compiler is not defined");
18251845
mjit_enabled = false;
@@ -1937,7 +1957,14 @@ mjit_resume(void)
19371957

19381958
// Lazily prepare PCH when --mjit=pause is given
19391959
if (pch_status == PCH_NOT_READY) {
1940-
make_pch();
1960+
if (rb_respond_to(rb_mMJITCompiler, rb_intern("compile"))) {
1961+
// [experimental] defining RubyVM::MJIT.compile allows you to replace JIT
1962+
mjit_opts.custom = true;
1963+
}
1964+
else {
1965+
// Lazy MJIT boot
1966+
make_pch();
1967+
}
19411968
}
19421969

19431970
if (!start_worker()) {

mjit.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@ struct mjit_options {
5959
// Maximal permitted number of iseq JIT codes in a MJIT memory
6060
// cache.
6161
int max_cache_size;
62-
// [experimental] If true, do not start MJIT until MJIT.resume is called.
62+
// [experimental] Do not start MJIT until MJIT.resume is called.
6363
bool pause;
64+
// [experimental] Call custom RubyVM::MJIT.compile instead of MJIT.
65+
bool custom;
6466
};
6567

6668
// State of optimization switches

0 commit comments

Comments
 (0)