diff options
-rw-r--r-- | bootstraptest/test_yjit.rb | 4 | ||||
-rw-r--r-- | yjit/src/codegen.rs | 38 |
2 files changed, 31 insertions, 11 deletions
diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb index 90f1c0b5f1..7240e5ce8f 100644 --- a/bootstraptest/test_yjit.rb +++ b/bootstraptest/test_yjit.rb @@ -4513,6 +4513,10 @@ assert_equal 'true', %q{ def entry = yield entry { true } } +assert_equal 'sym', %q{ + def entry = :sym.to_sym + entry +} assert_normal_exit %q{ ivars = 1024.times.map { |i| "@iv_#{i} = #{i}\n" }.join diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 1e8f046403..eb85239998 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -6638,8 +6638,14 @@ fn gen_send_bmethod( perf_call! { gen_send_iseq(jit, asm, ocb, iseq, ci, frame_type, Some(capture.ep), cme, block, flags, argc, None) } } +/// The kind of a value an ISEQ returns +enum IseqReturn { + Value(VALUE), + Receiver, +} + /// Return the ISEQ's return value if it consists of only putnil/putobject and leave. -fn iseq_get_return_value(iseq: IseqPtr) -> Option<VALUE> { +fn iseq_get_return_value(iseq: IseqPtr, captured_opnd: Option<Opnd>) -> Option<IseqReturn> { // Expect only two instructions and one possible operand let iseq_size = unsafe { get_iseq_encoded_size(iseq) }; if !(2..=3).contains(&iseq_size) { @@ -6655,10 +6661,12 @@ fn iseq_get_return_value(iseq: IseqPtr) -> Option<VALUE> { return None; } match first_insn { - YARVINSN_putnil => Some(Qnil), - YARVINSN_putobject => unsafe { Some(*rb_iseq_pc_at_idx(iseq, 1)) }, - YARVINSN_putobject_INT2FIX_0_ => Some(VALUE::fixnum_from_usize(0)), - YARVINSN_putobject_INT2FIX_1_ => Some(VALUE::fixnum_from_usize(1)), + YARVINSN_putnil => Some(IseqReturn::Value(Qnil)), + YARVINSN_putobject => Some(IseqReturn::Value(unsafe { *rb_iseq_pc_at_idx(iseq, 1) })), + YARVINSN_putobject_INT2FIX_0_ => Some(IseqReturn::Value(VALUE::fixnum_from_usize(0))), + YARVINSN_putobject_INT2FIX_1_ => Some(IseqReturn::Value(VALUE::fixnum_from_usize(1))), + // We don't support invokeblock for now. Such ISEQs are likely not used by blocks anyway. + YARVINSN_putself if captured_opnd.is_none() => Some(IseqReturn::Receiver), _ => None, } } @@ -6934,16 +6942,24 @@ fn gen_send_iseq( } // Inline simple ISEQs whose return value is known at compile time - if let (Some(value), None, false) = (iseq_get_return_value(iseq), block_arg_type, opt_send_call) { + if let (Some(value), None, false) = (iseq_get_return_value(iseq, captured_opnd), block_arg_type, opt_send_call) { asm_comment!(asm, "inlined simple ISEQ"); gen_counter_incr(asm, Counter::num_send_iseq_inline); - // Pop receiver and arguments - asm.stack_pop(argc as usize + if captured_opnd.is_some() { 0 } else { 1 }); + match value { + IseqReturn::Value(value) => { + // Pop receiver and arguments + asm.stack_pop(argc as usize + if captured_opnd.is_some() { 0 } else { 1 }); - // Push the return value - let stack_ret = asm.stack_push(Type::from(value)); - asm.mov(stack_ret, value.into()); + // Push the return value + let stack_ret = asm.stack_push(Type::from(value)); + asm.mov(stack_ret, value.into()); + }, + IseqReturn::Receiver => { + // Just pop arguments and leave the receiver on stack + asm.stack_pop(argc as usize); + } + } // Let guard chains share the same successor jump_to_next_insn(jit, asm, ocb); |