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
17 changes: 16 additions & 1 deletion set.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,14 @@ struct set_object {
set_table table;
};

static int
mark_and_pin_key(st_data_t key, st_data_t data)
{
rb_gc_mark((VALUE)key);

return ST_CONTINUE;
}

static int
mark_key(st_data_t key, st_data_t data)
{
Expand All @@ -135,7 +143,14 @@ static void
set_mark(void *ptr)
{
struct set_object *sobj = ptr;
if (sobj->table.entries) set_table_foreach(&sobj->table, mark_key, 0);
if (sobj->table.entries) {
if (sobj->table.type == &identhash) {
set_table_foreach(&sobj->table, mark_and_pin_key, 0);
}
else {
set_table_foreach(&sobj->table, mark_key, 0);
}
}
}

static void
Expand Down
19 changes: 19 additions & 0 deletions test/ruby/test_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -902,6 +902,25 @@ def test_compare_by_identity
assert_equal(array.uniq.sort, set.sort)
end

def test_compare_by_identity_compact
omit "compaction is not supported on this platform" unless GC.respond_to?(:compact)

# [Bug #22064]
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
set = Set.new.compare_by_identity
o = Object.new
set.add(o)
assert_include(set, o)
GC.verify_compaction_references(expand_heap: true, toward: :empty)
assert_include(set, o)
end;
end

def test_reset
[Set, Class.new(Set)].each { |klass|
a = [1, 2]
Expand Down
1 change: 1 addition & 0 deletions zjit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ def stats_string
:compile_hir_time_ns,
:compile_hir_build_time_ns,
:compile_hir_strength_reduce_time_ns,
:compile_hir_canonicalize_time_ns,
:compile_hir_fold_constants_time_ns,
:compile_hir_clean_cfg_time_ns,
:compile_hir_eliminate_dead_code_time_ns,
Expand Down
89 changes: 16 additions & 73 deletions zjit/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ pub extern "C" fn rb_zjit_iseq_gen_entry_point(iseq: IseqPtr, ec: EcPtr, jit_exc
// We assert only `jit_exception: false` cases until we support exception handlers.
if ZJITState::assert_compiles_enabled() && !jit_exception {
let iseq_location = iseq_get_location(iseq, 0);
panic!("Failed to compile: {iseq_location}");
panic!("Failed to compile: {iseq_location}: {err:?}");
}

// For --zjit-stats, generate an entry that just increments exit_compilation_failure and exits
Expand Down Expand Up @@ -394,7 +394,7 @@ fn gen_function(cb: &mut CodeBlock, iseq: IseqPtr, version: IseqVersionRef, func
}

// Compile each basic block
for (rpo_idx, &block_id) in reverse_post_order.iter().enumerate() {
for &block_id in reverse_post_order.iter() {
// Skip the entries superblock — it's an internal CFG artifact
if block_id == function.entries_block { continue; }
// Set the current block to the LIR block that corresponds to this
Expand Down Expand Up @@ -437,70 +437,35 @@ fn gen_function(cb: &mut CodeBlock, iseq: IseqPtr, version: IseqVersionRef, func
for (insn_idx, &insn_id) in block.insns().enumerate() {
let insn = function.find(insn_id);

// IfTrue and IfFalse should never be terminators
if matches!(insn, Insn::IfTrue {..} | Insn::IfFalse {..}) {
assert!(!insn.is_terminator(), "IfTrue/IfFalse should not be terminators");
}

match insn {
Insn::IfFalse { val, target } => {

Insn::CondBranch { val, if_true, if_false } => {
let val_opnd = jit.get_opnd(val);
let true_target = hir_to_lir[if_true.target.0].unwrap();
let false_target = hir_to_lir[if_false.target.0].unwrap();

let lir_target = hir_to_lir[target.target.0].unwrap();

let fall_through_target = asm.new_block(block_id, false, rpo_idx);

let branch_edge = lir::BranchEdge {
target: lir_target,
args: target.args.iter().map(|insn_id| jit.get_opnd(*insn_id)).collect()
let true_branch = lir::BranchEdge {
target: true_target,
args: if_true.args.iter().map(|insn_id| jit.get_opnd(*insn_id)).collect()
};

let fall_through_edge = lir::BranchEdge {
target: fall_through_target,
args: vec![]
let false_branch = lir::BranchEdge {
target: false_target,
args: if_false.args.iter().map(|insn_id| jit.get_opnd(*insn_id)).collect()
};

gen_if_false(&mut asm, val_opnd, branch_edge, fall_through_edge);
assert!(asm.current_block().insns.last().unwrap().is_terminator());

asm.set_current_block(fall_through_target);

let label = jit.get_label(&mut asm, fall_through_target, block_id);
asm.write_label(label);
},
Insn::IfTrue { val, target } => {
let val_opnd = jit.get_opnd(val);

let lir_target = hir_to_lir[target.target.0].unwrap();

let fall_through_target = asm.new_block(block_id, false, rpo_idx);
asm.test(val_opnd, val_opnd);
asm.push_insn(lir::Insn::Jnz(Target::Block(true_branch)));
asm.jmp(Target::Block(false_branch));

let branch_edge = lir::BranchEdge {
target: lir_target,
args: target.args.iter().map(|insn_id| jit.get_opnd(*insn_id)).collect()
};

let fall_through_edge = lir::BranchEdge {
target: fall_through_target,
args: vec![]
};

gen_if_true(&mut asm, val_opnd, branch_edge, fall_through_edge);
assert!(asm.current_block().insns.last().unwrap().is_terminator());

asm.set_current_block(fall_through_target);

let label = jit.get_label(&mut asm, fall_through_target, block_id);
asm.write_label(label);
}
Insn::Jump(target) => {
let lir_target = hir_to_lir[target.target.0].unwrap();
let branch_edge = lir::BranchEdge {
target: lir_target,
args: target.args.iter().map(|insn_id| jit.get_opnd(*insn_id)).collect()
};
gen_jump(&mut asm, branch_edge);
asm.jmp(Target::Block(branch_edge));
assert!(asm.current_block().insns.last().unwrap().is_terminator());

// Jump should always be the last instruction in an HIR block
Expand Down Expand Up @@ -779,7 +744,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
&Insn::ArrayMax { ref elements, state } => gen_array_max(jit, asm, opnds!(elements), &function.frame_state(state)),
&Insn::ArrayMin { ref elements, state } => gen_array_min(jit, asm, opnds!(elements), &function.frame_state(state)),
&Insn::Throw { state, .. } => return Err(state),
&Insn::IfFalse { .. } | Insn::IfTrue { .. }
&Insn::CondBranch { .. }
| &Insn::Jump { .. } | Insn::Entries { .. } => unreachable!(),
};

Expand Down Expand Up @@ -1467,28 +1432,6 @@ fn gen_param(asm: &mut Assembler, _idx: usize) -> lir::Opnd {
vreg
}

/// Compile a jump to a basic block
fn gen_jump(asm: &mut Assembler, branch: lir::BranchEdge) {
// Jump to the basic block
asm.jmp(Target::Block(branch));
}

/// Compile a conditional branch to a basic block
fn gen_if_true(asm: &mut Assembler, val: lir::Opnd, branch: lir::BranchEdge, fall_through: lir::BranchEdge) {
// If val is zero, move on to the next instruction.
asm.test(val, val);
asm.push_insn(lir::Insn::Jz(Target::Block(fall_through)));
asm.jmp(Target::Block(branch));
}

/// Compile a conditional branch to a basic block
fn gen_if_false(asm: &mut Assembler, val: lir::Opnd, branch: lir::BranchEdge, fall_through: lir::BranchEdge) {
// If val is not zero, move on to the next instruction.
asm.test(val, val);
asm.push_insn(lir::Insn::Jnz(Target::Block(fall_through)));
asm.jmp(Target::Block(branch));
}

/// Compile a dynamic dispatch with block
fn gen_send(
jit: &mut JITState,
Expand Down
Loading