@@ -1404,14 +1404,39 @@ mjit_target_iseq_p(const rb_iseq_t *iseq)
1404
1404
&& strcmp ("<internal:mjit>" , RSTRING_PTR (rb_iseq_path (iseq ))) != 0 ;
1405
1405
}
1406
1406
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
+
1407
1429
// If recompile_p is true, the call is initiated by mjit_recompile.
1408
1430
// This assumes the caller holds CRITICAL_SECTION when recompile_p is true.
1409
1431
static void
1410
1432
mjit_add_iseq_to_process (const rb_iseq_t * iseq , const struct rb_mjit_compile_info * compile_info , bool recompile_p )
1411
1433
{
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
1414
1435
return ;
1436
+ if (mjit_opts .custom ) {
1437
+ mjit_hook_custom_compile (iseq );
1438
+ return ;
1439
+ }
1415
1440
if (!mjit_target_iseq_p (iseq )) {
1416
1441
ISEQ_BODY (iseq )-> jit_func = (mjit_func_t )NOT_COMPILED_JIT_ISEQ_FUNC ; // skip mjit_wait
1417
1442
return ;
@@ -1804,11 +1829,6 @@ const struct ruby_opt_message mjit_option_messages[] = {
1804
1829
};
1805
1830
#undef M
1806
1831
1807
- // RubyVM::MJIT::Compiler
1808
- VALUE rb_mMJITCompiler = 0 ;
1809
- // RubyVM::MJIT::C
1810
- VALUE rb_mMJITC = 0 ;
1811
-
1812
1832
// Initialize MJIT. Start a thread creating the precompiled header and
1813
1833
// processing ISeqs. The function should be called first for using MJIT.
1814
1834
// If everything is successful, MJIT_INIT_P will be TRUE.
@@ -1819,7 +1839,7 @@ mjit_init(const struct mjit_options *opts)
1819
1839
mjit_opts = * opts ;
1820
1840
1821
1841
// 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" ));
1823
1843
if (!rb_const_defined (rb_mMJIT , rb_intern ("Compiler" ))) {
1824
1844
verbose (1 , "Disabling MJIT because RubyVM::MJIT::Compiler is not defined" );
1825
1845
mjit_enabled = false;
@@ -1937,7 +1957,14 @@ mjit_resume(void)
1937
1957
1938
1958
// Lazily prepare PCH when --mjit=pause is given
1939
1959
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
+ }
1941
1968
}
1942
1969
1943
1970
if (!start_worker ()) {
0 commit comments