summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common.mk20
-rw-r--r--cont.c131
-rw-r--r--eval.c4
-rw-r--r--internal/cont.h5
-rw-r--r--iseq.h1
-rw-r--r--mjit.c103
-rw-r--r--mjit.h4
-rw-r--r--ruby.c7
-rw-r--r--yjit.c6
-rw-r--r--yjit/src/cruby_bindings.inc.rs4
10 files changed, 159 insertions, 126 deletions
diff --git a/common.mk b/common.mk
index 464f64cb76..934939ea4d 100644
--- a/common.mk
+++ b/common.mk
@@ -3564,6 +3564,7 @@ cont.$(OBJEXT): {$(VPATH)}internal/value_type.h
cont.$(OBJEXT): {$(VPATH)}internal/variable.h
cont.$(OBJEXT): {$(VPATH)}internal/warning_push.h
cont.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+cont.$(OBJEXT): {$(VPATH)}iseq.h
cont.$(OBJEXT): {$(VPATH)}method.h
cont.$(OBJEXT): {$(VPATH)}missing.h
cont.$(OBJEXT): {$(VPATH)}mjit.h
@@ -3580,6 +3581,8 @@ cont.$(OBJEXT): {$(VPATH)}thread_native.h
cont.$(OBJEXT): {$(VPATH)}vm_core.h
cont.$(OBJEXT): {$(VPATH)}vm_debug.h
cont.$(OBJEXT): {$(VPATH)}vm_opts.h
+cont.$(OBJEXT): {$(VPATH)}vm_sync.h
+cont.$(OBJEXT): {$(VPATH)}yjit.h
debug.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
debug.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
debug.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -6262,6 +6265,7 @@ eval.$(OBJEXT): $(hdrdir)/ruby/ruby.h
eval.$(OBJEXT): $(top_srcdir)/internal/array.h
eval.$(OBJEXT): $(top_srcdir)/internal/class.h
eval.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+eval.$(OBJEXT): $(top_srcdir)/internal/cont.h
eval.$(OBJEXT): $(top_srcdir)/internal/error.h
eval.$(OBJEXT): $(top_srcdir)/internal/eval.h
eval.$(OBJEXT): $(top_srcdir)/internal/gc.h
@@ -6902,6 +6906,7 @@ gc.$(OBJEXT): {$(VPATH)}internal/variable.h
gc.$(OBJEXT): {$(VPATH)}internal/warning_push.h
gc.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
gc.$(OBJEXT): {$(VPATH)}io.h
+gc.$(OBJEXT): {$(VPATH)}iseq.h
gc.$(OBJEXT): {$(VPATH)}method.h
gc.$(OBJEXT): {$(VPATH)}missing.h
gc.$(OBJEXT): {$(VPATH)}mjit.h
@@ -7124,6 +7129,10 @@ goruby.$(OBJEXT): {$(VPATH)}thread_native.h
goruby.$(OBJEXT): {$(VPATH)}vm_core.h
goruby.$(OBJEXT): {$(VPATH)}vm_debug.h
goruby.$(OBJEXT): {$(VPATH)}vm_opts.h
+hash.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+hash.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+hash.$(OBJEXT): $(CCAN_DIR)/list/list.h
+hash.$(OBJEXT): $(CCAN_DIR)/str/str.h
hash.$(OBJEXT): $(hdrdir)/ruby/ruby.h
hash.$(OBJEXT): $(top_srcdir)/internal/array.h
hash.$(OBJEXT): $(top_srcdir)/internal/bignum.h
@@ -7134,6 +7143,7 @@ hash.$(OBJEXT): $(top_srcdir)/internal/cont.h
hash.$(OBJEXT): $(top_srcdir)/internal/error.h
hash.$(OBJEXT): $(top_srcdir)/internal/gc.h
hash.$(OBJEXT): $(top_srcdir)/internal/hash.h
+hash.$(OBJEXT): $(top_srcdir)/internal/imemo.h
hash.$(OBJEXT): $(top_srcdir)/internal/object.h
hash.$(OBJEXT): $(top_srcdir)/internal/proc.h
hash.$(OBJEXT): $(top_srcdir)/internal/serial.h
@@ -7146,6 +7156,7 @@ hash.$(OBJEXT): $(top_srcdir)/internal/variable.h
hash.$(OBJEXT): $(top_srcdir)/internal/vm.h
hash.$(OBJEXT): $(top_srcdir)/internal/warnings.h
hash.$(OBJEXT): {$(VPATH)}assert.h
+hash.$(OBJEXT): {$(VPATH)}atomic.h
hash.$(OBJEXT): {$(VPATH)}backward/2/assume.h
hash.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
hash.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -7314,21 +7325,28 @@ hash.$(OBJEXT): {$(VPATH)}internal/value_type.h
hash.$(OBJEXT): {$(VPATH)}internal/variable.h
hash.$(OBJEXT): {$(VPATH)}internal/warning_push.h
hash.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+hash.$(OBJEXT): {$(VPATH)}iseq.h
+hash.$(OBJEXT): {$(VPATH)}method.h
hash.$(OBJEXT): {$(VPATH)}missing.h
+hash.$(OBJEXT): {$(VPATH)}node.h
hash.$(OBJEXT): {$(VPATH)}onigmo.h
hash.$(OBJEXT): {$(VPATH)}oniguruma.h
hash.$(OBJEXT): {$(VPATH)}probes.dmyh
hash.$(OBJEXT): {$(VPATH)}probes.h
hash.$(OBJEXT): {$(VPATH)}ractor.h
hash.$(OBJEXT): {$(VPATH)}ruby_assert.h
+hash.$(OBJEXT): {$(VPATH)}ruby_atomic.h
hash.$(OBJEXT): {$(VPATH)}shape.h
hash.$(OBJEXT): {$(VPATH)}st.h
hash.$(OBJEXT): {$(VPATH)}subst.h
hash.$(OBJEXT): {$(VPATH)}symbol.h
+hash.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
hash.$(OBJEXT): {$(VPATH)}thread_native.h
hash.$(OBJEXT): {$(VPATH)}transient_heap.h
hash.$(OBJEXT): {$(VPATH)}util.h
+hash.$(OBJEXT): {$(VPATH)}vm_core.h
hash.$(OBJEXT): {$(VPATH)}vm_debug.h
+hash.$(OBJEXT): {$(VPATH)}vm_opts.h
hash.$(OBJEXT): {$(VPATH)}vm_sync.h
inits.$(OBJEXT): $(hdrdir)/ruby.h
inits.$(OBJEXT): $(hdrdir)/ruby/ruby.h
@@ -13408,6 +13426,7 @@ ruby.$(OBJEXT): $(top_srcdir)/internal/array.h
ruby.$(OBJEXT): $(top_srcdir)/internal/class.h
ruby.$(OBJEXT): $(top_srcdir)/internal/cmdlineopt.h
ruby.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/cont.h
ruby.$(OBJEXT): $(top_srcdir)/internal/error.h
ruby.$(OBJEXT): $(top_srcdir)/internal/file.h
ruby.$(OBJEXT): $(top_srcdir)/internal/gc.h
@@ -13598,6 +13617,7 @@ ruby.$(OBJEXT): {$(VPATH)}internal/variable.h
ruby.$(OBJEXT): {$(VPATH)}internal/warning_push.h
ruby.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
ruby.$(OBJEXT): {$(VPATH)}io.h
+ruby.$(OBJEXT): {$(VPATH)}iseq.h
ruby.$(OBJEXT): {$(VPATH)}method.h
ruby.$(OBJEXT): {$(VPATH)}missing.h
ruby.$(OBJEXT): {$(VPATH)}mjit.h
diff --git a/cont.c b/cont.c
index b6d26d716e..1ce60811d2 100644
--- a/cont.c
+++ b/cont.c
@@ -34,7 +34,9 @@ extern int madvise(caddr_t, size_t, int);
#include "internal/warnings.h"
#include "ruby/fiber/scheduler.h"
#include "mjit.h"
+#include "yjit.h"
#include "vm_core.h"
+#include "vm_sync.h"
#include "id_table.h"
#include "ractor_core.h"
@@ -67,6 +69,8 @@ static VALUE rb_cFiberPool;
#define FIBER_POOL_ALLOCATION_FREE
#endif
+#define jit_cont_enabled mjit_enabled // To be used by YJIT later
+
enum context_type {
CONTINUATION_CONTEXT = 0,
FIBER_CONTEXT = 1
@@ -195,6 +199,15 @@ struct fiber_pool {
size_t vm_stack_size;
};
+// Continuation contexts used by JITs
+struct rb_jit_cont {
+ rb_execution_context_t *ec; // continuation ec
+ struct rb_jit_cont *prev, *next; // used to form lists
+};
+
+// Doubly linked list for enumerating all on-stack ISEQs.
+static struct rb_jit_cont *first_jit_cont;
+
typedef struct rb_context_struct {
enum context_type type;
int argc;
@@ -212,8 +225,7 @@ typedef struct rb_context_struct {
rb_execution_context_t saved_ec;
rb_jmpbuf_t jmpbuf;
rb_ensure_entry_t *ensure_array;
- /* Pointer to MJIT info about the continuation. */
- struct mjit_cont *mjit_cont;
+ struct rb_jit_cont *jit_cont; // Continuation contexts for JITs
} rb_context_t;
@@ -1000,6 +1012,8 @@ fiber_is_root_p(const rb_fiber_t *fiber)
}
#endif
+static void jit_cont_free(struct rb_jit_cont *cont);
+
static void
cont_free(void *ptr)
{
@@ -1020,9 +1034,9 @@ cont_free(void *ptr)
RUBY_FREE_UNLESS_NULL(cont->saved_vm_stack.ptr);
- if (mjit_enabled) {
- VM_ASSERT(cont->mjit_cont != NULL);
- mjit_cont_free(cont->mjit_cont);
+ if (jit_cont_enabled) {
+ VM_ASSERT(cont->jit_cont != NULL);
+ jit_cont_free(cont->jit_cont);
}
/* free rb_cont_t or rb_fiber_t */
ruby_xfree(ptr);
@@ -1187,12 +1201,98 @@ cont_save_thread(rb_context_t *cont, rb_thread_t *th)
sec->machine.stack_end = NULL;
}
+// Register a new continuation with execution context `ec`. Return JIT info about
+// the continuation.
+static struct rb_jit_cont *
+jit_cont_new(rb_execution_context_t *ec)
+{
+ struct rb_jit_cont *cont;
+
+ // We need to use calloc instead of something like ZALLOC to avoid triggering GC here.
+ // When this function is called from rb_thread_alloc through rb_threadptr_root_fiber_setup,
+ // the thread is still being prepared and marking it causes SEGV.
+ cont = calloc(1, sizeof(struct rb_jit_cont));
+ if (cont == NULL)
+ rb_memerror();
+ cont->ec = ec;
+
+ RB_VM_LOCK_ENTER();
+ if (first_jit_cont == NULL) {
+ cont->next = cont->prev = NULL;
+ }
+ else {
+ cont->prev = NULL;
+ cont->next = first_jit_cont;
+ first_jit_cont->prev = cont;
+ }
+ first_jit_cont = cont;
+ RB_VM_LOCK_LEAVE();
+
+ return cont;
+}
+
+// Unregister continuation `cont`.
+static void
+jit_cont_free(struct rb_jit_cont *cont)
+{
+ RB_VM_LOCK_ENTER();
+ if (cont == first_jit_cont) {
+ first_jit_cont = cont->next;
+ if (first_jit_cont != NULL)
+ first_jit_cont->prev = NULL;
+ }
+ else {
+ cont->prev->next = cont->next;
+ if (cont->next != NULL)
+ cont->next->prev = cont->prev;
+ }
+ RB_VM_LOCK_LEAVE();
+
+ free(cont);
+}
+
+// Call a given callback against all on-stack ISEQs.
+void
+rb_jit_cont_each_iseq(rb_iseq_callback callback)
+{
+ struct rb_jit_cont *cont;
+ for (cont = first_jit_cont; cont != NULL; cont = cont->next) {
+ if (cont->ec->vm_stack == NULL)
+ continue;
+
+ const rb_control_frame_t *cfp;
+ for (cfp = RUBY_VM_END_CONTROL_FRAME(cont->ec) - 1; ; cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
+ const rb_iseq_t *iseq;
+ if (cfp->pc && (iseq = cfp->iseq) != NULL && imemo_type((VALUE)iseq) == imemo_iseq) {
+ callback(iseq);
+ }
+
+ if (cfp == cont->ec->cfp)
+ break; // reached the most recent cfp
+ }
+ }
+}
+
+// Finish working with continuation info.
+void
+rb_jit_cont_finish(void)
+{
+ if (!jit_cont_enabled)
+ return;
+
+ struct rb_jit_cont *cont, *next;
+ for (cont = first_jit_cont; cont != NULL; cont = next) {
+ next = cont->next;
+ xfree(cont);
+ }
+}
+
static void
-cont_init_mjit_cont(rb_context_t *cont)
+cont_init_jit_cont(rb_context_t *cont)
{
- VM_ASSERT(cont->mjit_cont == NULL);
- if (mjit_enabled) {
- cont->mjit_cont = mjit_cont_new(&(cont->saved_ec));
+ VM_ASSERT(cont->jit_cont == NULL);
+ if (jit_cont_enabled) {
+ cont->jit_cont = jit_cont_new(&(cont->saved_ec));
}
}
@@ -1211,7 +1311,7 @@ cont_init(rb_context_t *cont, rb_thread_t *th)
cont->saved_ec.local_storage = NULL;
cont->saved_ec.local_storage_recursive_hash = Qnil;
cont->saved_ec.local_storage_recursive_hash_for_trace = Qnil;
- cont_init_mjit_cont(cont);
+ cont_init_jit_cont(cont);
}
static rb_context_t *
@@ -1242,9 +1342,9 @@ rb_fiberptr_blocking(struct rb_fiber_struct *fiber)
// This is used for root_fiber because other fibers call cont_init_mjit_cont through cont_new.
void
-rb_fiber_init_mjit_cont(struct rb_fiber_struct *fiber)
+rb_fiber_init_jit_cont(struct rb_fiber_struct *fiber)
{
- cont_init_mjit_cont(&fiber->cont);
+ cont_init_jit_cont(&fiber->cont);
}
#if 0
@@ -2187,9 +2287,10 @@ rb_threadptr_root_fiber_setup(rb_thread_t *th)
fiber->blocking = 1;
fiber_status_set(fiber, FIBER_RESUMED); /* skip CREATED */
th->ec = &fiber->cont.saved_ec;
- // This skips mjit_cont_new for the initial thread because mjit_enabled is always false
- // at this point. mjit_init calls rb_fiber_init_mjit_cont again for this root_fiber.
- rb_fiber_init_mjit_cont(fiber);
+ // This skips jit_cont_new for the initial thread because rb_yjit_enabled_p() and
+ // mjit_enabled are false at this point. ruby_opt_init will call rb_fiber_init_jit_cont
+ // again for this root_fiber.
+ rb_fiber_init_jit_cont(fiber);
}
void
diff --git a/eval.c b/eval.c
index 9567f80150..f5c9c0f087 100644
--- a/eval.c
+++ b/eval.c
@@ -21,6 +21,7 @@
#include "gc.h"
#include "internal.h"
#include "internal/class.h"
+#include "internal/cont.h"
#include "internal/error.h"
#include "internal/eval.h"
#include "internal/hash.h"
@@ -251,7 +252,8 @@ rb_ec_cleanup(rb_execution_context_t *ec, int ex0)
}
}
- mjit_finish(true); // We still need ISeqs here.
+ mjit_finish(true); // We still need ISeqs here, so it's before rb_ec_finalize().
+ rb_jit_cont_finish();
rb_ec_finalize(ec);
diff --git a/internal/cont.h b/internal/cont.h
index abffc97104..0b669f0ad5 100644
--- a/internal/cont.h
+++ b/internal/cont.h
@@ -9,6 +9,7 @@
* @brief Internal header for Fiber.
*/
#include "ruby/ruby.h" /* for VALUE */
+#include "iseq.h"
struct rb_thread_struct; /* in vm_core.h */
struct rb_fiber_struct; /* in cont.c */
@@ -17,7 +18,9 @@ struct rb_execution_context_struct; /* in vm_core.c */
/* cont.c */
void rb_fiber_reset_root_local_storage(struct rb_thread_struct *);
void ruby_register_rollback_func_for_ensure(VALUE (*ensure_func)(VALUE), VALUE (*rollback_func)(VALUE));
-void rb_fiber_init_mjit_cont(struct rb_fiber_struct *fiber);
+void rb_fiber_init_jit_cont(struct rb_fiber_struct *fiber);
+void rb_jit_cont_each_iseq(rb_iseq_callback callback);
+void rb_jit_cont_finish(void);
VALUE rb_fiberptr_self(struct rb_fiber_struct *fiber);
unsigned int rb_fiberptr_blocking(struct rb_fiber_struct *fiber);
diff --git a/iseq.h b/iseq.h
index 98cf71d52c..d771874c2f 100644
--- a/iseq.h
+++ b/iseq.h
@@ -31,6 +31,7 @@ RUBY_EXTERN const int ruby_api_version[];
typedef struct rb_iseq_struct rb_iseq_t;
#define rb_iseq_t rb_iseq_t
#endif
+typedef void (*rb_iseq_callback)(const rb_iseq_t *);
extern const ID rb_iseq_shared_exc_local_tbl[];
diff --git a/mjit.c b/mjit.c
index 80743a150b..22da5fd45f 100644
--- a/mjit.c
+++ b/mjit.c
@@ -951,42 +951,19 @@ mjit_capture_cc_entries(const struct rb_iseq_constant_body *compiled_iseq, const
// Set up field `used_code_p` for unit iseqs whose iseq on the stack of ec.
static void
-mark_ec_units(rb_execution_context_t *ec)
+mark_iseq_units(const rb_iseq_t *iseq)
{
- const rb_control_frame_t *cfp;
-
- if (ec->vm_stack == NULL)
- return;
- for (cfp = RUBY_VM_END_CONTROL_FRAME(ec) - 1; ; cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
- const rb_iseq_t *iseq;
- if (cfp->pc && (iseq = cfp->iseq) != NULL
- && imemo_type((VALUE) iseq) == imemo_iseq
- && (ISEQ_BODY(iseq)->jit_unit) != NULL) {
- ISEQ_BODY(iseq)->jit_unit->used_code_p = true;
- }
-
- if (cfp == ec->cfp)
- break; // reached the most recent cfp
+ if (ISEQ_BODY(iseq)->jit_unit != NULL) {
+ ISEQ_BODY(iseq)->jit_unit->used_code_p = true;
}
}
-// MJIT info related to an existing continutaion.
-struct mjit_cont {
- rb_execution_context_t *ec; // continuation ec
- struct mjit_cont *prev, *next; // used to form lists
-};
-
-// Double linked list of registered continuations. This is used to detect
-// units which are in use in unload_units.
-static struct mjit_cont *first_cont;
-
// Unload JIT code of some units to satisfy the maximum permitted
// number of units with a loaded code.
static void
unload_units(void)
{
struct rb_mjit_unit *unit = 0, *next;
- struct mjit_cont *cont;
int units_num = active_units.length;
// For now, we don't unload units when ISeq is GCed. We should
@@ -1005,9 +982,7 @@ unload_units(void)
}
// All threads have a root_fiber which has a mjit_cont. Other normal fibers also
// have a mjit_cont. Thus we can check ISeqs in use by scanning ec of mjit_conts.
- for (cont = first_cont; cont != NULL; cont = cont->next) {
- mark_ec_units(cont->ec);
- }
+ rb_jit_cont_each_iseq(mark_iseq_units);
// TODO: check stale_units and unload unused ones! (note that the unit is not associated to ISeq anymore)
// Unload units whose total_calls is smaller than any total_calls in unit_queue.
@@ -1163,68 +1138,6 @@ free_list(struct rb_mjit_unit_list *list, bool close_handle_p)
list->length = 0;
}
-// Register a new continuation with execution context `ec`. Return MJIT info about
-// the continuation.
-struct mjit_cont *
-mjit_cont_new(rb_execution_context_t *ec)
-{
- struct mjit_cont *cont;
-
- // We need to use calloc instead of something like ZALLOC to avoid triggering GC here.
- // When this function is called from rb_thread_alloc through rb_threadptr_root_fiber_setup,
- // the thread is still being prepared and marking it causes SEGV.
- cont = calloc(1, sizeof(struct mjit_cont));
- if (cont == NULL)
- rb_memerror();
- cont->ec = ec;
-
- CRITICAL_SECTION_START(3, "in mjit_cont_new");
- if (first_cont == NULL) {
- cont->next = cont->prev = NULL;
- }
- else {
- cont->prev = NULL;
- cont->next = first_cont;
- first_cont->prev = cont;
- }
- first_cont = cont;
- CRITICAL_SECTION_FINISH(3, "in mjit_cont_new");
-
- return cont;
-}
-
-// Unregister continuation `cont`.
-void
-mjit_cont_free(struct mjit_cont *cont)
-{
- CRITICAL_SECTION_START(3, "in mjit_cont_new");
- if (cont == first_cont) {
- first_cont = cont->next;
- if (first_cont != NULL)
- first_cont->prev = NULL;
- }
- else {
- cont->prev->next = cont->next;
- if (cont->next != NULL)
- cont->next->prev = cont->prev;
- }
- CRITICAL_SECTION_FINISH(3, "in mjit_cont_new");
-
- free(cont);
-}
-
-// Finish work with continuation info.
-static void
-finish_conts(void)
-{
- struct mjit_cont *cont, *next;
-
- for (cont = first_cont; cont != NULL; cont = next) {
- next = cont->next;
- xfree(cont);
- }
-}
-
static void mjit_wait(struct rb_iseq_constant_body *body);
// Check the unit queue and start mjit_compile if nothing is in progress.
@@ -1889,13 +1802,6 @@ mjit_init(const struct mjit_options *opts)
rb_native_cond_initialize(&mjit_worker_wakeup);
rb_native_cond_initialize(&mjit_gc_wakeup);
- // Make sure the saved_ec of the initial thread's root_fiber is scanned by mark_ec_units.
- //
- // rb_threadptr_root_fiber_setup for the initial thread is called before mjit_init,
- // meaning mjit_cont_new is skipped for the root_fiber. Therefore we need to call
- // rb_fiber_init_mjit_cont again with mjit_enabled=true to set the root_fiber's mjit_cont.
- rb_fiber_init_mjit_cont(GET_EC()->fiber_ptr);
-
// If --mjit=pause is given, lazily start MJIT when RubyVM::MJIT.resume is called.
// You can use it to control MJIT warmup, or to customize the JIT implementation.
if (!mjit_opts.pause) {
@@ -2052,7 +1958,6 @@ mjit_finish(bool close_handle_p)
free_list(&active_units, close_handle_p);
free_list(&compact_units, close_handle_p);
free_list(&stale_units, close_handle_p);
- finish_conts();
mjit_enabled = false;
verbose(1, "Successful MJIT finish");
diff --git a/mjit.h b/mjit.h
index ed696b3ff7..7211e460ab 100644
--- a/mjit.h
+++ b/mjit.h
@@ -101,8 +101,6 @@ extern void mjit_init(const struct mjit_options *opts);
extern void mjit_free_iseq(const rb_iseq_t *iseq);
extern void mjit_update_references(const rb_iseq_t *iseq);
extern void mjit_mark(void);
-extern struct mjit_cont *mjit_cont_new(rb_execution_context_t *ec);
-extern void mjit_cont_free(struct mjit_cont *cont);
extern void mjit_mark_cc_entries(const struct rb_iseq_constant_body *const body);
extern void mjit_notify_waitpid(int exit_code);
@@ -120,8 +118,6 @@ void mjit_finish(bool close_handle_p);
# else // USE_MJIT
static inline void mjit_cancel_all(const char *reason){}
-static inline struct mjit_cont *mjit_cont_new(rb_execution_context_t *ec){return NULL;}
-static inline void mjit_cont_free(struct mjit_cont *cont){}
static inline void mjit_free_iseq(const rb_iseq_t *iseq){}
static inline void mjit_mark(void){}
static inline VALUE jit_exec(rb_execution_context_t *ec) { return Qundef; /* unreachable */ }
diff --git a/ruby.c b/ruby.c
index 752498f66c..0a3248f95f 100644
--- a/ruby.c
+++ b/ruby.c
@@ -44,6 +44,7 @@
#include "eval_intern.h"
#include "internal.h"
#include "internal/cmdlineopt.h"
+#include "internal/cont.h"
#include "internal/error.h"
#include "internal/file.h"
#include "internal/inits.h"
@@ -1618,6 +1619,12 @@ ruby_opt_init(ruby_cmdline_options_t *opt)
rb_call_builtin_inits();
ruby_init_prelude();
+ // Make sure the saved_ec of the initial thread's root_fiber is scanned by rb_jit_cont_each_ec.
+ //
+ // rb_threadptr_root_fiber_setup for the initial thread is called before rb_yjit_enabled_p()
+ // or mjit_enabled becomes true, meaning jit_cont_new is skipped for the root_fiber.
+ // Therefore we need to call this again here to set the root_fiber's jit_cont.
+ rb_fiber_init_jit_cont(GET_EC()->fiber_ptr);
#if USE_MJIT
// mjit_init is safe only after rb_call_builtin_inits defines RubyVM::MJIT::Compiler
if (opt->mjit.on)
diff --git a/yjit.c b/yjit.c
index a53e2ca709..2a523f9787 100644
--- a/yjit.c
+++ b/yjit.c
@@ -894,13 +894,11 @@ rb_assert_cme_handle(VALUE handle)
RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(handle, imemo_ment));
}
-typedef void (*iseq_callback)(const rb_iseq_t *);
-
// Heap-walking callback for rb_yjit_for_each_iseq().
static int
for_each_iseq_i(void *vstart, void *vend, size_t stride, void *data)
{
- const iseq_callback callback = (iseq_callback)data;
+ const rb_iseq_callback callback = (rb_iseq_callback)data;
VALUE v = (VALUE)vstart;
for (; v != (VALUE)vend; v += stride) {
void *ptr = asan_poisoned_object_p(v);
@@ -919,7 +917,7 @@ for_each_iseq_i(void *vstart, void *vend, size_t stride, void *data)
// Iterate through the whole GC heap and invoke a callback for each iseq.
// Used for global code invalidation.
void
-rb_yjit_for_each_iseq(iseq_callback callback)
+rb_yjit_for_each_iseq(rb_iseq_callback callback)
{
rb_objspace_each_objects(for_each_iseq_i, (void *)callback);
}
diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs
index e12ac9eef1..db124c9303 100644
--- a/yjit/src/cruby_bindings.inc.rs
+++ b/yjit/src/cruby_bindings.inc.rs
@@ -1244,6 +1244,7 @@ pub const YARVINSN_trace_putobject_INT2FIX_0_: ruby_vminsn_type = 200;
pub const YARVINSN_trace_putobject_INT2FIX_1_: ruby_vminsn_type = 201;
pub const VM_INSTRUCTION_SIZE: ruby_vminsn_type = 202;
pub type ruby_vminsn_type = u32;
+pub type rb_iseq_callback = ::std::option::Option<unsafe extern "C" fn(arg1: *const rb_iseq_t)>;
extern "C" {
pub fn rb_vm_insn_addr2opcode(addr: *const ::std::os::raw::c_void) -> ::std::os::raw::c_int;
}
@@ -1538,9 +1539,8 @@ extern "C" {
extern "C" {
pub fn rb_assert_cme_handle(handle: VALUE);
}
-pub type iseq_callback = ::std::option::Option<unsafe extern "C" fn(arg1: *const rb_iseq_t)>;
extern "C" {
- pub fn rb_yjit_for_each_iseq(callback: iseq_callback);
+ pub fn rb_yjit_for_each_iseq(callback: rb_iseq_callback);
}
extern "C" {
pub fn rb_yjit_obj_written(