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
21 changes: 21 additions & 0 deletions bootstraptest/test_ractor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2370,3 +2370,24 @@ def call_test(obj)
:ok
end
RUBY

assert_equal 'ok', <<~'RUBY'
begin
100.times do |i|
Ractor.new(i) do |j|
1000.times do |i|
"#{j}-#{i}"
end
end
pid = fork do
GC.verify_internal_consistency
end
_, status = Process.waitpid2 pid
raise unless status.success?
end

:ok
rescue NotImplementedError
:ok
end
RUBY
9 changes: 4 additions & 5 deletions cont.c
Original file line number Diff line number Diff line change
Expand Up @@ -2005,10 +2005,9 @@ fiber_alloc(VALUE klass)
}

static rb_serial_t
next_fiber_serial(void)
next_fiber_serial(rb_ractor_t *cr)
{
static rbimpl_atomic_uint64_t fiber_serial = 1;
return (rb_serial_t)ATOMIC_U64_FETCH_ADD(fiber_serial, 1);
return cr->next_fiber_serial++;
}

static rb_fiber_t*
Expand All @@ -2027,7 +2026,7 @@ fiber_t_alloc(VALUE fiber_value, unsigned int blocking)
fiber->cont.type = FIBER_CONTEXT;
fiber->blocking = blocking;
fiber->killed = 0;
fiber->serial = next_fiber_serial();
fiber->serial = next_fiber_serial(th->ractor);
cont_init(&fiber->cont, th);

fiber->cont.saved_ec.fiber_ptr = fiber;
Expand Down Expand Up @@ -2580,7 +2579,7 @@ rb_threadptr_root_fiber_setup(rb_thread_t *th)
fiber->cont.saved_ec.thread_ptr = th;
fiber->blocking = 1;
fiber->killed = 0;
fiber->serial = next_fiber_serial();
fiber->serial = next_fiber_serial(th->ractor);
fiber_status_set(fiber, FIBER_RESUMED); /* skip CREATED */
th->ec = &fiber->cont.saved_ec;
cont_init_jit_cont(&fiber->cont);
Expand Down
12 changes: 11 additions & 1 deletion gc/default/default.c
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,8 @@ typedef struct rb_objspace {
rb_postponed_job_handle_t finalize_deferred_pjob;

unsigned long live_ractor_cache_count;

int fork_vm_lock_lev;
} rb_objspace_t;

#ifndef HEAP_PAGE_ALIGN_LOG
Expand Down Expand Up @@ -9324,12 +9326,20 @@ gc_malloc_allocations(VALUE self)
void
rb_gc_impl_before_fork(void *objspace_ptr)
{
/* no-op */
rb_objspace_t *objspace = objspace_ptr;

objspace->fork_vm_lock_lev = RB_GC_VM_LOCK();
rb_gc_vm_barrier();
}

void
rb_gc_impl_after_fork(void *objspace_ptr, rb_pid_t pid)
{
rb_objspace_t *objspace = objspace_ptr;

RB_GC_VM_UNLOCK(objspace->fork_vm_lock_lev);
objspace->fork_vm_lock_lev = 0;

if (pid == 0) { /* child process */
rb_gc_ractor_newobj_cache_foreach(gc_ractor_newobj_cache_clear, NULL);
}
Expand Down
1 change: 1 addition & 0 deletions insns.def
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ setinstancevariable
(VALUE val)
()
// attr bool leaf = false; /* has rb_check_frozen() */
// attr bool zjit_profile = true;
{
vm_setinstancevariable(GET_ISEQ(), GET_SELF(), id, val, ic);
}
Expand Down
2 changes: 2 additions & 0 deletions ractor.c
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ ractor_alloc(VALUE klass)
VALUE rv = TypedData_Make_Struct(klass, rb_ractor_t, &ractor_data_type, r);
FL_SET_RAW(rv, RUBY_FL_SHAREABLE);
r->pub.self = rv;
r->next_fiber_serial = 1;
VM_ASSERT(ractor_status_p(r, ractor_created));
return rv;
}
Expand All @@ -435,6 +436,7 @@ rb_ractor_main_alloc(void)
r->name = Qnil;
r->pub.self = Qnil;
r->newobj_cache = rb_gc_ractor_cache_alloc(r);
r->next_fiber_serial = 1;
ruby_single_main_ractor = r;

return r;
Expand Down
2 changes: 2 additions & 0 deletions ractor_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ struct rb_ractor_struct {

// ractor local data

rb_serial_t next_fiber_serial;

st_table *local_storage;
struct rb_id_table *idkey_local_storage;
VALUE local_storage_store_lock;
Expand Down
23 changes: 0 additions & 23 deletions ruby_atomic.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,27 +70,4 @@ rbimpl_atomic_u64_set_relaxed(volatile rbimpl_atomic_uint64_t *address, uint64_t
}
#define ATOMIC_U64_SET_RELAXED(var, val) rbimpl_atomic_u64_set_relaxed(&(var), val)

static inline uint64_t
rbimpl_atomic_u64_fetch_add(volatile rbimpl_atomic_uint64_t *ptr, uint64_t val)
{
#if defined(HAVE_GCC_ATOMIC_BUILTINS_64)
return __atomic_fetch_add(ptr, val, __ATOMIC_SEQ_CST);
#elif defined(_WIN32)
return InterlockedExchangeAdd64((volatile LONG64 *)ptr, val);
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
return atomic_add_64_nv(ptr, val) - val;
#elif defined(HAVE_STDATOMIC_H)
return atomic_fetch_add_explicit((_Atomic uint64_t *)ptr, val, memory_order_seq_cst);
#else
// Fallback using mutex for platforms without 64-bit atomics
static rb_nativethread_mutex_t lock = RB_NATIVETHREAD_LOCK_INIT;
rb_native_mutex_lock(&lock);
uint64_t old = *ptr;
*ptr = old + val;
rb_native_mutex_unlock(&lock);
return old;
#endif
}
#define ATOMIC_U64_FETCH_ADD(var, val) rbimpl_atomic_u64_fetch_add(&(var), val)

#endif
1 change: 1 addition & 0 deletions zjit/bindgen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ fn main() {
.allowlist_function("rb_shape_get_iv_index")
.allowlist_function("rb_shape_transition_add_ivar_no_warnings")
.allowlist_var("rb_invalid_shape_id")
.allowlist_type("shape_id_fl_type")
.allowlist_var("VM_KW_SPECIFIED_BITS_MAX")
.allowlist_var("SHAPE_ID_NUM_BITS")
.allowlist_function("rb_obj_is_kind_of")
Expand Down
4 changes: 4 additions & 0 deletions zjit/src/cruby.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,10 @@ impl ShapeId {
pub fn is_too_complex(self) -> bool {
unsafe { rb_jit_shape_too_complex_p(self.0) }
}

pub fn is_frozen(self) -> bool {
(self.0 & SHAPE_ID_FL_FROZEN) != 0
}
}

// Given an ISEQ pointer, convert PC to insn_idx
Expand Down
66 changes: 37 additions & 29 deletions zjit/src/cruby_bindings.inc.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 46 additions & 0 deletions zjit/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2873,6 +2873,50 @@ impl Function {
};
self.make_equal_to(insn_id, replacement);
}
Insn::SetIvar { self_val, id, val, state, ic: _ } => {
let frame_state = self.frame_state(state);
let Some(recv_type) = self.profiled_type_of_at(self_val, frame_state.insn_idx) else {
// No (monomorphic/skewed polymorphic) profile info
self.push_insn_id(block, insn_id); continue;
};
if recv_type.flags().is_immediate() {
// Instance variable lookups on immediate values are always nil
self.push_insn_id(block, insn_id); continue;
}
assert!(recv_type.shape().is_valid());
if !recv_type.flags().is_t_object() {
// Check if the receiver is a T_OBJECT
self.push_insn_id(block, insn_id); continue;
}
if recv_type.shape().is_too_complex() {
// too-complex shapes can't use index access
self.push_insn_id(block, insn_id); continue;
}
if recv_type.shape().is_frozen() {
// Can't set ivars on frozen objects
self.push_insn_id(block, insn_id); continue;
}
let mut ivar_index: u16 = 0;
if !unsafe { rb_shape_get_iv_index(recv_type.shape().0, id, &mut ivar_index) } {
// TODO(max): Shape transition
self.push_insn_id(block, insn_id); continue;
}
let self_val = self.push_insn(block, Insn::GuardType { val: self_val, guard_type: types::HeapBasicObject, state });
let self_val = self.push_insn(block, Insn::GuardShape { val: self_val, shape: recv_type.shape(), state });
// Current shape contains this ivar
let (ivar_storage, offset) = if recv_type.flags().is_embedded() {
// See ROBJECT_FIELDS() from include/ruby/internal/core/robject.h
let offset = ROBJECT_OFFSET_AS_ARY as i32 + (SIZEOF_VALUE * ivar_index.to_usize()) as i32;
(self_val, offset)
} else {
let as_heap = self.push_insn(block, Insn::LoadField { recv: self_val, id: ID!(_as_heap), offset: ROBJECT_OFFSET_AS_HEAP_FIELDS as i32, return_type: types::CPtr });
let offset = SIZEOF_VALUE_I32 * ivar_index as i32;
(as_heap, offset)
};
let replacement = self.push_insn(block, Insn::StoreField { recv: ivar_storage, id, offset, val });
self.push_insn(block, Insn::WriteBarrier { recv: self_val, val });
self.make_equal_to(insn_id, replacement);
}
_ => { self.push_insn_id(block, insn_id); }
}
}
Expand Down Expand Up @@ -4906,6 +4950,8 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
// profiled cfp->self.
if opcode == YARVINSN_getinstancevariable || opcode == YARVINSN_trace_getinstancevariable {
profiles.profile_self(&exit_state, self_param);
} else if opcode == YARVINSN_setinstancevariable || opcode == YARVINSN_trace_setinstancevariable {
profiles.profile_self(&exit_state, self_param);
} else if opcode == YARVINSN_definedivar || opcode == YARVINSN_trace_definedivar {
profiles.profile_self(&exit_state, self_param);
} else if opcode == YARVINSN_invokeblock || opcode == YARVINSN_trace_invokeblock {
Expand Down
Loading