@@ -3166,6 +3166,56 @@ gen_getblockparamproxy(jitstate_t *jit, ctx_t *ctx)
31663166 return YJIT_KEEP_COMPILING ;
31673167}
31683168
3169+ // opt_invokebuiltin_delegate calls a builtin function, like
3170+ // invokebuiltin does, but instead of taking arguments from the top of the
3171+ // stack uses the argument locals (and self) from the current method.
3172+ static codegen_status_t
3173+ gen_opt_invokebuiltin_delegate (jitstate_t * jit , ctx_t * ctx )
3174+ {
3175+ const struct rb_builtin_function * bf = (struct rb_builtin_function * )jit_get_arg (jit , 0 );
3176+ int32_t start_index = (int32_t )jit_get_arg (jit , 1 );
3177+
3178+ if (bf -> argc + 2 >= NUM_C_ARG_REGS ) {
3179+ return YJIT_CANT_COMPILE ;
3180+ }
3181+
3182+ // If the calls don't allocate, do they need up to date PC, SP?
3183+ jit_save_pc (jit , REG0 );
3184+ jit_save_sp (jit , ctx );
3185+
3186+ // Save YJIT registers
3187+ yjit_save_regs (cb );
3188+
3189+ if (bf -> argc > 0 ) {
3190+ // Load environment pointer EP from CFP
3191+ mov (cb , REG0 , member_opnd (REG_CFP , rb_control_frame_t , ep ));
3192+ }
3193+
3194+ // Save self from CFP
3195+ mov (cb , REG1 , member_opnd (REG_CFP , rb_control_frame_t , self ));
3196+
3197+ // Call the builtin func (ec, recv, arg1, arg2, ...)
3198+ mov (cb , C_ARG_REGS [0 ], REG_EC ); // clobbers REG_CFP
3199+ mov (cb , C_ARG_REGS [1 ], REG1 ); // self, clobbers REG_EC
3200+
3201+ // Copy arguments from locals
3202+ for (int32_t i = 0 ; i < bf -> argc ; i ++ ) {
3203+ const int32_t offs = - jit -> iseq -> body -> local_table_size - VM_ENV_DATA_SIZE + 1 + start_index + i ;
3204+ x86opnd_t local_opnd = mem_opnd (64 , REG0 , offs * SIZEOF_VALUE );
3205+ x86opnd_t c_arg_reg = C_ARG_REGS [i + 2 ];
3206+ mov (cb , c_arg_reg , local_opnd );
3207+ }
3208+ call_ptr (cb , REG0 , (void * )bf -> func_ptr );
3209+
3210+ // Load YJIT registers
3211+ yjit_load_regs (cb );
3212+
3213+ // Push the return value
3214+ x86opnd_t stack_ret = ctx_stack_push (ctx , TYPE_UNKNOWN );
3215+ mov (cb , stack_ret , RAX );
3216+
3217+ return YJIT_KEEP_COMPILING ;
3218+ }
31693219
31703220static void
31713221yjit_reg_op (int opcode , codegen_fn gen_fn )
@@ -3237,6 +3287,8 @@ yjit_init_codegen(void)
32373287 yjit_reg_op (BIN (opt_str_uminus ), gen_opt_str_uminus );
32383288 yjit_reg_op (BIN (opt_not ), gen_opt_not );
32393289 yjit_reg_op (BIN (opt_getinlinecache ), gen_opt_getinlinecache );
3290+ yjit_reg_op (BIN (opt_invokebuiltin_delegate ), gen_opt_invokebuiltin_delegate );
3291+ yjit_reg_op (BIN (opt_invokebuiltin_delegate_leave ), gen_opt_invokebuiltin_delegate );
32403292 yjit_reg_op (BIN (branchif ), gen_branchif );
32413293 yjit_reg_op (BIN (branchunless ), gen_branchunless );
32423294 yjit_reg_op (BIN (branchnil ), gen_branchnil );
0 commit comments