@@ -2752,7 +2752,6 @@ fn gen_checktype(
2752
2752
if let RUBY_T_STRING | RUBY_T_ARRAY | RUBY_T_HASH = type_val {
2753
2753
let val_type = asm. ctx . get_opnd_type ( StackOpnd ( 0 ) ) ;
2754
2754
let val = asm. stack_pop ( 1 ) ;
2755
- let val = asm. load ( val) ;
2756
2755
2757
2756
// Check if we know from type information
2758
2757
match val_type. known_value_type ( ) {
@@ -2770,6 +2769,7 @@ fn gen_checktype(
2770
2769
2771
2770
let ret = asm. new_label ( "ret" ) ;
2772
2771
2772
+ let val = asm. load ( val) ;
2773
2773
if !val_type. is_heap ( ) {
2774
2774
// if (SPECIAL_CONST_P(val)) {
2775
2775
// Return Qfalse via REG1 if not on heap
@@ -5417,6 +5417,7 @@ fn gen_send_cfunc(
5417
5417
if let Some ( known_cfunc_codegen) = codegen_p {
5418
5418
if known_cfunc_codegen ( jit, asm, ocb, ci, cme, block, argc, recv_known_klass) {
5419
5419
assert_eq ! ( expected_stack_after, asm. ctx. get_stack_size( ) as i32 ) ;
5420
+ gen_counter_incr ( asm, Counter :: num_send_known_cfunc) ;
5420
5421
// cfunc codegen generated code. Terminate the block so
5421
5422
// there isn't multiple calls in the same block.
5422
5423
jump_to_next_insn ( jit, asm, ocb) ;
@@ -5852,6 +5853,31 @@ fn gen_send_bmethod(
5852
5853
gen_send_iseq ( jit, asm, ocb, iseq, ci, frame_type, Some ( capture. ep ) , cme, block, flags, argc, None )
5853
5854
}
5854
5855
5856
+ /// Return the ISEQ's return value if it consists of only putnil/putobject and leave.
5857
+ fn iseq_get_return_value ( iseq : IseqPtr ) -> Option < VALUE > {
5858
+ // Expect only two instructions and one possible operand
5859
+ let iseq_size = unsafe { get_iseq_encoded_size ( iseq) } ;
5860
+ if !( 2 ..=3 ) . contains ( & iseq_size) {
5861
+ return None ;
5862
+ }
5863
+
5864
+ // Get the first two instructions
5865
+ let first_insn = iseq_opcode_at_idx ( iseq, 0 ) ;
5866
+ let second_insn = iseq_opcode_at_idx ( iseq, insn_len ( first_insn as usize ) ) ;
5867
+
5868
+ // Extract the return value if known
5869
+ if second_insn != YARVINSN_leave {
5870
+ return None ;
5871
+ }
5872
+ match first_insn {
5873
+ YARVINSN_putnil => Some ( Qnil ) ,
5874
+ YARVINSN_putobject => unsafe { Some ( * rb_iseq_pc_at_idx ( iseq, 1 ) ) } ,
5875
+ YARVINSN_putobject_INT2FIX_0_ => Some ( VALUE :: fixnum_from_usize ( 0 ) ) ,
5876
+ YARVINSN_putobject_INT2FIX_1_ => Some ( VALUE :: fixnum_from_usize ( 1 ) ) ,
5877
+ _ => None ,
5878
+ }
5879
+ }
5880
+
5855
5881
fn gen_send_iseq (
5856
5882
jit : & mut JITState ,
5857
5883
asm : & mut Assembler ,
@@ -6112,8 +6138,6 @@ fn gen_send_iseq(
6112
6138
if let ( None , Some ( builtin_info) , true , false ) = ( block, builtin_func, builtin_attrs & BUILTIN_ATTR_LEAF != 0 , opt_send_call) {
6113
6139
let builtin_argc = unsafe { ( * builtin_info) . argc } ;
6114
6140
if builtin_argc + 1 < ( C_ARG_OPNDS . len ( ) as i32 ) {
6115
- asm_comment ! ( asm, "inlined leaf builtin" ) ;
6116
-
6117
6141
// We pop the block arg without using it because:
6118
6142
// - the builtin is leaf, so it promises to not `yield`.
6119
6143
// - no leaf builtins have block param at the time of writing, and
@@ -6126,6 +6150,9 @@ fn gen_send_iseq(
6126
6150
asm. stack_pop ( 1 ) ;
6127
6151
}
6128
6152
6153
+ asm_comment ! ( asm, "inlined leaf builtin" ) ;
6154
+ gen_counter_incr ( asm, Counter :: num_send_leaf_builtin) ;
6155
+
6129
6156
// Skip this if it doesn't trigger GC
6130
6157
if builtin_attrs & BUILTIN_ATTR_NO_GC == 0 {
6131
6158
// The callee may allocate, e.g. Integer#abs on a Bignum.
@@ -6152,10 +6179,29 @@ fn gen_send_iseq(
6152
6179
// Note: assuming that the leaf builtin doesn't change local variables here.
6153
6180
// Seems like a safe assumption.
6154
6181
6155
- return Some ( KeepCompiling ) ;
6182
+ // Let guard chains share the same successor
6183
+ jump_to_next_insn ( jit, asm, ocb) ;
6184
+ return Some ( EndBlock ) ;
6156
6185
}
6157
6186
}
6158
6187
6188
+ // Inline simple ISEQs whose return value is known at compile time
6189
+ if let ( Some ( value) , None , false ) = ( iseq_get_return_value ( iseq) , block_arg_type, opt_send_call) {
6190
+ asm_comment ! ( asm, "inlined simple ISEQ" ) ;
6191
+ gen_counter_incr ( asm, Counter :: num_send_inline) ;
6192
+
6193
+ // Pop receiver and arguments
6194
+ asm. stack_pop ( argc as usize + if captured_opnd. is_some ( ) { 0 } else { 1 } ) ;
6195
+
6196
+ // Push the return value
6197
+ let stack_ret = asm. stack_push ( Type :: from ( value) ) ;
6198
+ asm. mov ( stack_ret, value. into ( ) ) ;
6199
+
6200
+ // Let guard chains share the same successor
6201
+ jump_to_next_insn ( jit, asm, ocb) ;
6202
+ return Some ( EndBlock ) ;
6203
+ }
6204
+
6159
6205
// Stack overflow check
6160
6206
// Note that vm_push_frame checks it against a decremented cfp, hence the multiply by 2.
6161
6207
// #define CHECK_VM_STACK_OVERFLOW0(cfp, sp, margin)
0 commit comments