Skip to content

Commit ba4a36e

Browse files
authored
ZJIT: Inline attr_reader/attr_accessor (ruby#14126)
We can rewrite SendWithoutBlock to GetIvar.
1 parent 4a70f94 commit ba4a36e

File tree

2 files changed

+144
-13
lines changed

2 files changed

+144
-13
lines changed

test/ruby/test_zjit.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,38 @@ def test() = @foo = 1
887887
}
888888
end
889889

890+
def test_attr_reader
891+
assert_compiles '[4, 4]', %q{
892+
class C
893+
attr_reader :foo
894+
895+
def initialize
896+
@foo = 4
897+
end
898+
end
899+
900+
def test(c) = c.foo
901+
c = C.new
902+
[test(c), test(c)]
903+
}, call_threshold: 2, insns: [:opt_send_without_block]
904+
end
905+
906+
def test_attr_accessor
907+
assert_compiles '[4, 4]', %q{
908+
class C
909+
attr_accessor :foo
910+
911+
def initialize
912+
@foo = 4
913+
end
914+
end
915+
916+
def test(c) = c.foo
917+
c = C.new
918+
[test(c), test(c)]
919+
}, call_threshold: 2, insns: [:opt_send_without_block]
920+
end
921+
890922
def test_uncached_getconstant_path
891923
assert_compiles RUBY_COPYRIGHT.dump, %q{
892924
def test = RUBY_COPYRIGHT

zjit/src/hir.rs

Lines changed: 112 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1537,22 +1537,31 @@ impl Function {
15371537
// It allows you to use a faster ISEQ if possible.
15381538
cme = unsafe { rb_check_overloaded_cme(cme, ci) };
15391539
let def_type = unsafe { get_cme_def_type(cme) };
1540-
if def_type != VM_METHOD_TYPE_ISEQ {
1540+
if def_type == VM_METHOD_TYPE_ISEQ {
15411541
// TODO(max): Allow non-iseq; cache cme
1542+
// Only specialize positional-positional calls
1543+
// TODO(max): Handle other kinds of parameter passing
1544+
let iseq = unsafe { get_def_iseq_ptr((*cme).def) };
1545+
if !can_direct_send(iseq) {
1546+
self.push_insn_id(block, insn_id); continue;
1547+
}
1548+
self.push_insn(block, Insn::PatchPoint { invariant: Invariant::MethodRedefined { klass, method: mid, cme }, state });
1549+
if let Some(profiled_type) = profiled_type {
1550+
self_val = self.push_insn(block, Insn::GuardType { val: self_val, guard_type: Type::from_profiled_type(profiled_type), state });
1551+
}
1552+
let send_direct = self.push_insn(block, Insn::SendWithoutBlockDirect { self_val, cd, cme, iseq, args, state });
1553+
self.make_equal_to(insn_id, send_direct);
1554+
} else if def_type == VM_METHOD_TYPE_IVAR && args.is_empty() {
1555+
self.push_insn(block, Insn::PatchPoint { invariant: Invariant::MethodRedefined { klass, method: mid, cme }, state });
1556+
if let Some(profiled_type) = profiled_type {
1557+
self_val = self.push_insn(block, Insn::GuardType { val: self_val, guard_type: Type::from_profiled_type(profiled_type), state });
1558+
}
1559+
let id = unsafe { get_cme_def_body_attr_id(cme) };
1560+
let getivar = self.push_insn(block, Insn::GetIvar { self_val, id, state });
1561+
self.make_equal_to(insn_id, getivar);
1562+
} else {
15421563
self.push_insn_id(block, insn_id); continue;
15431564
}
1544-
// Only specialize positional-positional calls
1545-
// TODO(max): Handle other kinds of parameter passing
1546-
let iseq = unsafe { get_def_iseq_ptr((*cme).def) };
1547-
if !can_direct_send(iseq) {
1548-
self.push_insn_id(block, insn_id); continue;
1549-
}
1550-
self.push_insn(block, Insn::PatchPoint { invariant: Invariant::MethodRedefined { klass, method: mid, cme }, state });
1551-
if let Some(profiled_type) = profiled_type {
1552-
self_val = self.push_insn(block, Insn::GuardType { val: self_val, guard_type: Type::from_profiled_type(profiled_type), state });
1553-
}
1554-
let send_direct = self.push_insn(block, Insn::SendWithoutBlockDirect { self_val, cd, cme, iseq, args, state });
1555-
self.make_equal_to(insn_id, send_direct);
15561565
}
15571566
Insn::GetConstantPath { ic, state, .. } => {
15581567
let idlist: *const ID = unsafe { (*ic).segments };
@@ -7422,4 +7431,94 @@ mod opt_tests {
74227431
Return v7
74237432
"#]]);
74247433
}
7434+
7435+
#[test]
7436+
fn test_inline_attr_reader_constant() {
7437+
eval("
7438+
class C
7439+
attr_reader :foo
7440+
end
7441+
7442+
O = C.new
7443+
def test = O.foo
7444+
test
7445+
test
7446+
");
7447+
assert_optimized_method_hir("test", expect![[r#"
7448+
fn test@<compiled>:7:
7449+
bb0(v0:BasicObject):
7450+
PatchPoint SingleRactorMode
7451+
PatchPoint StableConstantNames(0x1000, O)
7452+
v9:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
7453+
PatchPoint MethodRedefined(C@0x1010, foo@0x1018, cme:0x1020)
7454+
v11:BasicObject = GetIvar v9, :@foo
7455+
Return v11
7456+
"#]]);
7457+
}
7458+
7459+
#[test]
7460+
fn test_inline_attr_accessor_constant() {
7461+
eval("
7462+
class C
7463+
attr_accessor :foo
7464+
end
7465+
7466+
O = C.new
7467+
def test = O.foo
7468+
test
7469+
test
7470+
");
7471+
assert_optimized_method_hir("test", expect![[r#"
7472+
fn test@<compiled>:7:
7473+
bb0(v0:BasicObject):
7474+
PatchPoint SingleRactorMode
7475+
PatchPoint StableConstantNames(0x1000, O)
7476+
v9:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
7477+
PatchPoint MethodRedefined(C@0x1010, foo@0x1018, cme:0x1020)
7478+
v11:BasicObject = GetIvar v9, :@foo
7479+
Return v11
7480+
"#]]);
7481+
}
7482+
7483+
#[test]
7484+
fn test_inline_attr_reader() {
7485+
eval("
7486+
class C
7487+
attr_reader :foo
7488+
end
7489+
7490+
def test(o) = o.foo
7491+
test C.new
7492+
test C.new
7493+
");
7494+
assert_optimized_method_hir("test", expect![[r#"
7495+
fn test@<compiled>:6:
7496+
bb0(v0:BasicObject, v1:BasicObject):
7497+
PatchPoint MethodRedefined(C@0x1000, foo@0x1008, cme:0x1010)
7498+
v7:BasicObject[class_exact:C] = GuardType v1, BasicObject[class_exact:C]
7499+
v8:BasicObject = GetIvar v7, :@foo
7500+
Return v8
7501+
"#]]);
7502+
}
7503+
7504+
#[test]
7505+
fn test_inline_attr_accessor() {
7506+
eval("
7507+
class C
7508+
attr_accessor :foo
7509+
end
7510+
7511+
def test(o) = o.foo
7512+
test C.new
7513+
test C.new
7514+
");
7515+
assert_optimized_method_hir("test", expect![[r#"
7516+
fn test@<compiled>:6:
7517+
bb0(v0:BasicObject, v1:BasicObject):
7518+
PatchPoint MethodRedefined(C@0x1000, foo@0x1008, cme:0x1010)
7519+
v7:BasicObject[class_exact:C] = GuardType v1, BasicObject[class_exact:C]
7520+
v8:BasicObject = GetIvar v7, :@foo
7521+
Return v8
7522+
"#]]);
7523+
}
74257524
}

0 commit comments

Comments
 (0)