summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--encoding.c12
-rw-r--r--zjit/src/backend/lir.rs62
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();