mirror of
https://github.com/ruby/ruby.git
synced 2026-01-26 20:19:19 +00:00
ZJIT: Specialize some Sends (#14363)
* ZJIT: Profile and specialize Array#empty? * ZJIT: Specialize BasicObject#== * ZJIT: Specialize Hash#empty? * ZJIT: Specialize BasicObject#! Co-authored-by: Takashi Kokubun <takashikkbn@gmail.com>
This commit is contained in:
parent
886268856b
commit
4652879f43
@ -1575,6 +1575,7 @@ opt_empty_p
|
||||
(CALL_DATA cd)
|
||||
(VALUE recv)
|
||||
(VALUE val)
|
||||
// attr bool zjit_profile = true;
|
||||
{
|
||||
val = vm_opt_empty_p(recv);
|
||||
|
||||
@ -1603,6 +1604,7 @@ opt_not
|
||||
(CALL_DATA cd)
|
||||
(VALUE recv)
|
||||
(VALUE val)
|
||||
// attr bool zjit_profile = true;
|
||||
{
|
||||
val = vm_opt_not(GET_ISEQ(), cd, recv);
|
||||
|
||||
|
||||
4
zjit/src/cruby_bindings.inc.rs
generated
4
zjit/src/cruby_bindings.inc.rs
generated
@ -696,7 +696,9 @@ pub const YARVINSN_zjit_opt_gt: ruby_vminsn_type = 229;
|
||||
pub const YARVINSN_zjit_opt_ge: ruby_vminsn_type = 230;
|
||||
pub const YARVINSN_zjit_opt_and: ruby_vminsn_type = 231;
|
||||
pub const YARVINSN_zjit_opt_or: ruby_vminsn_type = 232;
|
||||
pub const VM_INSTRUCTION_SIZE: ruby_vminsn_type = 233;
|
||||
pub const YARVINSN_zjit_opt_empty_p: ruby_vminsn_type = 233;
|
||||
pub const YARVINSN_zjit_opt_not: ruby_vminsn_type = 234;
|
||||
pub const VM_INSTRUCTION_SIZE: ruby_vminsn_type = 235;
|
||||
pub type ruby_vminsn_type = u32;
|
||||
pub type rb_iseq_callback = ::std::option::Option<
|
||||
unsafe extern "C" fn(arg1: *const rb_iseq_t, arg2: *mut ::std::os::raw::c_void),
|
||||
|
||||
@ -171,8 +171,12 @@ pub fn init() -> Annotations {
|
||||
annotate!(rb_cModule, "===", types::BoolExact, no_gc, leaf);
|
||||
annotate!(rb_cArray, "length", types::Fixnum, no_gc, leaf, elidable);
|
||||
annotate!(rb_cArray, "size", types::Fixnum, no_gc, leaf, elidable);
|
||||
annotate!(rb_cArray, "empty?", types::BoolExact, no_gc, leaf, elidable);
|
||||
annotate!(rb_cHash, "empty?", types::BoolExact, no_gc, leaf, elidable);
|
||||
annotate!(rb_cNilClass, "nil?", types::TrueClass, no_gc, leaf, elidable);
|
||||
annotate!(rb_mKernel, "nil?", types::FalseClass, no_gc, leaf, elidable);
|
||||
annotate!(rb_cBasicObject, "==", types::BoolExact, no_gc, leaf, elidable);
|
||||
annotate!(rb_cBasicObject, "!", types::BoolExact, no_gc, leaf, elidable);
|
||||
|
||||
annotate_builtin!(rb_mKernel, "Float", types::Float);
|
||||
annotate_builtin!(rb_mKernel, "Integer", types::Integer);
|
||||
|
||||
@ -8117,6 +8117,79 @@ mod opt_tests {
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_specialize_basicobject_not_to_ccall() {
|
||||
eval("
|
||||
def test(a) = !a
|
||||
|
||||
test([])
|
||||
");
|
||||
assert_snapshot!(hir_string("test"), @r"
|
||||
fn test@<compiled>:2:
|
||||
bb0(v0:BasicObject, v1:BasicObject):
|
||||
PatchPoint MethodRedefined(Array@0x1000, !@0x1008, cme:0x1010)
|
||||
v9:ArrayExact = GuardType v1, ArrayExact
|
||||
v10:BoolExact = CCall !@0x1038, v9
|
||||
CheckInterrupts
|
||||
Return v10
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_specialize_array_empty_p_to_ccall() {
|
||||
eval("
|
||||
def test(a) = a.empty?
|
||||
|
||||
test([])
|
||||
");
|
||||
assert_snapshot!(hir_string("test"), @r"
|
||||
fn test@<compiled>:2:
|
||||
bb0(v0:BasicObject, v1:BasicObject):
|
||||
PatchPoint MethodRedefined(Array@0x1000, empty?@0x1008, cme:0x1010)
|
||||
v9:ArrayExact = GuardType v1, ArrayExact
|
||||
v10:BoolExact = CCall empty?@0x1038, v9
|
||||
CheckInterrupts
|
||||
Return v10
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_specialize_hash_empty_p_to_ccall() {
|
||||
eval("
|
||||
def test(a) = a.empty?
|
||||
|
||||
test({})
|
||||
");
|
||||
assert_snapshot!(hir_string("test"), @r"
|
||||
fn test@<compiled>:2:
|
||||
bb0(v0:BasicObject, v1:BasicObject):
|
||||
PatchPoint MethodRedefined(Hash@0x1000, empty?@0x1008, cme:0x1010)
|
||||
v9:HashExact = GuardType v1, HashExact
|
||||
v10:BoolExact = CCall empty?@0x1038, v9
|
||||
CheckInterrupts
|
||||
Return v10
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_specialize_basic_object_eq_to_ccall() {
|
||||
eval("
|
||||
class C; end
|
||||
def test(a, b) = a == b
|
||||
|
||||
test(C.new, C.new)
|
||||
");
|
||||
assert_snapshot!(hir_string("test"), @r"
|
||||
fn test@<compiled>:3:
|
||||
bb0(v0:BasicObject, v1:BasicObject, v2:BasicObject):
|
||||
PatchPoint MethodRedefined(C@0x1000, ==@0x1008, cme:0x1010)
|
||||
v10:HeapObject[class_exact:C] = GuardType v1, HeapObject[class_exact:C]
|
||||
v11:BoolExact = CCall ==@0x1038, v10, v2
|
||||
CheckInterrupts
|
||||
Return v11
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_guard_fixnum_and_fixnum() {
|
||||
eval("
|
||||
|
||||
@ -246,6 +246,8 @@ impl Type {
|
||||
else if val.is_true() { types::TrueClass }
|
||||
else if val.is_false() { types::FalseClass }
|
||||
else if val.class() == unsafe { rb_cString } { types::StringExact }
|
||||
else if val.class() == unsafe { rb_cArray } { types::ArrayExact }
|
||||
else if val.class() == unsafe { rb_cHash } { types::HashExact }
|
||||
else {
|
||||
// TODO(max): Add more cases for inferring type bits from built-in types
|
||||
Type { bits: bits::HeapObject, spec: Specialization::TypeExact(val.class()) }
|
||||
|
||||
@ -66,6 +66,8 @@ fn profile_insn(bare_opcode: ruby_vminsn_type, ec: EcPtr) {
|
||||
YARVINSN_opt_ge => profile_operands(profiler, profile, 2),
|
||||
YARVINSN_opt_and => profile_operands(profiler, profile, 2),
|
||||
YARVINSN_opt_or => profile_operands(profiler, profile, 2),
|
||||
YARVINSN_opt_empty_p => profile_operands(profiler, profile, 1),
|
||||
YARVINSN_opt_not => profile_operands(profiler, profile, 1),
|
||||
YARVINSN_opt_send_without_block => {
|
||||
let cd: *const rb_call_data = profiler.insn_opnd(0).as_ptr();
|
||||
let argc = unsafe { vm_ci_argc((*cd).ci) };
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user