@@ -610,8 +610,12 @@ pub enum Insn {
610610 IsMethodCfunc { val: InsnId, cd: *const rb_call_data, cfunc: *const u8, state: InsnId },
611611 /// Return C `true` if left == right
612612 IsBitEqual { left: InsnId, right: InsnId },
613+ // TODO(max): In iseq body types that are not ISEQ_TYPE_METHOD, rewrite to Constant false.
613614 Defined { op_type: usize, obj: VALUE, pushval: VALUE, v: InsnId, state: InsnId },
614615 GetConstantPath { ic: *const iseq_inline_constant_cache, state: InsnId },
616+ /// Kernel#block_given? but without pushing a frame. Similar to [`Insn::Defined`] with
617+ /// `DEFINED_YIELD`
618+ IsBlockGiven,
615619
616620 /// Get a global variable named `id`
617621 GetGlobal { id: ID, state: InsnId },
@@ -870,6 +874,7 @@ impl Insn {
870874 Insn::NewRange { .. } => true,
871875 Insn::NewRangeFixnum { .. } => false,
872876 Insn::StringGetbyteFixnum { .. } => false,
877+ Insn::IsBlockGiven => false,
873878 _ => true,
874879 }
875880 }
@@ -1065,6 +1070,7 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
10651070 Insn::GuardBlockParamProxy { level, .. } => write!(f, "GuardBlockParamProxy l{level}"),
10661071 Insn::PatchPoint { invariant, .. } => { write!(f, "PatchPoint {}", invariant.print(self.ptr_map)) },
10671072 Insn::GetConstantPath { ic, .. } => { write!(f, "GetConstantPath {:p}", self.ptr_map.map_ptr(ic)) },
1073+ Insn::IsBlockGiven => { write!(f, "IsBlockGiven") },
10681074 Insn::CCall { cfunc, args, name, return_type: _, elidable: _ } => {
10691075 write!(f, "CCall {}@{:p}", name.contents_lossy(), self.ptr_map.map_ptr(cfunc))?;
10701076 for arg in args {
@@ -1562,6 +1568,7 @@ impl Function {
15621568 result@(Const {..}
15631569 | Param {..}
15641570 | GetConstantPath {..}
1571+ | IsBlockGiven
15651572 | PatchPoint {..}
15661573 | PutSpecialObject {..}
15671574 | GetGlobal {..}
@@ -1828,6 +1835,7 @@ impl Function {
18281835 Insn::Defined { pushval, .. } => Type::from_value(*pushval).union(types::NilClass),
18291836 Insn::DefinedIvar { pushval, .. } => Type::from_value(*pushval).union(types::NilClass),
18301837 Insn::GetConstantPath { .. } => types::BasicObject,
1838+ Insn::IsBlockGiven { .. } => types::BoolExact,
18311839 Insn::ArrayMax { .. } => types::BasicObject,
18321840 Insn::GetGlobal { .. } => types::BasicObject,
18331841 Insn::GetIvar { .. } => types::BasicObject,
@@ -3009,6 +3017,7 @@ impl Function {
30093017 | &Insn::LoadSelf
30103018 | &Insn::GetLocal { .. }
30113019 | &Insn::PutSpecialObject { .. }
3020+ | &Insn::IsBlockGiven
30123021 | &Insn::IncrCounter(_)
30133022 | &Insn::IncrCounterPtr { .. } =>
30143023 {}
@@ -8492,13 +8501,23 @@ mod opt_tests {
84928501 use super::tests::assert_contains_opcode;
84938502
84948503 #[track_caller]
8495- fn hir_string(method: &str) -> String {
8496- let iseq = crate::cruby::with_rubyvm(|| get_method_iseq("self", method));
8504+ fn hir_string_function(function: &Function) -> String {
8505+ format!("{}", FunctionPrinter::without_snapshot(function))
8506+ }
8507+
8508+ #[track_caller]
8509+ fn hir_string_proc(proc: &str) -> String {
8510+ let iseq = crate::cruby::with_rubyvm(|| get_proc_iseq(proc));
84978511 unsafe { crate::cruby::rb_zjit_profile_disable(iseq) };
84988512 let mut function = iseq_to_hir(iseq).unwrap();
84998513 function.optimize();
85008514 function.validate().unwrap();
8501- format!("{}", FunctionPrinter::without_snapshot(&function))
8515+ hir_string_function(&function)
8516+ }
8517+
8518+ #[track_caller]
8519+ fn hir_string(method: &str) -> String {
8520+ hir_string_proc(&format!("{}.method(:{})", "self", method))
85028521 }
85038522
85048523 #[test]
@@ -10671,6 +10690,87 @@ mod opt_tests {
1067110690 ");
1067210691 }
1067310692
10693+ #[test]
10694+ fn test_inline_kernel_block_given_p() {
10695+ eval("
10696+ def test = block_given?
10697+ test
10698+ ");
10699+ assert_snapshot!(hir_string("test"), @r"
10700+ fn test@<compiled>:2:
10701+ bb0():
10702+ EntryPoint interpreter
10703+ v1:BasicObject = LoadSelf
10704+ Jump bb2(v1)
10705+ bb1(v4:BasicObject):
10706+ EntryPoint JIT(0)
10707+ Jump bb2(v4)
10708+ bb2(v6:BasicObject):
10709+ PatchPoint MethodRedefined(Object@0x1000, block_given?@0x1008, cme:0x1010)
10710+ PatchPoint NoSingletonClass(Object@0x1000)
10711+ v20:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
10712+ v21:BoolExact = IsBlockGiven
10713+ IncrCounter inline_cfunc_optimized_send_count
10714+ CheckInterrupts
10715+ Return v21
10716+ ");
10717+ }
10718+
10719+ #[test]
10720+ fn test_inline_kernel_block_given_p_in_block() {
10721+ eval("
10722+ TEST = proc { block_given? }
10723+ TEST.call
10724+ ");
10725+ assert_snapshot!(hir_string_proc("TEST"), @r"
10726+ fn block in <compiled>@<compiled>:2:
10727+ bb0():
10728+ EntryPoint interpreter
10729+ v1:BasicObject = LoadSelf
10730+ Jump bb2(v1)
10731+ bb1(v4:BasicObject):
10732+ EntryPoint JIT(0)
10733+ Jump bb2(v4)
10734+ bb2(v6:BasicObject):
10735+ PatchPoint MethodRedefined(Object@0x1000, block_given?@0x1008, cme:0x1010)
10736+ PatchPoint NoSingletonClass(Object@0x1000)
10737+ v20:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
10738+ v21:BoolExact = IsBlockGiven
10739+ IncrCounter inline_cfunc_optimized_send_count
10740+ CheckInterrupts
10741+ Return v21
10742+ ");
10743+ }
10744+
10745+ #[test]
10746+ fn test_elide_kernel_block_given_p() {
10747+ eval("
10748+ def test
10749+ block_given?
10750+ 5
10751+ end
10752+ test
10753+ ");
10754+ assert_snapshot!(hir_string("test"), @r"
10755+ fn test@<compiled>:3:
10756+ bb0():
10757+ EntryPoint interpreter
10758+ v1:BasicObject = LoadSelf
10759+ Jump bb2(v1)
10760+ bb1(v4:BasicObject):
10761+ EntryPoint JIT(0)
10762+ Jump bb2(v4)
10763+ bb2(v6:BasicObject):
10764+ PatchPoint MethodRedefined(Object@0x1000, block_given?@0x1008, cme:0x1010)
10765+ PatchPoint NoSingletonClass(Object@0x1000)
10766+ v23:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
10767+ IncrCounter inline_cfunc_optimized_send_count
10768+ v14:Fixnum[5] = Const Value(5)
10769+ CheckInterrupts
10770+ Return v14
10771+ ");
10772+ }
10773+
1067410774 #[test]
1067510775 fn const_send_direct_integer() {
1067610776 eval("
0 commit comments