Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/zjit-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ jobs:
rustup install ${{ matrix.rust_version }} --profile minimal
rustup default ${{ matrix.rust_version }}

- uses: taiki-e/install-action@288e746965032cfcc232e09af2daf5f23c14d780 # v2.86.1
- uses: taiki-e/install-action@b6b84cf49ebfe0176417bdce007c624f0db37f20 # v2.86.2
with:
tool: nextest@0.9
if: ${{ matrix.test_task == 'zjit-check' }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/zjit-ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ jobs:
ruby-version: '3.1'
bundler: none

- uses: taiki-e/install-action@288e746965032cfcc232e09af2daf5f23c14d780 # v2.86.1
- uses: taiki-e/install-action@b6b84cf49ebfe0176417bdce007c624f0db37f20 # v2.86.2
with:
tool: nextest@0.9
if: ${{ matrix.test_task == 'zjit-check' }}
Expand Down
32 changes: 13 additions & 19 deletions compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -1864,14 +1864,14 @@ update_lvar_state(const rb_iseq_t *iseq, int level, int idx)
iseq = ISEQ_BODY(iseq)->parent_iseq;
}

enum lvar_state *states = ISEQ_BODY(iseq)->lvar_states;
uint8_t *states = ISEQ_BODY(iseq)->lvar_states;
int table_idx = ISEQ_BODY(iseq)->local_table_size - idx;
switch (states[table_idx]) {
switch (iseq_lvar_state_get(states, table_idx)) {
case lvar_uninitialized:
states[table_idx] = lvar_initialized;
iseq_lvar_state_set(states, table_idx, lvar_initialized);
break;
case lvar_initialized:
states[table_idx] = lvar_reassigned;
iseq_lvar_state_set(states, table_idx, lvar_reassigned);
break;
case lvar_reassigned:
/* nothing */
Expand All @@ -1885,13 +1885,13 @@ static int
iseq_set_parameters_lvar_state(const rb_iseq_t *iseq)
{
for (unsigned int i=0; i<ISEQ_BODY(iseq)->param.size; i++) {
ISEQ_BODY(iseq)->lvar_states[i] = lvar_initialized;
iseq_lvar_state_set(ISEQ_BODY(iseq)->lvar_states, i, lvar_initialized);
}

int lead_num = ISEQ_BODY(iseq)->param.lead_num;
int opt_num = ISEQ_BODY(iseq)->param.opt_num;
for (int i=0; i<opt_num; i++) {
ISEQ_BODY(iseq)->lvar_states[lead_num + i] = lvar_uninitialized;
iseq_lvar_state_set(ISEQ_BODY(iseq)->lvar_states, lead_num + i, lvar_uninitialized);
}

return COMPILE_OK;
Expand Down Expand Up @@ -2257,13 +2257,7 @@ iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *
MEMCPY(ids, tbl->ids + offset, ID, size);
ISEQ_BODY(iseq)->local_table = ids;

enum lvar_state *states = ALLOC_N(enum lvar_state, size);
// fprintf(stderr, "iseq:%p states:%p size:%d\n", iseq, states, (int)size);
for (unsigned int i=0; i<size; i++) {
states[i] = lvar_uninitialized;
// fprintf(stderr, "id:%s\n", rb_id2name(ISEQ_BODY(iseq)->local_table[i]));
}
ISEQ_BODY(iseq)->lvar_states = states;
ISEQ_BODY(iseq)->lvar_states = ZALLOC_N(uint8_t, ISEQ_LVAR_STATES_BUFLEN(size));
}
ISEQ_BODY(iseq)->local_table_size = size;

Expand Down Expand Up @@ -12616,7 +12610,7 @@ typedef uint32_t ibf_offset_t;

#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
#ifdef RUBY_DEVEL
#define IBF_DEVEL_VERSION 6
#define IBF_DEVEL_VERSION 7
#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
#else
#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
Expand Down Expand Up @@ -13443,20 +13437,20 @@ static ibf_offset_t
ibf_dump_lvar_states(struct ibf_dump *dump, const rb_iseq_t *iseq)
{
const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
const int size = body->local_table_size;
IBF_W_ALIGN(enum lvar_state);
return ibf_dump_write(dump, body->lvar_states, sizeof(enum lvar_state) * (body->lvar_states ? size : 0));
const int size = ISEQ_LVAR_STATES_BUFLEN(body->local_table_size);
IBF_W_ALIGN(uint8_t);
return ibf_dump_write(dump, body->lvar_states, sizeof(uint8_t) * (body->lvar_states ? size : 0));
}

static enum lvar_state *
static uint8_t *
ibf_load_lvar_states(const struct ibf_load *load, ibf_offset_t lvar_states_offset, int size, const ID *local_table)
{
if (local_table == rb_iseq_shared_exc_local_tbl ||
size <= 0) {
return NULL;
}
else {
enum lvar_state *states = IBF_R(lvar_states_offset, enum lvar_state, size);
uint8_t *states = IBF_R(lvar_states_offset, uint8_t, ISEQ_LVAR_STATES_BUFLEN(size));
return states;
}
}
Expand Down
42 changes: 4 additions & 38 deletions gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,6 @@ typedef struct gc_function_map {
void (*writebarrier_unprotect)(void *objspace_ptr, VALUE obj);
void (*writebarrier_remember)(void *objspace_ptr, VALUE obj);
void (*obj_became_shareable)(void *objspace_ptr, VALUE obj);
void (*pin_in_flight_message)(void *objspace_ptr, VALUE obj);
// Heap walking
void (*each_objects)(void *objspace_ptr, int (*callback)(void *, void *, size_t, void *), void *data);
void (*each_objects_shareable)(void *objspace_ptr, int (*callback)(void *, void *, size_t, void *), void *data);
Expand Down Expand Up @@ -882,7 +881,6 @@ ruby_modular_gc_init(void)
load_modular_gc_func(writebarrier_unprotect);
load_modular_gc_func(writebarrier_remember);
load_modular_gc_func(obj_became_shareable);
load_modular_gc_func(pin_in_flight_message);
// Heap walking
load_modular_gc_func(each_objects);
load_modular_gc_func(each_objects_shareable);
Expand Down Expand Up @@ -987,7 +985,6 @@ ruby_modular_gc_init(void)
# define rb_gc_impl_writebarrier_unprotect rb_gc_functions.writebarrier_unprotect
# define rb_gc_impl_writebarrier_remember rb_gc_functions.writebarrier_remember
# define rb_gc_impl_obj_became_shareable rb_gc_functions.obj_became_shareable
# define rb_gc_impl_pin_in_flight_message rb_gc_functions.pin_in_flight_message
// Heap walking
# define rb_gc_impl_each_objects rb_gc_functions.each_objects
# define rb_gc_impl_each_objects_shareable rb_gc_functions.each_objects_shareable
Expand Down Expand Up @@ -3267,14 +3264,12 @@ rb_gc_mark_roots(void *objspace, const char **categoryp)
!rb_gc_impl_multi_objspace_p();

/* Mark the current Ractor's roots from its C structs (a local GC must not depend on
* heap wrapper traversal). A global GC does the same for every Ractor and re-pins
* the in-flight payloads whose shrefs its clear pass dropped. */
* heap wrapper traversal). A global GC does the same for every Ractor. */
MARK_CHECKPOINT("ractor");
if (global_gc) {
rb_ractor_t *r;
ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
rb_ractor_mark_local_roots(r);
rb_ractor_repin_in_flight(r);
}

/* Early in boot (before rb_ractor_main_setup) main is not in vm->ractor.set
Expand All @@ -3284,15 +3279,13 @@ rb_gc_mark_roots(void *objspace, const char **categoryp)
}
/* A Ractor that terminated (left vm->ractor.set) but whose struct is not freed
* still owns rb_gc_register_mark_object pins. Keep them alive until
* ractor_free hands them to main; an orphan (owner == NULL) was moved above. */
* ractor_free hands them to main; an orphan (owner == NULL) was moved above.
* The join value is not rooted here: ractor_mark marks it from the wrapper. */
for (size_t i = 0; i < vm->gc.zombie_objspaces_count; i++) {
rb_ractor_t *owner = vm->gc.zombie_objspaces[i].owner;
if (owner) {
rb_gc_mark_vm_stack_values((long)owner->registered_marks_cnt,
owner->registered_marks);
/* Keep a terminated Ractor's join value (read by Ractor#value) alive
* without depending on wrapper reachability. Threads are not walked. */
rb_ractor_mark_terminated_join_value(owner);
}
}

Expand Down Expand Up @@ -3346,15 +3339,6 @@ rb_gc_mark_roots(void *objspace, const char **categoryp)
if (vm_mark_needs_lock) vm_mark_lock_lev = RB_GC_VM_LOCK_NO_BARRIER();
rb_vm_mark(vm);

if (global_gc) {
/* Mark and pin the shareable REFs of in-flight (off-heap) move couriers,
* covering the transient window between queue and materialize frame. Only
* a global GC frees shareable objects, so only it needs this pass. */
MARK_CHECKPOINT("move_couriers");
void rb_ractor_move_courier_registry_mark(void);
rb_ractor_move_courier_registry_mark();
}

MARK_CHECKPOINT("global_tbl");
rb_gc_mark_global_tbl();

Expand Down Expand Up @@ -3757,14 +3741,6 @@ rb_gc_obj_became_shareable(VALUE obj)

/* Pin an in-flight message payload in its owner's (the sender's) objspace, so the
* sender's local GC keeps it alive while it sits in a queue the sender does not walk. */
void
rb_gc_pin_in_flight_message(VALUE obj)
{
if (RB_SPECIAL_CONST_P(obj)) return;

rb_gc_impl_pin_in_flight_message(rb_gc_get_objspace(), obj);
}

void
rb_gc_copy_attributes(VALUE dest, VALUE obj)
{
Expand Down Expand Up @@ -4159,11 +4135,8 @@ rb_gc_vm_refresh_zombie_pages(void)
vm->gc.zombie_total_pages = total;
}

/* Incremental marking only runs single-objspace; vm_insert_ractor0 calls this just
* before a second Ractor becomes visible so any cycle in progress finishes; a settle
* cannot resume, nor inheritance extend, another objspace's partial mark. */
void
rb_gc_finish_in_flight_gc(void)
rb_gc_rest(void)
{
rb_gc_impl_gc_rest(rb_gc_get_objspace());
}
Expand Down Expand Up @@ -4954,13 +4927,6 @@ rb_gc_vm_generic_fields_drain_dead(bool (*is_dead)(VALUE key))
rb_generic_fields_tables_foreach(gf_drain_table_cb, &ctx);
}

/* A wrapper exported from gc.c so a modular build's gc-impl can call it. */
bool
rb_gc_current_ractor_materializing_p(void)
{
return rb_ractor_materializing_p();
}

VALUE
rb_gc_vm_top_self(void)
{
Expand Down
34 changes: 4 additions & 30 deletions gc/default/default.c
Original file line number Diff line number Diff line change
Expand Up @@ -6415,15 +6415,13 @@ check_children_i(const VALUE child, void *ptr)
* unshareable parent holding an unrecorded foreign unshareable child would be
* invisible to both local GCs. The exception is a box's top_self, which every
* thread's th->top_self points at and which is VM-permanent. Skipped during a
* global GC: it clears every shref bit and keeps in-flight payloads alive by
* re-pinning, so the shref exemption would not fire, and its unified exact
* stop-the-world mark makes the invariant itself moot. */
* global GC: it clears every shref bit, so the shref exemption would not fire,
* and its unified exact stop-the-world mark makes the invariant itself moot. */
if (!data->parent_shareable &&
child != rb_gc_vm_top_self() &&
!MARKED_IN_BITMAP(GET_HEAP_SHAREABLE_BITS(child), child) &&
!MARKED_IN_BITMAP(GET_HEAP_SHREF_BITS(child), child) &&
!rb_gc_impl_during_global_gc_p(data->objspace) &&
!rb_gc_current_ractor_materializing_p() &&
!global_objspace->during_absorb) {
fprintf(stderr, "check_children_i: containment violation: "
"unshareable %s (objspace %p) -> foreign unshareable %s (objspace %p)\n",
Expand Down Expand Up @@ -6500,10 +6498,6 @@ root_scope_check_i(const char *category, VALUE obj, void *ptr)
if (MARKED_IN_BITMAP(GET_HEAP_SHAREABLE_BITS(obj), obj)) return;
if (MARKED_IN_BITMAP(GET_HEAP_SHREF_BITS(obj), obj)) return;
if (obj == rb_gc_vm_top_self()) return; /* VM-permanent (see check_children_i) */
/* A sender-resident snapshot being materialized by a receive is rooted through
* sync.materializing_copies: a foreign-unshareable root that is valid only while
* the copy runs (see check_children_i). */
if (rb_gc_current_ractor_materializing_p()) return;

fprintf(stderr, "root_scope_check_i: root category \"%s\" names a foreign "
"unshareable without a shref record: %s (owner %p, self %p)\n",
Expand Down Expand Up @@ -7843,26 +7837,6 @@ rb_gc_impl_obj_became_shareable(void *objspace_ptr, VALUE obj)
}
}

void
rb_gc_impl_pin_in_flight_message(void *objspace_ptr, VALUE obj)
{
if (RB_FL_TEST_RAW(obj, RUBY_FL_SHAREABLE)) return; /* pinned anyway */

/* The payload's pages belong to the sender, so a plain store is enough. */
struct heap_page *page = GET_HEAP_PAGE(obj);
if (!_MARKED_IN_BITMAP(page->shref_bits, page, obj)) {
_MARK_IN_BITMAP(page->shref_bits, page, obj);
page->flags.has_shref_objects = TRUE;
}
/* A shref bit only makes the object a root for the next local GC; it does not affect an
* in-progress global compaction's move decision (pinned_bits). Moving a payload node
* would break the address-keyed maps, dedup tables and pin lists, so pin it as well. */
rb_objspace_t *objspace = objspace_ptr;
if (objspace->flags.during_global_gc) {
gc_pin(objspace, obj);
}
}

void
rb_gc_impl_writebarrier_unprotect(void *objspace_ptr, VALUE obj)
{
Expand Down Expand Up @@ -9069,8 +9043,8 @@ gc_start_global(rb_objspace_t *driver, unsigned int reason, bool compact, bool a
}
}

/* steps 6-7: every Ractor's roots (gc.c walks them all and re-pins in-flight payloads),
* then one unified precise mark. A global GC does not go through gc_marks, so the marking
/* steps 6-7: every Ractor's roots (gc.c walks them all), then one unified precise
* mark. A global GC does not go through gc_marks, so the marking
* phase is opened here instead; it closes after rb_ractor_finish_marking below, which is
* where gc_marks_finish ends for a local collection. */
gc_marking_enter(driver);
Expand Down
1 change: 0 additions & 1 deletion gc/gc.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ MODULAR_GC_FN void rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func ca
MODULAR_GC_FN void rb_gc_vm_generic_fields_mark_foreach(int (*cb)(VALUE key, VALUE val, void *arg), void *arg);
MODULAR_GC_FN void rb_gc_vm_generic_fields_drain_dead(bool (*is_dead)(VALUE key));
/* Exemptions for the shareable containment verifier (called from a gc-impl). */
MODULAR_GC_FN bool rb_gc_current_ractor_materializing_p(void);
MODULAR_GC_FN VALUE rb_gc_vm_top_self(void);
MODULAR_GC_FN void rb_gc_update_object_references(void *objspace, VALUE obj);
MODULAR_GC_FN void rb_gc_update_vm_references(void *objspace);
Expand Down
1 change: 0 additions & 1 deletion gc/gc_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,6 @@ GC_IMPL_FN void rb_gc_impl_writebarrier(void *objspace_ptr, VALUE a, VALUE b);
GC_IMPL_FN void rb_gc_impl_writebarrier_unprotect(void *objspace_ptr, VALUE obj);
GC_IMPL_FN void rb_gc_impl_writebarrier_remember(void *objspace_ptr, VALUE obj);
GC_IMPL_FN void rb_gc_impl_obj_became_shareable(void *objspace_ptr, VALUE obj);
GC_IMPL_FN void rb_gc_impl_pin_in_flight_message(void *objspace_ptr, VALUE obj);
// Heap walking
GC_IMPL_FN void rb_gc_impl_each_objects(void *objspace_ptr, int (*callback)(void *, void *, size_t, void *), void *data);
GC_IMPL_FN void rb_gc_impl_each_objects_shareable(void *objspace_ptr, int (*callback)(void *, void *, size_t, void *), void *data);
Expand Down
6 changes: 0 additions & 6 deletions gc/mmtk/mmtk.c
Original file line number Diff line number Diff line change
Expand Up @@ -1265,12 +1265,6 @@ rb_gc_impl_obj_became_shareable(void *objspace_ptr, VALUE obj)
/* MMTk has no per-page shareable bits. */
}

void
rb_gc_impl_pin_in_flight_message(void *objspace_ptr, VALUE obj)
{
/* With a single objspace there is nothing to pin. */
}

void
rb_gc_impl_writebarrier_remember(void *objspace_ptr, VALUE obj)
{
Expand Down
3 changes: 1 addition & 2 deletions internal/gc.h
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,6 @@ rb_obj_atomic_write(
int rb_ec_stack_check(struct rb_execution_context_struct *ec);
void rb_gc_writebarrier_remember(VALUE obj);
void rb_gc_obj_became_shareable(VALUE obj);
void rb_gc_pin_in_flight_message(VALUE obj);
bool rb_gc_multi_objspace_p(void);
bool rb_gc_obj_foreign_p(VALUE obj);
void *rb_gc_objspace_alloc(void);
Expand All @@ -313,7 +312,7 @@ void rb_gc_zombie_objspaces_atfork(void);
void rb_gc_disable_holders_atfork(void);
void rb_gc_atfork_global_locks(void);
void rb_gc_stash_cleanup_objspace(void);
void rb_gc_finish_in_flight_gc(void);
void rb_gc_rest(void);
bool rb_gc_during_global_gc_p(void);
bool rb_gc_single_objspace_p(void);
const char *rb_obj_info(VALUE obj);
Expand Down
10 changes: 5 additions & 5 deletions internal/re.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@ long rb_reg_search0(VALUE, VALUE, long, int, int, VALUE *);
VALUE rb_reg_match_p(VALUE re, VALUE str, long pos);
VALUE rb_reg_regsub_match(VALUE str, VALUE src, VALUE match);
VALUE rb_match_init_copy(VALUE copy, VALUE orig);
/* MatchData transfer for the move courier (ractor.c). */
void *rb_match_move_dump(VALUE match, VALUE *regexp_out, VALUE *str_out, int *num_regs_out);
VALUE rb_match_move_alloc(VALUE klass, int num_regs);
void rb_match_move_load(VALUE match, VALUE regexp, VALUE str, int num_regs, const void *blob);
void rb_match_move_free(void *blob);
/* MatchData transfer for the Ractor courier (ractor.c). */
void *rb_match_blob_dump(VALUE match, VALUE *regexp_out, VALUE *str_out, int *num_regs_out, bool release_source);
VALUE rb_match_blob_alloc(VALUE klass, int num_regs);
void rb_match_blob_load(VALUE match, VALUE regexp, VALUE str, int num_regs, const void *blob);
void rb_match_blob_free(void *blob);
bool rb_reg_start_with_p(VALUE re, VALUE str);
VALUE rb_reg_hash(VALUE re);
VALUE rb_reg_equal(VALUE re1, VALUE re2);
Expand Down
1 change: 1 addition & 0 deletions internal/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ bool rb_obj_is_fstring_table(VALUE obj);
void Init_fstring_table();
VALUE rb_obj_as_string_result(VALUE str, VALUE obj);
VALUE rb_str_opt_plus(VALUE x, VALUE y);
VALUE rb_str_new_owned(char *ptr, long len, long capa, int encindex);
VALUE rb_str_concat_literals(size_t num, const VALUE *strary);
VALUE rb_str_eql(VALUE str1, VALUE str2);
VALUE rb_id_quote_unprintable(ID);
Expand Down
3 changes: 3 additions & 0 deletions internal/vm.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ VALUE rb_make_backtrace(void);
void rb_backtrace_print_as_bugreport(FILE*);
int rb_backtrace_p(VALUE obj);
VALUE rb_backtrace_dup(VALUE btobj);
void *rb_backtrace_blob_dump(VALUE btobj, int *size_out);
VALUE rb_backtrace_blob_load(const void *blob, int size);
void rb_backtrace_blob_mark(const void *blob, int size);
VALUE rb_backtrace_to_str_ary(VALUE obj);
VALUE rb_backtrace_to_location_ary(VALUE obj);
VALUE rb_location_ary_to_backtrace(VALUE ary);
Expand Down
4 changes: 2 additions & 2 deletions iseq.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ rb_iseq_free(const rb_iseq_t *iseq)
if (LIKELY(body->local_table != rb_iseq_shared_exc_local_tbl)) {
SIZED_FREE_N(body->local_table, body->local_table_size);
}
SIZED_FREE_N(body->lvar_states, body->local_table_size);
SIZED_FREE_N(body->lvar_states, ISEQ_LVAR_STATES_BUFLEN(body->local_table_size));

compile_data_free(ISEQ_COMPILE_DATA(iseq));
if (body->outer_variables) rb_id_table_free(body->outer_variables);
Expand Down Expand Up @@ -544,7 +544,7 @@ rb_iseq_memsize(const rb_iseq_t *iseq)
size += body->iseq_size * sizeof(VALUE);
size += body->insns_info.size * (sizeof(struct iseq_insn_info_entry) + sizeof(unsigned int));
size += body->local_table_size * sizeof(ID); // body->local_table
if (body->lvar_states) size += body->local_table_size * sizeof(enum lvar_state);
if (body->lvar_states) size += ISEQ_LVAR_STATES_BUFLEN(body->local_table_size) * sizeof(uint8_t);
size += ISEQ_MBITS_BUFLEN(body->iseq_size) * ISEQ_MBITS_SIZE;
if (body->catch_table) {
size += iseq_catch_table_bytes(body->catch_table->size);
Expand Down
Loading