diff options
| -rw-r--r-- | encoding.c | 12 | ||||
| -rw-r--r-- | zjit/src/backend/lir.rs | 62 |
2 files changed, 49 insertions, 25 deletions
diff --git a/encoding.c b/encoding.c index 73fad8f1a6..c17f118eef 100644 --- a/encoding.c +++ b/encoding.c @@ -98,6 +98,7 @@ static rb_encoding *global_enc_ascii, *global_enc_us_ascii; static int filesystem_encindex = ENCINDEX_ASCII_8BIT; +static rb_atomic_t locale_alias_registered; #define GLOBAL_ENC_TABLE_LOCKING(tbl) \ for (struct enc_table *tbl = &global_enc_table, **locking = &tbl; \ @@ -1568,15 +1569,16 @@ rb_locale_encindex(void) if (idx < 0) idx = ENCINDEX_UTF_8; - GLOBAL_ENC_TABLE_LOCKING(enc_table) { - if (enc_registered(enc_table, "locale") < 0) { + if (!RUBY_ATOMIC_LOAD(locale_alias_registered)) { + GLOBAL_ENC_TABLE_LOCKING(enc_table) { + if (enc_registered(enc_table, "locale") < 0) { # if defined _WIN32 - void Init_w32_codepage(void); - Init_w32_codepage(); + void Init_w32_codepage(void); + Init_w32_codepage(); # endif - GLOBAL_ENC_TABLE_LOCKING(enc_table) { enc_alias_internal(enc_table, "locale", idx); } + RUBY_ATOMIC_SET(locale_alias_registered, 1); } } diff --git a/zjit/src/backend/lir.rs b/zjit/src/backend/lir.rs index 944b855244..a417df300a 100644 --- a/zjit/src/backend/lir.rs +++ b/zjit/src/backend/lir.rs @@ -1562,23 +1562,6 @@ impl Assembler iter } - /// Return an operand for a basic block argument at a given index. - /// To simplify the implementation, we allocate a fixed register or a stack slot - /// for each basic block argument. - pub fn param_opnd(idx: usize) -> Opnd { - use crate::backend::current::ALLOC_REGS; - use crate::cruby::SIZEOF_VALUE_I32; - - if idx < ALLOC_REGS.len() { - Opnd::Reg(ALLOC_REGS[idx]) - } else { - // With FrameSetup, the address that NATIVE_BASE_PTR points to stores an old value in the register. - // To avoid clobbering it, we need to start from the next slot, and we also reserve one space for - // JITFrame, hence `+ 2` for the index. - Opnd::mem(64, NATIVE_BASE_PTR, (idx - ALLOC_REGS.len() + 2) as i32 * -SIZEOF_VALUE_I32) - } - } - pub fn linearize_instructions(&self) -> Vec<Insn> { // Emit instructions with labels, expanding branch parameters let mut insns = Vec::with_capacity(ASSEMBLER_INSNS_CAPACITY); @@ -2040,11 +2023,25 @@ impl Assembler if self.basic_blocks[block_id.0].is_dummy() { continue; } let params = self.basic_blocks[block_id.0].parameters.clone(); + // JIT-to-JIT entries that would need more argument registers should + // be unreachable because can_direct_send() refuses to call them. + // Keep compiling the function body, but make the unsupported entry + // abort if control ever reaches it. TODO: Remove this (Shopify/ruby#916) + if params.len() > C_ARG_OPNDS.len() { + let insert_pos = self.basic_blocks[block_id.0].insns.iter() + .position(|insn| matches!(insn, Insn::FrameSetup { .. })) + .or_else(|| self.basic_blocks[block_id.0].insns.iter().position(|insn| matches!(insn, Insn::Label(_))).map(|idx| idx + 1)) + .unwrap_or(0); + self.basic_blocks[block_id.0].insns.insert(insert_pos, Insn::Abort); + self.basic_blocks[block_id.0].insn_ids.insert(insert_pos, None); + continue; + } + // Rewrite VRegs to physical registers before sequentialization // so the parcopy algorithm can detect physical register conflicts. let reg_copies: Vec<parcopy::RegisterCopy<Opnd>> = params.iter().enumerate() .map(|(i, param)| parcopy::RegisterCopy::<Opnd> { - source: Assembler::param_opnd(i), + source: C_ARG_OPNDS[i], destination: Self::rewritten_opnd(*param, assignments), }) .filter(|copy| copy.source != copy.destination) @@ -4216,8 +4213,8 @@ mod tests { let (assignments, _) = asm.linear_scan(intervals.clone(), 5, &preferred_registers); // Entry block b1 has parameters [v0, v1]. - // With 5 registers: v0 -> Reg(0) = regs[0], arrival = param_opnd(0) = regs[0] -> self-move, filtered - // v1 -> Reg(1) = regs[1], arrival = param_opnd(1) = regs[1] -> self-move, filtered + // With 5 registers: v0 -> Reg(0) = regs[0], arrival = C_ARG_OPNDS[0] = regs[0] -> self-move, filtered + // v1 -> Reg(1) = regs[1], arrival = C_ARG_OPNDS[1] = regs[1] -> self-move, filtered // Before resolve_ssa, b1 has: [Label, Jmp] = 2 insns assert_eq!(asm.basic_blocks[b1.0].insns.len(), 2); @@ -4242,6 +4239,31 @@ mod tests { } } + #[test] + fn test_resolve_ssa_entry_params_too_many_abort() { + let mut asm = Assembler::new(); + let block = asm.new_block(hir::BlockId(0), true, 0); + asm.set_current_block(block); + let label = asm.new_label("bb0"); + asm.write_label(label); + + for _ in 0..=C_ARG_OPNDS.len() { + let param = asm.new_vreg(64); + asm.basic_blocks[block.0].add_parameter(param); + } + asm.basic_blocks[block.0].push_insn(Insn::CRet(Opnd::UImm(0))); + + let live_in = asm.analyze_liveness(); + asm.number_instructions(0); + let intervals = asm.build_intervals(live_in); + let preferred_registers = asm.preferred_register_assignments(&intervals); + let (assignments, _) = asm.linear_scan(intervals.clone(), 5, &preferred_registers); + + asm.resolve_ssa(&intervals, &assignments); + + assert!(matches!(asm.basic_blocks[block.0].insns[1], Insn::Abort)); + } + fn build_critical_edge() -> (Assembler, Opnd, Opnd, Opnd, Opnd, Opnd, BlockId, BlockId, BlockId) { let mut asm = Assembler::new(); |
