@@ -766,6 +766,79 @@ gen_opt_plus(jitstate_t* jit, ctx_t* ctx)
766766 return true;
767767}
768768
769+ static bool
770+ gen_opt_aref (jitstate_t * jit , ctx_t * ctx )
771+ {
772+ struct rb_call_data * cd = (struct rb_call_data * )jit_get_arg (jit , 0 );
773+ int32_t argc = (int32_t )vm_ci_argc (cd -> ci );
774+
775+ // Only JIT one arg calls like `ary[6]`
776+ if (argc != 1 ) {
777+ return false;
778+ }
779+
780+ const rb_callable_method_entry_t * cme = vm_cc_cme (cd -> cc );
781+
782+ // Bail if the inline cache has been filled. Currently, certain types
783+ // (including arrays) don't use the inline cache, so if the inline cache
784+ // has an entry, then this must be used by some other type.
785+ if (cme ) {
786+ return false;
787+ }
788+
789+ // Create a size-exit to fall back to the interpreter
790+ uint8_t * side_exit = ujit_side_exit (jit , ctx );
791+
792+ x86opnd_t recv = ctx_stack_opnd (ctx , argc );
793+
794+ mov (cb , REG0 , recv );
795+
796+ // if (SPECIAL_CONST_P(recv)) {
797+ // Bail if it's not a heap object
798+ test (cb , REG0 , imm_opnd (RUBY_IMMEDIATE_MASK ));
799+ jnz_ptr (cb , side_exit );
800+ cmp (cb , REG0 , imm_opnd (Qfalse ));
801+ je_ptr (cb , side_exit );
802+ cmp (cb , REG0 , imm_opnd (Qnil ));
803+ je_ptr (cb , side_exit );
804+
805+ // Bail if recv is *not* an array
806+ x86opnd_t klass_opnd = mem_opnd (64 , REG0 , offsetof(struct RBasic , klass ));
807+ mov (cb , REG0 , klass_opnd );
808+ mov (cb , REG1 , const_ptr_opnd ((void * )rb_cArray ));
809+ cmp (cb , REG0 , REG1 );
810+ jne_ptr (cb , side_exit );
811+
812+ // Bail if arg0 is *not* an FIXNUM
813+ x86opnd_t operand = ctx_stack_opnd (ctx , 0 );
814+ mov (cb , REG1 , operand );
815+ test (cb , REG1 , imm_opnd (RUBY_FIXNUM_FLAG ));
816+ jz_ptr (cb , side_exit );
817+
818+ // Save MicroJIT registers
819+ push (cb , REG_CFP );
820+ push (cb , REG_EC );
821+ push (cb , REG_SP );
822+ // Maintain 16-byte RSP alignment
823+ sub (cb , RSP , imm_opnd (8 ));
824+
825+ mov (cb , RDI , recv );
826+ sar (cb , REG1 , imm_opnd (1 )); // Convert fixnum to int
827+ mov (cb , RSI , REG1 );
828+ call_ptr (cb , REG0 , (void * )rb_ary_entry_internal );
829+
830+ // Restore registers
831+ add (cb , RSP , imm_opnd (8 ));
832+ pop (cb , REG_SP );
833+ pop (cb , REG_EC );
834+ pop (cb , REG_CFP );
835+
836+ x86opnd_t stack_ret = ctx_stack_push (ctx , T_NONE );
837+ mov (cb , stack_ret , RAX );
838+
839+ return true;
840+ }
841+
769842void
770843gen_branchif_branch (codeblock_t * cb , uint8_t * target0 , uint8_t * target1 , uint8_t shape )
771844{
@@ -1429,4 +1502,5 @@ ujit_init_codegen(void)
14291502 ujit_reg_op (BIN (jump ), gen_jump , true);
14301503 ujit_reg_op (BIN (opt_send_without_block ), gen_opt_send_without_block , true);
14311504 ujit_reg_op (BIN (leave ), gen_leave , true);
1505+ ujit_reg_op (BIN (opt_aref ), gen_opt_aref , false);
14321506}
0 commit comments