mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Make mjit_cont sharable with YJIT (#6556)
* Make mjit_cont sharable with YJIT * Update dependencies * Update YJIT binding
This commit is contained in:
parent
07a93b1e37
commit
e7c71c6c92
Notes:
git
2022-10-17 16:28:19 +00:00
Merged-By: k0kubun <takashikkbn@gmail.com>
10 changed files with 160 additions and 127 deletions
20
common.mk
20
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
|
||||
|
|
133
cont.c
133
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;
|
||||
}
|
||||
|
||||
static void
|
||||
cont_init_mjit_cont(rb_context_t *cont)
|
||||
// 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)
|
||||
{
|
||||
VM_ASSERT(cont->mjit_cont == NULL);
|
||||
if (mjit_enabled) {
|
||||
cont->mjit_cont = mjit_cont_new(&(cont->saved_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_jit_cont(rb_context_t *cont)
|
||||
{
|
||||
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
|
||||
|
|
4
eval.c
4
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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
1
iseq.h
1
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[];
|
||||
|
||||
|
|
101
mjit.c
101
mjit.c
|
@ -951,34 +951,12 @@ 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) {
|
||||
if (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
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
@ -986,7 +964,6 @@ 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");
|
||||
|
|
4
mjit.h
4
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 */ }
|
||||
|
|
7
ruby.c
7
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)
|
||||
|
|
6
yjit.c
6
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);
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in a new issue