mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Port jit_rb_str_concat to new backend, re-enable cfunc lookup (https://github.com/Shopify/ruby/pull/402)
This commit is contained in:
parent
5a76a15a0f
commit
09c12111d4
2 changed files with 52 additions and 59 deletions
|
@ -1345,32 +1345,27 @@ fn guard_object_is_array(
|
||||||
asm.jne(side_exit.into());
|
asm.jne(side_exit.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
fn guard_object_is_string(
|
fn guard_object_is_string(
|
||||||
cb: &mut CodeBlock,
|
asm: &mut Assembler,
|
||||||
object_reg: X86Opnd,
|
object_reg: Opnd,
|
||||||
flags_reg: X86Opnd,
|
|
||||||
side_exit: CodePtr,
|
side_exit: CodePtr,
|
||||||
) {
|
) {
|
||||||
add_comment(cb, "guard object is string");
|
asm.comment("guard object is string");
|
||||||
|
|
||||||
// Pull out the type mask
|
// Pull out the type mask
|
||||||
mov(
|
let flags_reg = asm.load(
|
||||||
cb,
|
Opnd::mem(
|
||||||
flags_reg,
|
|
||||||
mem_opnd(
|
|
||||||
8 * SIZEOF_VALUE as u8,
|
8 * SIZEOF_VALUE as u8,
|
||||||
object_reg,
|
object_reg,
|
||||||
RUBY_OFFSET_RBASIC_FLAGS,
|
RUBY_OFFSET_RBASIC_FLAGS,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
and(cb, flags_reg, uimm_opnd(RUBY_T_MASK as u64));
|
let flags_reg = asm.and(flags_reg, Opnd::UImm(RUBY_T_MASK as u64));
|
||||||
|
|
||||||
// Compare the result with T_STRING
|
// Compare the result with T_STRING
|
||||||
cmp(cb, flags_reg, uimm_opnd(RUBY_T_STRING as u64));
|
asm.cmp(flags_reg, Opnd::UImm(RUBY_T_STRING as u64));
|
||||||
jne_ptr(cb, side_exit);
|
asm.jne(side_exit.into());
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
// push enough nils onto the stack to fill out an array
|
// push enough nils onto the stack to fill out an array
|
||||||
fn gen_expandarray(
|
fn gen_expandarray(
|
||||||
|
@ -2079,7 +2074,7 @@ fn gen_get_ivar(
|
||||||
// Check that the slot is inside the extended table (num_slots > index)
|
// Check that the slot is inside the extended table (num_slots > index)
|
||||||
let num_slots = Opnd::mem(32, recv, ROBJECT_OFFSET_NUMIV);
|
let num_slots = Opnd::mem(32, recv, ROBJECT_OFFSET_NUMIV);
|
||||||
asm.cmp(num_slots, Opnd::UImm(ivar_index as u64));
|
asm.cmp(num_slots, Opnd::UImm(ivar_index as u64));
|
||||||
asm.jbe(Target::CodePtr(counted_exit!(ocb, side_exit, getivar_idx_out_of_range)));
|
asm.jbe(counted_exit!(ocb, side_exit, getivar_idx_out_of_range).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a pointer to the extended table
|
// Get a pointer to the extended table
|
||||||
|
@ -3660,16 +3655,19 @@ fn jit_rb_str_uplus(
|
||||||
asm.test(flags_opnd, Opnd::Imm(RUBY_FL_FREEZE as i64));
|
asm.test(flags_opnd, Opnd::Imm(RUBY_FL_FREEZE as i64));
|
||||||
|
|
||||||
let ret_label = asm.new_label("stack_ret");
|
let ret_label = asm.new_label("stack_ret");
|
||||||
// If the string isn't frozen, we just return it. It's already in REG0.
|
|
||||||
|
// We guard for the receiver being a ::String, so the return value is too
|
||||||
|
let stack_ret = ctx.stack_push(Type::CString);
|
||||||
|
|
||||||
|
// If the string isn't frozen, we just return it.
|
||||||
|
asm.mov(stack_ret, recv_opnd);
|
||||||
asm.jz(ret_label);
|
asm.jz(ret_label);
|
||||||
|
|
||||||
// Str is frozen - duplicate
|
// Str is frozen - duplicate it
|
||||||
let ret_opnd = asm.ccall(rb_str_dup as *const u8, vec![recv_opnd]);
|
let ret_opnd = asm.ccall(rb_str_dup as *const u8, vec![recv_opnd]);
|
||||||
|
asm.mov(stack_ret, ret_opnd);
|
||||||
|
|
||||||
asm.write_label(ret_label);
|
asm.write_label(ret_label);
|
||||||
// We guard for an exact-class match on the receiver of rb_cString
|
|
||||||
let stack_ret = ctx.stack_push(Type::CString);
|
|
||||||
asm.mov(stack_ret, ret_opnd);
|
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -3720,6 +3718,7 @@ fn jit_rb_str_to_s(
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Codegen for rb_str_concat() -- *not* String#concat
|
// Codegen for rb_str_concat() -- *not* String#concat
|
||||||
// Frequently strings are concatenated using "out_str << next_str".
|
// Frequently strings are concatenated using "out_str << next_str".
|
||||||
|
@ -3749,63 +3748,65 @@ fn jit_rb_str_concat(
|
||||||
|
|
||||||
// Guard that the argument is of class String at runtime.
|
// Guard that the argument is of class String at runtime.
|
||||||
let insn_opnd = StackOpnd(0);
|
let insn_opnd = StackOpnd(0);
|
||||||
let arg_opnd = asm.load(ctx.stack_opnd(0));
|
|
||||||
let arg_type = ctx.get_opnd_type(insn_opnd);
|
let arg_type = ctx.get_opnd_type(insn_opnd);
|
||||||
|
|
||||||
if arg_type != Type::CString && arg_type != Type::TString {
|
|
||||||
if !arg_type.is_heap() {
|
|
||||||
asm.comment("guard arg not immediate");
|
|
||||||
asm.test(REG0, imm_opnd(RUBY_IMMEDIATE_MASK as i64));
|
|
||||||
asm.jnz(Target::CodePtr(side_exit));
|
|
||||||
asm.cmp(arg_opnd, Qnil.into());
|
|
||||||
asm.jbe(Target::CodePtr(side_exit));
|
|
||||||
|
|
||||||
ctx.upgrade_opnd_type(insn_opnd, Type::UnknownHeap);
|
|
||||||
}
|
|
||||||
guard_object_is_string(cb, REG0, REG1, side_exit);
|
|
||||||
// We know this has type T_STRING, but not necessarily that it's a ::String
|
|
||||||
ctx.upgrade_opnd_type(insn_opnd, Type::TString);
|
|
||||||
}
|
|
||||||
|
|
||||||
let concat_arg = ctx.stack_pop(1);
|
let concat_arg = ctx.stack_pop(1);
|
||||||
let recv = ctx.stack_pop(1);
|
let recv = ctx.stack_pop(1);
|
||||||
|
|
||||||
|
// If we're not compile-time certain that this will always be a string, guard at runtime
|
||||||
|
if arg_type != Type::CString && arg_type != Type::TString {
|
||||||
|
let arg_opnd = asm.load(concat_arg);
|
||||||
|
if !arg_type.is_heap() {
|
||||||
|
asm.comment("guard arg not immediate");
|
||||||
|
asm.test(arg_opnd, Opnd::UImm(RUBY_IMMEDIATE_MASK as u64));
|
||||||
|
asm.jnz(side_exit.into());
|
||||||
|
asm.cmp(arg_opnd, Qnil.into());
|
||||||
|
asm.jbe(side_exit.into());
|
||||||
|
|
||||||
|
ctx.upgrade_opnd_type(insn_opnd, Type::UnknownHeap);
|
||||||
|
}
|
||||||
|
guard_object_is_string(asm, arg_opnd, side_exit);
|
||||||
|
// We know this is a string-or-subclass, but not necessarily that it's a ::String
|
||||||
|
ctx.upgrade_opnd_type(insn_opnd, Type::TString);
|
||||||
|
}
|
||||||
|
|
||||||
// Test if string encodings differ. If different, use rb_str_append. If the same,
|
// Test if string encodings differ. If different, use rb_str_append. If the same,
|
||||||
// use rb_yjit_str_simple_append, which calls rb_str_cat.
|
// use rb_yjit_str_simple_append, which calls rb_str_cat.
|
||||||
asm.comment("<< on strings");
|
asm.comment("<< on strings");
|
||||||
|
|
||||||
// Both rb_str_append and rb_yjit_str_simple_append take identical args
|
|
||||||
let ccall_args = vec![recv, concat_arg];
|
|
||||||
|
|
||||||
// Take receiver's object flags XOR arg's flags. If any
|
// Take receiver's object flags XOR arg's flags. If any
|
||||||
// string-encoding flags are different between the two,
|
// string-encoding flags are different between the two,
|
||||||
// the encodings don't match.
|
// the encodings don't match.
|
||||||
|
let recv_reg = asm.load(recv);
|
||||||
|
let concat_arg_reg = asm.load(concat_arg);
|
||||||
let flags_xor = asm.xor(
|
let flags_xor = asm.xor(
|
||||||
Opnd::mem(64, asm.load(recv), RUBY_OFFSET_RBASIC_FLAGS),
|
Opnd::mem(64, recv_reg, RUBY_OFFSET_RBASIC_FLAGS),
|
||||||
Opnd::mem(64, asm.load(concat_arg), RUBY_OFFSET_RBASIC_FLAGS)
|
Opnd::mem(64, concat_arg_reg, RUBY_OFFSET_RBASIC_FLAGS)
|
||||||
);
|
);
|
||||||
asm.test(flags_xor, Opnd::UImm(RUBY_ENCODING_MASK as u64));
|
asm.test(flags_xor, Opnd::UImm(RUBY_ENCODING_MASK as u64));
|
||||||
|
|
||||||
|
// Push once, use the resulting operand in both branches below.
|
||||||
|
let stack_ret = ctx.stack_push(Type::CString);
|
||||||
|
|
||||||
let enc_mismatch = asm.new_label("enc_mismatch");
|
let enc_mismatch = asm.new_label("enc_mismatch");
|
||||||
asm.jnz(enc_mismatch);
|
asm.jnz(enc_mismatch);
|
||||||
|
|
||||||
// If encodings match, call the simple append function and jump to return
|
// If encodings match, call the simple append function and jump to return
|
||||||
let ret_opnd = asm.ccall(rb_yjit_str_simple_append as *const u8, ccall_args);
|
let ret_opnd = asm.ccall(rb_yjit_str_simple_append as *const u8, vec![recv, concat_arg]);
|
||||||
let ret_label = asm.new_label("stack_return");
|
let ret_label = asm.new_label("func_return");
|
||||||
|
asm.mov(stack_ret, ret_opnd);
|
||||||
asm.jmp(ret_label);
|
asm.jmp(ret_label);
|
||||||
|
|
||||||
// If encodings are different, use a slower encoding-aware concatenate
|
// If encodings are different, use a slower encoding-aware concatenate
|
||||||
asm.write_label(enc_mismatch);
|
asm.write_label(enc_mismatch);
|
||||||
asm.ccall(rb_str_buf_append as *const u8, ccall_args);
|
let ret_opnd = asm.ccall(rb_str_buf_append as *const u8, vec![recv, concat_arg]);
|
||||||
|
asm.mov(stack_ret, ret_opnd);
|
||||||
// Drop through to return
|
// Drop through to return
|
||||||
|
|
||||||
asm.write_label(ret_label);
|
asm.write_label(ret_label);
|
||||||
let stack_ret = ctx.stack_push(Type::CString);
|
|
||||||
asm.mov(stack_ret, ret_opnd);
|
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
fn jit_thread_s_current(
|
fn jit_thread_s_current(
|
||||||
_jit: &mut JITState,
|
_jit: &mut JITState,
|
||||||
|
@ -3921,20 +3922,12 @@ fn gen_send_cfunc(
|
||||||
if kw_arg.is_null() {
|
if kw_arg.is_null() {
|
||||||
let codegen_p = lookup_cfunc_codegen(unsafe { (*cme).def });
|
let codegen_p = lookup_cfunc_codegen(unsafe { (*cme).def });
|
||||||
if let Some(known_cfunc_codegen) = codegen_p {
|
if let Some(known_cfunc_codegen) = codegen_p {
|
||||||
return CantCompile; /*
|
if known_cfunc_codegen(jit, ctx, asm, ocb, ci, cme, block, argc, recv_known_klass) {
|
||||||
let start_pos = cb.get_write_ptr().raw_ptr() as usize;
|
|
||||||
if known_cfunc_codegen(jit, ctx, cb, ocb, ci, cme, block, argc, recv_known_klass) {
|
|
||||||
let written_bytes = cb.get_write_ptr().raw_ptr() as usize - start_pos;
|
|
||||||
if written_bytes < JUMP_SIZE_IN_BYTES {
|
|
||||||
add_comment(cb, "Writing NOPs to leave room for later invalidation code");
|
|
||||||
nop(cb, (JUMP_SIZE_IN_BYTES - written_bytes) as u32);
|
|
||||||
}
|
|
||||||
// cfunc codegen generated code. Terminate the block so
|
// cfunc codegen generated code. Terminate the block so
|
||||||
// there isn't multiple calls in the same block.
|
// there isn't multiple calls in the same block.
|
||||||
jump_to_next_insn(jit, ctx, cb, ocb);
|
jump_to_next_insn(jit, ctx, asm, ocb);
|
||||||
return EndBlock;
|
return EndBlock;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6141,8 +6134,8 @@ impl CodegenGlobals {
|
||||||
//self.yjit_reg_method(rb_cString, "to_s", jit_rb_str_to_s);
|
//self.yjit_reg_method(rb_cString, "to_s", jit_rb_str_to_s);
|
||||||
//self.yjit_reg_method(rb_cString, "to_str", jit_rb_str_to_s);
|
//self.yjit_reg_method(rb_cString, "to_str", jit_rb_str_to_s);
|
||||||
self.yjit_reg_method(rb_cString, "bytesize", jit_rb_str_bytesize);
|
self.yjit_reg_method(rb_cString, "bytesize", jit_rb_str_bytesize);
|
||||||
//self.yjit_reg_method(rb_cString, "<<", jit_rb_str_concat);
|
self.yjit_reg_method(rb_cString, "<<", jit_rb_str_concat);
|
||||||
self.yjit_reg_method(rb_cString, "+@", jit_rb_str_uplus);
|
//self.yjit_reg_method(rb_cString, "+@", jit_rb_str_uplus);
|
||||||
|
|
||||||
// Thread.current
|
// Thread.current
|
||||||
self.yjit_reg_method(
|
self.yjit_reg_method(
|
||||||
|
|
|
@ -69,7 +69,7 @@ impl Type {
|
||||||
} else if val.flonum_p() {
|
} else if val.flonum_p() {
|
||||||
Type::Flonum
|
Type::Flonum
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!("Illegal value: {:?}", val)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Core.rs can't reference rb_cString because it's linked by Rust-only tests.
|
// Core.rs can't reference rb_cString because it's linked by Rust-only tests.
|
||||||
|
|
Loading…
Add table
Reference in a new issue