@@ -1479,30 +1479,120 @@ def opt_newarray_min(jit, ctx, asm)
14791479 # @param ctx [RubyVM::RJIT::Context]
14801480 # @param asm [RubyVM::RJIT::Assembler]
14811481 def invokesuper ( jit , ctx , asm )
1482- # Specialize on a compile-time receiver, and split a block for chain guards
1482+ cd = C . rb_call_data . new ( jit . operand ( 0 ) )
1483+ block = jit . operand ( 1 )
1484+
1485+ # Defer compilation so we can specialize on class of receiver
14831486 unless jit . at_current_insn?
14841487 defer_compilation ( jit , ctx , asm )
14851488 return EndBlock
14861489 end
14871490
1488- cd = C . rb_call_data . new ( jit . operand ( 0 ) )
1489- blockiseq = jit . operand ( 1 )
1491+ me = C . rb_vm_frame_method_entry ( jit . cfp )
1492+ if me . nil?
1493+ return CantCompile
1494+ end
14901495
1491- block_handler = jit_caller_setup_arg_block ( jit , ctx , asm , cd . ci , blockiseq , true )
1492- if block_handler == CantCompile
1496+ # FIXME: We should track and invalidate this block when this cme is invalidated
1497+ current_defined_class = me . defined_class
1498+ mid = me . def . original_id
1499+
1500+ if me . to_i != C . rb_callable_method_entry ( current_defined_class , me . called_id ) . to_i
1501+ # Though we likely could generate this call, as we are only concerned
1502+ # with the method entry remaining valid, assume_method_lookup_stable
1503+ # below requires that the method lookup matches as well
14931504 return CantCompile
14941505 end
14951506
1496- # calling->ci
1497- mid = C . vm_ci_mid ( cd . ci )
1498- calling = build_calling ( ci : cd . ci , block_handler :)
1507+ # vm_search_normal_superclass
1508+ rbasic_klass = C . to_ruby ( C . RBasic . new ( C . to_value ( current_defined_class ) ) . klass )
1509+ if C ::BUILTIN_TYPE ( current_defined_class ) == C ::RUBY_T_ICLASS && C ::BUILTIN_TYPE ( rbasic_klass ) == C ::RUBY_T_MODULE && \
1510+ C ::FL_TEST_RAW ( rbasic_klass , C ::RMODULE_IS_REFINEMENT ) != 0
1511+ return CantCompile
1512+ end
1513+ comptime_superclass = C . rb_class_get_superclass ( C . RCLASS_ORIGIN ( current_defined_class ) )
14991514
1500- # vm_sendish
1501- cme = jit_search_super_method ( jit , ctx , asm , mid , calling )
1502- if cme == CantCompile
1515+ ci = cd . ci
1516+ argc = C . vm_ci_argc ( ci )
1517+
1518+ ci_flags = C . vm_ci_flag ( ci )
1519+
1520+ # Don't JIT calls that aren't simple
1521+ # Note, not using VM_CALL_ARGS_SIMPLE because sometimes we pass a block.
1522+
1523+ if ci_flags & C ::VM_CALL_KWARG != 0
1524+ asm . incr_counter ( :send_keywords )
15031525 return CantCompile
15041526 end
1505- jit_call_general ( jit , ctx , asm , mid , calling , cme , nil )
1527+ if ci_flags & C ::VM_CALL_KW_SPLAT != 0
1528+ asm . incr_counter ( :send_kw_splat )
1529+ return CantCompile
1530+ end
1531+ if ci_flags & C ::VM_CALL_ARGS_BLOCKARG != 0
1532+ asm . incr_counter ( :send_block_arg )
1533+ return CantCompile
1534+ end
1535+
1536+ # Ensure we haven't rebound this method onto an incompatible class.
1537+ # In the interpreter we try to avoid making this check by performing some
1538+ # cheaper calculations first, but since we specialize on the method entry
1539+ # and so only have to do this once at compile time this is fine to always
1540+ # check and side exit.
1541+ comptime_recv = jit . peek_at_stack ( argc )
1542+ unless C . obj_is_kind_of ( comptime_recv , current_defined_class )
1543+ return CantCompile
1544+ end
1545+
1546+ # Do method lookup
1547+ cme = C . rb_callable_method_entry ( comptime_superclass , mid )
1548+
1549+ if cme . nil?
1550+ return CantCompile
1551+ end
1552+
1553+ # Check that we'll be able to write this method dispatch before generating checks
1554+ cme_def_type = cme . def . type
1555+ if cme_def_type != C ::VM_METHOD_TYPE_ISEQ && cme_def_type != C ::VM_METHOD_TYPE_CFUNC
1556+ # others unimplemented
1557+ return CantCompile
1558+ end
1559+
1560+ asm . comment ( 'guard known me' )
1561+ lep_opnd = :rax
1562+ jit_get_lep ( jit , asm , reg : lep_opnd )
1563+ ep_me_opnd = [ lep_opnd , C . VALUE . size * C ::VM_ENV_DATA_INDEX_ME_CREF ]
1564+
1565+ asm . mov ( :rcx , me . to_i )
1566+ asm . cmp ( ep_me_opnd , :rcx )
1567+ asm . jne ( counted_exit ( side_exit ( jit , ctx ) , :invokesuper_me_changed ) )
1568+
1569+ if block == C ::VM_BLOCK_HANDLER_NONE
1570+ # Guard no block passed
1571+ # rb_vm_frame_block_handler(GET_EC()->cfp) == VM_BLOCK_HANDLER_NONE
1572+ # note, we assume VM_ASSERT(VM_ENV_LOCAL_P(ep))
1573+ #
1574+ # TODO: this could properly forward the current block handler, but
1575+ # would require changes to gen_send_*
1576+ asm . comment ( 'guard no block given' )
1577+ ep_specval_opnd = [ lep_opnd , C . VALUE . size * C ::VM_ENV_DATA_INDEX_SPECVAL ]
1578+ asm . cmp ( ep_specval_opnd , C ::VM_BLOCK_HANDLER_NONE )
1579+ asm . jne ( counted_exit ( side_exit ( jit , ctx ) , :invokesuper_block ) )
1580+ end
1581+
1582+ # We need to assume that both our current method entry and the super
1583+ # method entry we invoke remain stable
1584+ Invariants . assume_method_lookup_stable ( jit , me )
1585+ Invariants . assume_method_lookup_stable ( jit , cme )
1586+
1587+ calling = build_calling ( ci :, block_handler : block )
1588+ case cme_def_type
1589+ in C ::VM_METHOD_TYPE_ISEQ
1590+ iseq = def_iseq_ptr ( cme . def )
1591+ frame_type = C ::VM_FRAME_MAGIC_METHOD | C ::VM_ENV_FLAG_LOCAL
1592+ jit_call_iseq ( jit , ctx , asm , cme , calling , iseq , frame_type :)
1593+ in C ::VM_METHOD_TYPE_CFUNC
1594+ jit_call_cfunc ( jit , ctx , asm , cme , calling , nil )
1595+ end
15061596 end
15071597
15081598 # @param jit [RubyVM::RJIT::JITState]
@@ -3906,87 +3996,6 @@ def jit_search_method(jit, ctx, asm, mid, calling)
39063996 return cme , comptime_recv_klass
39073997 end
39083998
3909- def jit_search_super_method ( jit , ctx , asm , mid , calling )
3910- assert_equal ( true , jit . at_current_insn? )
3911-
3912- me = C . rb_vm_frame_method_entry ( jit . cfp )
3913- if me . nil?
3914- return CantCompile
3915- end
3916-
3917- # FIXME: We should track and invalidate this block when this cme is invalidated
3918- current_defined_class = me . defined_class
3919- mid = me . def . original_id
3920-
3921- if me . to_i != C . rb_callable_method_entry ( current_defined_class , me . called_id ) . to_i
3922- # Though we likely could generate this call, as we are only concerned
3923- # with the method entry remaining valid, assume_method_lookup_stable
3924- # below requires that the method lookup matches as well
3925- return CantCompile
3926- end
3927-
3928- # vm_search_normal_superclass
3929- rbasic_klass = C . to_ruby ( C . RBasic . new ( C . to_value ( current_defined_class ) ) . klass )
3930- if C ::BUILTIN_TYPE ( current_defined_class ) == C ::RUBY_T_ICLASS && C ::BUILTIN_TYPE ( rbasic_klass ) == C ::RUBY_T_MODULE && \
3931- C ::FL_TEST_RAW ( rbasic_klass , C ::RMODULE_IS_REFINEMENT ) != 0
3932- return CantCompile
3933- end
3934- comptime_superclass = C . rb_class_get_superclass ( C . RCLASS_ORIGIN ( current_defined_class ) )
3935-
3936- # Don't JIT calls that aren't simple
3937- # Note, not using VM_CALL_ARGS_SIMPLE because sometimes we pass a block.
3938-
3939- if calling . flags & C ::VM_CALL_KWARG != 0
3940- asm . incr_counter ( :send_kwarg )
3941- return CantCompile
3942- end
3943- if calling . flags & C ::VM_CALL_KW_SPLAT != 0
3944- asm . incr_counter ( :send_kw_splat )
3945- return CantCompile
3946- end
3947-
3948- # Ensure we haven't rebound this method onto an incompatible class.
3949- # In the interpreter we try to avoid making this check by performing some
3950- # cheaper calculations first, but since we specialize on the method entry
3951- # and so only have to do this once at compile time this is fine to always
3952- # check and side exit.
3953- comptime_recv = jit . peek_at_stack ( calling . argc )
3954- unless C . obj_is_kind_of ( comptime_recv , current_defined_class )
3955- return CantCompile
3956- end
3957-
3958- # Do method lookup
3959- cme = C . rb_callable_method_entry ( comptime_superclass , mid )
3960-
3961- if cme . nil?
3962- return CantCompile
3963- end
3964-
3965- # Check that we'll be able to write this method dispatch before generating checks
3966- cme_def_type = cme . def . type
3967- if cme_def_type != C ::VM_METHOD_TYPE_ISEQ && cme_def_type != C ::VM_METHOD_TYPE_CFUNC
3968- # others unimplemented
3969- return CantCompile
3970- end
3971-
3972- # Guard that the receiver has the same class as the one from compile time
3973- side_exit = side_exit ( jit , ctx )
3974-
3975- asm . comment ( 'guard known me' )
3976- jit_get_lep ( jit , asm , reg : :rax )
3977-
3978- asm . mov ( :rcx , me . to_i )
3979- asm . cmp ( [ :rax , C . VALUE . size * C ::VM_ENV_DATA_INDEX_ME_CREF ] , :rcx )
3980- asm . jne ( counted_exit ( side_exit , :invokesuper_me_changed ) )
3981-
3982- # We need to assume that both our current method entry and the super
3983- # method entry we invoke remain stable
3984- Invariants . assume_method_lookup_stable ( jit , me )
3985- Invariants . assume_method_lookup_stable ( jit , cme )
3986-
3987- return cme
3988- end
3989-
39903999 # vm_call_general
39914000 # @param jit [RubyVM::RJIT::JITState]
39924001 # @param ctx [RubyVM::RJIT::Context]
0 commit comments