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
4 changes: 4 additions & 0 deletions .github/workflows/zjit-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ jobs:

- run: make install

# setup/directories set MAKEFLAGS=-j4 for macOS, which randomly fails sqlite3.gem builds
- name: Unset MAKEFLAGS
run: echo "MAKEFLAGS=" >> "$GITHUB_ENV"

- name: Checkout ruby-bench
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
Expand Down
2 changes: 1 addition & 1 deletion class.c
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,7 @@ rb_class_classext_free_subclasses(rb_classext_t *ext, VALUE klass, bool replacin
}
VM_ASSERT(
rb_ns_subclasses_ref_count(anchor->ns_subclasses) > 0,
"ns_subclasses refcount (%p) %ld", anchor->ns_subclasses, rb_ns_subclasses_ref_count(anchor->ns_subclasses));
"ns_subclasses refcount (%p) %d", anchor->ns_subclasses, rb_ns_subclasses_ref_count(anchor->ns_subclasses));
st_delete(tbl, &ns_id, NULL);
rb_ns_subclasses_ref_dec(anchor->ns_subclasses);
xfree(anchor);
Expand Down
12 changes: 6 additions & 6 deletions internal/class.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,29 +28,29 @@
#endif

struct rb_ns_subclasses {
long refcount;
rb_atomic_t refcount;
struct st_table *tbl;
};
typedef struct rb_ns_subclasses rb_ns_subclasses_t;

static inline long
static inline rb_atomic_t
rb_ns_subclasses_ref_count(rb_ns_subclasses_t *ns_sub)
{
return ns_sub->refcount;
return ATOMIC_LOAD_RELAXED(ns_sub->refcount);
}

static inline rb_ns_subclasses_t *
rb_ns_subclasses_ref_inc(rb_ns_subclasses_t *ns_sub)
{
ns_sub->refcount++;
RUBY_ATOMIC_FETCH_ADD(ns_sub->refcount, 1);
return ns_sub;
}

static inline void
rb_ns_subclasses_ref_dec(rb_ns_subclasses_t *ns_sub)
{
ns_sub->refcount--;
if (ns_sub->refcount == 0) {
rb_atomic_t was = RUBY_ATOMIC_FETCH_SUB(ns_sub->refcount, 1);
if (was == 1) {
st_free_table(ns_sub->tbl);
xfree(ns_sub);
}
Expand Down
15 changes: 15 additions & 0 deletions test/ruby/test_class.rb
Original file line number Diff line number Diff line change
Expand Up @@ -887,4 +887,19 @@ def test_method_table_assignment_just_after_class_init
class C; end
end;
end

def test_subclasses_refcount_in_ractors
assert_ractor "#{<<~"begin;"}\n#{<<~'end;'}"
begin;
rs = []
8.times do
rs << Ractor.new do
5_000.times do
Class.new
end
end
end
rs.each(&:join)
end;
end
end
2 changes: 1 addition & 1 deletion vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -3445,7 +3445,7 @@ size_t rb_vm_memsize_workqueue(struct ccan_list_head *workqueue); // vm_trace.c
static enum rb_id_table_iterator_result
vm_memsize_constant_cache_i(ID id, VALUE ics, void *size)
{
*((size_t *) size) += rb_st_memsize((st_table *) ics);
*((size_t *) size) += rb_set_memsize((set_table *) ics);
return ID_TABLE_CONTINUE;
}

Expand Down
30 changes: 22 additions & 8 deletions vm_insnhelper.c
Original file line number Diff line number Diff line change
Expand Up @@ -5497,12 +5497,6 @@ vm_invoke_proc_block(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
return vm_invoke_block(ec, reg_cfp, calling, ci, is_lambda, block_handler);
}

enum rb_block_handler_type
rb_vm_block_handler_type(VALUE block_handler)
{
return vm_block_handler_type(block_handler);
}

static inline VALUE
vm_invoke_block(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
struct rb_calling_info *calling, const struct rb_callinfo *ci,
Expand Down Expand Up @@ -6065,10 +6059,30 @@ vm_define_method(const rb_execution_context_t *ec, VALUE obj, ID id, VALUE iseqv
}
}

// Return the untagged block handler:
// * If it's an ISEQ or an IFUNC, fetch it from its rb_captured_block
// * If it's a PROC or SYMBOL, return it as is
static VALUE
rb_vm_untag_block_handler(VALUE block_handler)
{
switch (vm_block_handler_type(block_handler)) {
case block_handler_type_iseq:
case block_handler_type_ifunc: {
struct rb_captured_block *captured = VM_TAGGED_PTR_REF(block_handler, 0x03);
return captured->code.val;
}
case block_handler_type_proc:
case block_handler_type_symbol:
return block_handler;
default:
rb_bug("rb_vm_untag_block_handler: unreachable");
}
}

VALUE
rb_vm_get_block_handler(rb_control_frame_t *reg_cfp)
rb_vm_get_untagged_block_handler(rb_control_frame_t *reg_cfp)
{
return VM_CF_BLOCK_HANDLER(reg_cfp);
return rb_vm_untag_block_handler(VM_CF_BLOCK_HANDLER(reg_cfp));
}

static VALUE
Expand Down
3 changes: 1 addition & 2 deletions zjit.c
Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,7 @@ rb_zjit_class_has_default_allocator(VALUE klass)
}


VALUE rb_vm_get_block_handler(rb_control_frame_t *reg_cfp);
enum rb_block_handler_type rb_vm_block_handler_type(VALUE block_handler);
VALUE rb_vm_get_untagged_block_handler(rb_control_frame_t *reg_cfp);

// Primitives used by zjit.rb. Don't put other functions below, which wouldn't use them.
VALUE rb_zjit_assert_compiles(rb_execution_context_t *ec, VALUE self);
Expand Down
3 changes: 1 addition & 2 deletions zjit/bindgen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,8 +399,7 @@ fn main() {
.allowlist_function("rb_yarv_str_eql_internal")
.allowlist_function("rb_str_neq_internal")
.allowlist_function("rb_yarv_ary_entry_internal")
.allowlist_function("rb_vm_get_block_handler")
.allowlist_function("rb_vm_block_handler_type")
.allowlist_function("rb_vm_get_untagged_block_handler")
.allowlist_function("rb_FL_TEST")
.allowlist_function("rb_FL_TEST_RAW")
.allowlist_function("rb_RB_TYPE_P")
Expand Down
3 changes: 2 additions & 1 deletion zjit/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2163,7 +2163,8 @@ fn gen_function_stub(cb: &mut CodeBlock, iseq_call: IseqCallRef) -> Result<CodeP
})
}

/// Generate a trampoline that is used when a
/// Generate a trampoline that is used when a function stub is called.
/// See [gen_function_stub] for how it's used.
pub fn gen_function_stub_hit_trampoline(cb: &mut CodeBlock) -> Result<CodePtr, CompileError> {
let (mut asm, scratch_reg) = Assembler::new_with_scratch_reg();
asm_comment!(asm, "function_stub_hit trampoline");
Expand Down
8 changes: 1 addition & 7 deletions zjit/src/cruby_bindings.inc.rs

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

5 changes: 2 additions & 3 deletions zjit/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4421,10 +4421,9 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let summary = TypeDistributionSummary::new(&self_type_distribution);
if summary.is_monomorphic() {
let obj = summary.bucket(0).class();
let bh_type = unsafe { rb_vm_block_handler_type(obj) };
if bh_type == block_handler_type_iseq {
if unsafe { rb_IMEMO_TYPE_P(obj, imemo_iseq) == 1 } {
fun.push_insn(block, Insn::IncrCounter(Counter::invokeblock_handler_monomorphic_iseq));
} else if bh_type == block_handler_type_ifunc {
} else if unsafe { rb_IMEMO_TYPE_P(obj, imemo_ifunc) == 1 } {
fun.push_insn(block, Insn::IncrCounter(Counter::invokeblock_handler_monomorphic_ifunc));
} else {
fun.push_insn(block, Insn::IncrCounter(Counter::invokeblock_handler_monomorphic_other));
Expand Down
2 changes: 1 addition & 1 deletion zjit/src/profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl Profiler {
}

fn peek_at_block_handler(&self) -> VALUE {
unsafe { rb_vm_get_block_handler(self.cfp) }
unsafe { rb_vm_get_untagged_block_handler(self.cfp) }
}
}

Expand Down
4 changes: 0 additions & 4 deletions zjit/src/stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,8 +331,6 @@ pub enum CompileError {
IseqStackTooLarge,
ExceptionHandler,
OutOfMemory,
RegisterSpillOnAlloc,
RegisterSpillOnCCall,
ParseError(ParseError),
JitToJitOptional,
}
Expand All @@ -347,8 +345,6 @@ pub fn exit_counter_for_compile_error(compile_error: &CompileError) -> Counter {
IseqStackTooLarge => compile_error_iseq_stack_too_large,
ExceptionHandler => compile_error_exception_handler,
OutOfMemory => compile_error_out_of_memory,
RegisterSpillOnAlloc => compile_error_register_spill_on_alloc,
RegisterSpillOnCCall => compile_error_register_spill_on_ccall,
JitToJitOptional => compile_error_jit_to_jit_optional,
ParseError(parse_error) => match parse_error {
StackUnderflow(_) => compile_error_parse_stack_underflow,
Expand Down