Skip to content

Commit f40f604

Browse files
committed
implement YJIT side
1 parent fde88b5 commit f40f604

3 files changed

Lines changed: 292 additions & 201 deletions

File tree

yjit/src/codegen.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4957,6 +4957,93 @@ fn gen_opt_new(
49574957
}
49584958
}
49594959

4960+
fn gen_opt_string_new(
4961+
jit: &mut JITState,
4962+
asm: &mut Assembler,
4963+
) -> Option<CodegenStatus> {
4964+
let cd = jit.get_arg(0).as_ptr();
4965+
let jump_offset = jit.get_arg(1).as_i32();
4966+
let capa_loc = jit.get_arg(2).as_i32();
4967+
4968+
if !jit.at_compile_target() {
4969+
return jit.defer_compilation(asm);
4970+
}
4971+
4972+
let ci = unsafe { get_call_data_ci(cd) }; // info about the call site
4973+
let mid = unsafe { vm_ci_mid(ci) };
4974+
let argc: i32 = unsafe { vm_ci_argc(ci) }.try_into().unwrap();
4975+
4976+
let recv_idx = argc;
4977+
let comptime_recv = jit.peek_at_stack(&asm.ctx, recv_idx as isize);
4978+
4979+
// The branch target is the generic new path, which calls new/initialize.
4980+
let jump_idx = jit.next_insn_idx() as i32 + jump_offset;
4981+
4982+
// The fast path only specializes String itself. Anything else bails to the
4983+
// generic path.
4984+
if comptime_recv != unsafe { rb_cString } {
4985+
return end_block_with_jump(jit, asm, jump_idx as u16);
4986+
}
4987+
4988+
let comptime_recv_klass = comptime_recv.class_of();
4989+
let recv = asm.stack_opnd(recv_idx);
4990+
4991+
perf_call!("opt_string_new: ", jit_guard_known_klass(
4992+
jit,
4993+
asm,
4994+
recv,
4995+
recv.into(),
4996+
comptime_recv,
4997+
SEND_MAX_DEPTH,
4998+
Counter::guard_send_klass_megamorphic,
4999+
));
5000+
5001+
// The interpreter skips the initialize call entirely, so the fast path is
5002+
// only valid while "new" is the builtin and String#initialize is unredefined.
5003+
// Otherwise fall back to the generic path.
5004+
if jit.assume_expected_cfunc(asm, comptime_recv_klass, mid, rb_class_new_instance_pass_kw as _)
5005+
&& assume_method_basic_definition(jit, asm, comptime_recv_klass, ID!(initialize)) {
5006+
5007+
extern "C" {
5008+
fn rb_str_buf_new(capa: std::os::raw::c_long) -> VALUE;
5009+
fn rb_str_new_capa_for_init(capa: std::os::raw::c_long) -> VALUE;
5010+
}
5011+
5012+
let str = if argc == 0 {
5013+
// bare String.new: an empty (embedded) string. rb_str_buf_new skips
5014+
// the encoding/coderange setup that rb_str_new would do.
5015+
jit_prepare_non_leaf_call(jit, asm);
5016+
asm.ccall(rb_str_buf_new as *const u8, vec![Opnd::Imm(0)])
5017+
} else {
5018+
// String.new(capacity: n): only fixnum capacities take the fast path.
5019+
// A non-fixnum side-exits so the interpreter takes the generic path.
5020+
let capa = asm.stack_opnd(capa_loc);
5021+
guard_object_is_fixnum(jit, asm, capa, capa.into());
5022+
5023+
jit_prepare_non_leaf_call(jit, asm);
5024+
5025+
// FIX2LONG; rb_str_new_capa_for_init floors anything below the
5026+
// minimum buffer size (including negatives) so no clamping needed.
5027+
let capa = asm.load(asm.stack_opnd(capa_loc));
5028+
let capa = asm.rshift(capa, Opnd::UImm(1));
5029+
asm.ccall(rb_str_new_capa_for_init as *const u8, vec![capa])
5030+
};
5031+
5032+
// Write the allocated string into both the receiver slot and the
5033+
// bookkeeping slot (mirrors TOPN(argc) and TOPN(argc + 1)).
5034+
let result = asm.stack_opnd(recv_idx + 1);
5035+
let recv = asm.stack_opnd(recv_idx);
5036+
asm.ctx.set_opnd_mapping(recv.into(), TempMapping::MapToStack(Type::CString));
5037+
asm.mov(recv, str);
5038+
asm.ctx.set_opnd_mapping(result.into(), TempMapping::MapToStack(Type::CString));
5039+
asm.mov(result, str);
5040+
5041+
jump_to_next_insn(jit, asm)
5042+
} else {
5043+
return end_block_with_jump(jit, asm, jump_idx as u16);
5044+
}
5045+
}
5046+
49605047
fn gen_jump(
49615048
jit: &mut JITState,
49625049
asm: &mut Assembler,
@@ -10825,6 +10912,7 @@ fn get_gen_fn(opcode: VALUE) -> Option<InsnGenFn> {
1082510912
YARVINSN_branchnil_without_ints => Some(gen_branchnil),
1082610913
YARVINSN_jump_without_ints => Some(gen_jump),
1082710914
YARVINSN_opt_new => Some(gen_opt_new),
10915+
YARVINSN_opt_string_new => Some(gen_opt_string_new),
1082810916

1082910917
YARVINSN_getblockparamproxy => Some(gen_getblockparamproxy),
1083010918
YARVINSN_getblockparam => Some(gen_getblockparam),

yjit/src/cruby.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,7 @@ pub(crate) mod ids {
826826
name: to_s content: b"to_s"
827827
name: eq content: b"=="
828828
name: include_p content: b"include?"
829+
name: initialize content: b"initialize"
829830
}
830831
}
831832

0 commit comments

Comments
 (0)