diff options
author | Takashi Kokubun <[email protected]> | 2024-08-08 16:13:16 -0700 |
---|---|---|
committer | GitHub <[email protected]> | 2024-08-08 16:13:16 -0700 |
commit | 77ffdfe79fc9dc0b327ff88ea3df4082183c08f6 (patch) | |
tree | c078ab5431c2cd8934edeaedab2f5e2d1e6792a1 | |
parent | ec5436bc3a8e7c616a9b88c08d766180894ea82d (diff) |
YJIT: Allow tracing fallback counters (#11347)
* YJIT: Allow tracing fallback counters
* Update yjit.md about --yjit-trace-exits=counter
Notes
Notes:
Merged-By: k0kubun <[email protected]>
-rw-r--r-- | doc/yjit/yjit.md | 2 | ||||
-rw-r--r-- | yjit/src/codegen.rs | 319 | ||||
-rw-r--r-- | yjit/src/options.rs | 6 |
3 files changed, 174 insertions, 153 deletions
diff --git a/doc/yjit/yjit.md b/doc/yjit/yjit.md index b2769a0f5d..c63d31b64f 100644 --- a/doc/yjit/yjit.md +++ b/doc/yjit/yjit.md @@ -179,7 +179,7 @@ YJIT supports all command-line options supported by upstream CRuby, but also add This can allow you to use a lower executable memory size limit, but may cause a slight drop in performance when the limit is hit. - `--yjit-perf`: enable frame pointers and profiling with the `perf` tool - `--yjit-trace-exits`: produce a Marshal dump of backtraces from all exits. Automatically enables `--yjit-stats` -- `--yjit-trace-exits=COUNTER`: produce a Marshal dump of backtraces from specified exits. Automatically enables `--yjit-stats` +- `--yjit-trace-exits=COUNTER`: produce a Marshal dump of backtraces from a counted exit or a fallback. Automatically enables `--yjit-stats` - `--yjit-trace-exits-sample-rate=N`: trace exit locations only every Nth occurrence. Automatically enables `--yjit-trace-exits` Note that there is also an environment variable `RUBY_YJIT_ENABLE` which can be used to enable YJIT. diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index a9b3a2dcda..458777b5e3 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -460,8 +460,31 @@ pub enum JCCKinds { JCC_JO_MUL, } +/// Generate code to increment a given counter. With --yjit-trace-exits=counter, +/// the counter is traced when it's incremented by this function. #[inline(always)] -fn gen_counter_incr(asm: &mut Assembler, counter: Counter) { +fn gen_counter_incr(jit: &JITState, asm: &mut Assembler, counter: Counter) { + gen_counter_incr_with_pc(asm, counter, jit.pc); +} + +/// Same as gen_counter_incr(), but takes PC isntead of JITState. +#[inline(always)] +fn gen_counter_incr_with_pc(asm: &mut Assembler, counter: Counter, pc: *mut VALUE) { + gen_counter_incr_without_pc(asm, counter); + + // Trace a counter if --yjit-trace-exits=counter is given. + // TraceExits::All is handled by gen_exit(). + if get_option!(trace_exits) == Some(TraceExits::Counter(counter)) { + with_caller_saved_temp_regs(asm, |asm| { + asm.ccall(rb_yjit_record_exit_stack as *const u8, vec![Opnd::const_ptr(pc as *const u8)]); + }); + } +} + +/// Generate code to increment a given counter. Not traced by --yjit-trace-exits=counter +/// unlike gen_counter_incr() or gen_counter_incr_with_pc(). +#[inline(always)] +fn gen_counter_incr_without_pc(asm: &mut Assembler, counter: Counter) { // Assert that default counters are not incremented by generated code as this would impact performance assert!(!DEFAULT_COUNTERS.contains(&counter), "gen_counter_incr incremented {:?}", counter); @@ -723,7 +746,7 @@ fn gen_stub_exit(ocb: &mut OutlinedCb) -> Option<CodePtr> { let ocb = ocb.unwrap(); let mut asm = Assembler::new_without_iseq(); - gen_counter_incr(&mut asm, Counter::exit_from_branch_stub); + gen_counter_incr_without_pc(&mut asm, Counter::exit_from_branch_stub); asm_comment!(asm, "exit from branch stub"); asm.cpop_into(SP); @@ -833,15 +856,7 @@ pub fn gen_counted_exit(exit_pc: *mut VALUE, side_exit: CodePtr, ocb: &mut Outli let mut asm = Assembler::new_without_iseq(); // Increment a counter - gen_counter_incr(&mut asm, counter); - - // Trace a counted exit if --yjit-trace-exits=counter is given. - // TraceExits::All is handled by gen_exit(). - if get_option!(trace_exits) == Some(TraceExits::CountedExit(counter)) { - with_caller_saved_temp_regs(&mut asm, |asm| { - asm.ccall(rb_yjit_record_exit_stack as *const u8, vec![Opnd::const_ptr(exit_pc as *const u8)]); - }); - } + gen_counter_incr_with_pc(&mut asm, counter, exit_pc); // Jump to the existing side exit asm.jmp(Target::CodePtr(side_exit)); @@ -901,7 +916,7 @@ fn gen_full_cfunc_return(ocb: &mut OutlinedCb) -> Option<CodePtr> { ); // Count the exit - gen_counter_incr(&mut asm, Counter::traced_cfunc_return); + gen_counter_incr_without_pc(&mut asm, Counter::traced_cfunc_return); // Return to the interpreter asm.cpop_into(SP); @@ -926,7 +941,7 @@ fn gen_leave_exit(ocb: &mut OutlinedCb) -> Option<CodePtr> { let ret_opnd = asm.live_reg_opnd(C_RET_OPND); // Every exit to the interpreter should be counted - gen_counter_incr(&mut asm, Counter::leave_interp_return); + gen_counter_incr_without_pc(&mut asm, Counter::leave_interp_return); asm_comment!(asm, "exit from leave"); asm.cpop_into(SP); @@ -952,7 +967,7 @@ fn gen_leave_exception(ocb: &mut OutlinedCb) -> Option<CodePtr> { let ruby_ret_val = asm.live_reg_opnd(C_RET_OPND); // Every exit to the interpreter should be counted - gen_counter_incr(&mut asm, Counter::leave_interp_return); + gen_counter_incr_without_pc(&mut asm, Counter::leave_interp_return); asm_comment!(asm, "push return value through cfp->sp"); let cfp_sp = Opnd::mem(64, CFP, RUBY_OFFSET_CFP_SP); @@ -1257,7 +1272,7 @@ pub fn gen_single_block( // :count-placement: // Count bytecode instructions that execute in generated code. // Note that the increment happens even when the output takes side exit. - gen_counter_incr(&mut asm, Counter::yjit_insns_count); + gen_counter_incr(&jit, &mut asm, Counter::yjit_insns_count); // Lookup the codegen function for this instruction let mut status = None; @@ -2118,13 +2133,13 @@ fn gen_expandarray( // If this instruction has the splat flag, then bail out. if flag & 0x01 != 0 { - gen_counter_incr(asm, Counter::expandarray_splat); + gen_counter_incr(jit, asm, Counter::expandarray_splat); return None; } // If this instruction has the postarg flag, then bail out. if flag & 0x02 != 0 { - gen_counter_incr(asm, Counter::expandarray_postarg); + gen_counter_incr(jit, asm, Counter::expandarray_postarg); return None; } @@ -2146,7 +2161,7 @@ fn gen_expandarray( // if to_ary is defined, return can't compile so to_ary can be called if cme_def_type != VM_METHOD_TYPE_UNDEF { - gen_counter_incr(asm, Counter::expandarray_to_ary); + gen_counter_incr(jit, asm, Counter::expandarray_to_ary); return None; } @@ -2720,7 +2735,7 @@ fn gen_get_ivar( // Use a general C call at the last chain to avoid exits on megamorphic shapes let megamorphic = asm.ctx.get_chain_depth() >= max_chain_depth; if megamorphic { - gen_counter_incr(asm, Counter::num_getivar_megamorphic); + gen_counter_incr(jit, asm, Counter::num_getivar_megamorphic); } // If the class uses the default allocator, instances should all be T_OBJECT @@ -2930,7 +2945,7 @@ fn gen_set_ivar( // If the comptime receiver is frozen, writing an IV will raise an exception // and we don't want to JIT code to deal with that situation. if comptime_receiver.is_frozen() { - gen_counter_incr(asm, Counter::setivar_frozen); + gen_counter_incr(jit, asm, Counter::setivar_frozen); return None; } @@ -2951,7 +2966,7 @@ fn gen_set_ivar( // Use a general C call at the last chain to avoid exits on megamorphic shapes let megamorphic = asm.ctx.get_chain_depth() >= SET_IVAR_MAX_DEPTH; if megamorphic { - gen_counter_incr(asm, Counter::num_setivar_megamorphic); + gen_counter_incr(jit, asm, Counter::num_setivar_megamorphic); } // Get the iv index @@ -3649,7 +3664,7 @@ fn gen_opt_aref( // Only JIT one arg calls like `ary[6]` if argc != 1 { - gen_counter_incr(asm, Counter::opt_aref_argc_not_one); + gen_counter_incr(jit, asm, Counter::opt_aref_argc_not_one); return None; } @@ -4396,7 +4411,7 @@ fn gen_opt_case_dispatch( // If megamorphic, fallback to compiling branch instructions after opt_case_dispatch let megamorphic = asm.ctx.get_chain_depth() >= CASE_WHEN_MAX_DEPTH; if megamorphic { - gen_counter_incr(asm, Counter::num_opt_case_dispatch_megamorphic); + gen_counter_incr(jit, asm, Counter::num_opt_case_dispatch_megamorphic); } if comptime_key.fixnum_p() && comptime_key.0 <= u32::MAX.as_usize() && case_hash_all_fixnum_p(case_hash) && !megamorphic { @@ -4603,11 +4618,11 @@ fn gen_throw( let throwobj = asm.load(throwobj); // Gather some statistics about throw - gen_counter_incr(asm, Counter::num_throw); + gen_counter_incr(jit, asm, Counter::num_throw); match (throw_state & VM_THROW_STATE_MASK as u64) as u32 { - RUBY_TAG_BREAK => gen_counter_incr(asm, Counter::num_throw_break), - RUBY_TAG_RETRY => gen_counter_incr(asm, Counter::num_throw_retry), - RUBY_TAG_RETURN => gen_counter_incr(asm, Counter::num_throw_return), + RUBY_TAG_BREAK => gen_counter_incr(jit, asm, Counter::num_throw_break), + RUBY_TAG_RETRY => gen_counter_incr(jit, asm, Counter::num_throw_retry), + RUBY_TAG_RETURN => gen_counter_incr(jit, asm, Counter::num_throw_return), _ => {}, } @@ -6450,11 +6465,11 @@ fn gen_send_cfunc( // If it's a splat and the method expects a Ruby array of arguments if cfunc_argc == -2 && flags & VM_CALL_ARGS_SPLAT != 0 { - gen_counter_incr(asm, Counter::send_cfunc_splat_neg2); + gen_counter_incr(jit, asm, Counter::send_cfunc_splat_neg2); return None; } - exit_if_kwsplat_non_nil(asm, flags, Counter::send_cfunc_kw_splat_non_nil)?; + exit_if_kwsplat_non_nil(jit, asm, flags, Counter::send_cfunc_kw_splat_non_nil)?; let kw_splat = flags & VM_CALL_KW_SPLAT != 0; let kw_arg = unsafe { vm_ci_kwarg(ci) }; @@ -6465,18 +6480,18 @@ fn gen_send_cfunc( }; if kw_arg_num != 0 && flags & VM_CALL_ARGS_SPLAT != 0 { - gen_counter_incr(asm, Counter::send_cfunc_splat_with_kw); + gen_counter_incr(jit, asm, Counter::send_cfunc_splat_with_kw); return None; } if c_method_tracing_currently_enabled(jit) { // Don't JIT if tracing c_call or c_return - gen_counter_incr(asm, Counter::send_cfunc_tracing); + gen_counter_incr(jit, asm, Counter::send_cfunc_tracing); return None; } // Increment total cfunc send count - gen_counter_incr(asm, Counter::num_send_cfunc); + gen_counter_incr(jit, asm, Counter::num_send_cfunc); // Delegate to codegen for C methods if we have it. if kw_arg.is_null() && @@ -6499,7 +6514,7 @@ fn gen_send_cfunc( if cfunc_codegen { assert_eq!(expected_stack_after, asm.ctx.get_stack_size() as i32); - gen_counter_incr(asm, Counter::num_send_cfunc_inline); + gen_counter_incr(jit, asm, Counter::num_send_cfunc_inline); // cfunc codegen generated code. Terminate the block so // there isn't multiple calls in the same block. jump_to_next_insn(jit, asm); @@ -6525,7 +6540,7 @@ fn gen_send_cfunc( let splat_array_idx = i32::from(kw_splat) + i32::from(block_arg); let comptime_splat_array = jit.peek_at_stack(&asm.ctx, splat_array_idx as isize); if unsafe { rb_yjit_ruby2_keywords_splat_p(comptime_splat_array) } != 0 { - gen_counter_incr(asm, Counter::send_cfunc_splat_varg_ruby2_keywords); + gen_counter_incr(jit, asm, Counter::send_cfunc_splat_varg_ruby2_keywords); return None; } @@ -6554,13 +6569,13 @@ fn gen_send_cfunc( // If the argument count doesn't match if cfunc_argc >= 0 && cfunc_argc != passed_argc && flags & VM_CALL_ARGS_SPLAT == 0 { - gen_counter_incr(asm, Counter::send_cfunc_argc_mismatch); + gen_counter_incr(jit, asm, Counter::send_cfunc_argc_mismatch); return None; } // Don't JIT functions that need C stack arguments for now if cfunc_argc >= 0 && passed_argc + 1 > (C_ARG_OPNDS.len() as i32) { - gen_counter_incr(asm, Counter::send_cfunc_toomany_args); + gen_counter_incr(jit, asm, Counter::send_cfunc_toomany_args); return None; } @@ -6578,7 +6593,7 @@ fn gen_send_cfunc( // Nothing to do } _ => { - gen_counter_incr(asm, Counter::send_cfunc_block_arg); + gen_counter_incr(jit, asm, Counter::send_cfunc_block_arg); return None; } } @@ -6614,7 +6629,7 @@ fn gen_send_cfunc( let required_args : u32 = (cfunc_argc as u32).saturating_sub(argc as u32 - 1); // + 1 because we pass self if required_args + 1 >= C_ARG_OPNDS.len() as u32 { - gen_counter_incr(asm, Counter::send_cfunc_toomany_args); + gen_counter_incr(jit, asm, Counter::send_cfunc_toomany_args); return None; } @@ -6964,14 +6979,14 @@ fn gen_send_bmethod( // Optimize for single ractor mode and avoid runtime check for // "defined with an un-shareable Proc in a different Ractor" if !assume_single_ractor_mode(jit, asm) { - gen_counter_incr(asm, Counter::send_bmethod_ractor); + gen_counter_incr(jit, asm, Counter::send_bmethod_ractor); return None; } // Passing a block to a block needs logic different from passing // a block to a method and sometimes requires allocation. Bail for now. if block.is_some() { - gen_counter_incr(asm, Counter::send_bmethod_block_arg); + gen_counter_incr(jit, asm, Counter::send_bmethod_block_arg); return None; } @@ -7134,29 +7149,29 @@ fn gen_send_iseq( let splat_pos = i32::from(block_arg) + i32::from(kw_splat) + kw_arg_num; exit_if_stack_too_large(iseq)?; - exit_if_tail_call(asm, ci)?; - exit_if_has_post(asm, iseq)?; - exit_if_kwsplat_non_nil(asm, flags, Counter::send_iseq_kw_splat_non_nil)?; - exit_if_has_rest_and_captured(asm, iseq_has_rest, captured_opnd)?; - exit_if_has_kwrest_and_captured(asm, has_kwrest, captured_opnd)?; - exit_if_has_rest_and_supplying_kws(asm, iseq_has_rest, supplying_kws)?; - exit_if_supplying_kw_and_has_no_kw(asm, supplying_kws, doing_kw_call)?; - exit_if_supplying_kws_and_accept_no_kwargs(asm, supplying_kws, iseq)?; - exit_if_doing_kw_and_splat(asm, doing_kw_call, flags)?; + exit_if_tail_call(jit, asm, ci)?; + exit_if_has_post(jit, asm, iseq)?; + exit_if_kwsplat_non_nil(jit, asm, flags, Counter::send_iseq_kw_splat_non_nil)?; + exit_if_has_rest_and_captured(jit, asm, iseq_has_rest, captured_opnd)?; + exit_if_has_kwrest_and_captured(jit, asm, has_kwrest, captured_opnd)?; + exit_if_has_rest_and_supplying_kws(jit, asm, iseq_has_rest, supplying_kws)?; + exit_if_supplying_kw_and_has_no_kw(jit, asm, supplying_kws, doing_kw_call)?; + exit_if_supplying_kws_and_accept_no_kwargs(jit, asm, supplying_kws, iseq)?; + exit_if_doing_kw_and_splat(jit, asm, doing_kw_call, flags)?; if !forwarding { - exit_if_wrong_number_arguments(asm, arg_setup_block, opts_filled, flags, opt_num, iseq_has_rest)?; + exit_if_wrong_number_arguments(jit, asm, arg_setup_block, opts_filled, flags, opt_num, iseq_has_rest)?; } - exit_if_doing_kw_and_opts_missing(asm, doing_kw_call, opts_missing)?; - exit_if_has_rest_and_optional_and_block(asm, iseq_has_rest, opt_num, iseq, block_arg)?; + exit_if_doing_kw_and_opts_missing(jit, asm, doing_kw_call, opts_missing)?; + exit_if_has_rest_and_optional_and_block(jit, asm, iseq_has_rest, opt_num, iseq, block_arg)?; if forwarding && flags & VM_CALL_OPT_SEND != 0 { - gen_counter_incr(asm, Counter::send_iseq_send_forwarding); + gen_counter_incr(jit, asm, Counter::send_iseq_send_forwarding); return None; } let block_arg_type = exit_if_unsupported_block_arg_type(jit, asm, block_arg)?; // Bail if we can't drop extra arguments for a yield by just popping them if supplying_kws && arg_setup_block && argc > (kw_arg_num + required_num + opt_num) { - gen_counter_incr(asm, Counter::send_iseq_complex_discard_extras); + gen_counter_incr(jit, asm, Counter::send_iseq_complex_discard_extras); return None; } @@ -7168,7 +7183,7 @@ fn gen_send_iseq( // In this case (param.flags.has_block && local_iseq != iseq), // the block argument is setup as a local variable and requires // materialization (allocation). Bail. - gen_counter_incr(asm, Counter::send_iseq_materialized_block); + gen_counter_incr(jit, asm, Counter::send_iseq_materialized_block); return None; } } @@ -7176,7 +7191,7 @@ fn gen_send_iseq( // Check that required keyword arguments are supplied and find any extras // that should go into the keyword rest parameter (**kw_rest). if doing_kw_call { - gen_iseq_kw_call_checks(asm, iseq, kw_arg, has_kwrest, kw_arg_num)?; + gen_iseq_kw_call_checks(jit, asm, iseq, kw_arg, has_kwrest, kw_arg_num)?; } let splat_array_length = if splat_call { @@ -7184,7 +7199,7 @@ fn gen_send_iseq( let array_length = if array == Qnil { 0 } else if unsafe { !RB_TYPE_P(array, RUBY_T_ARRAY) } { - gen_counter_incr(asm, Counter::send_iseq_splat_not_array); + gen_counter_incr(jit, asm, Counter::send_iseq_splat_not_array); return None; } else { unsafe { rb_yjit_array_len(array) as u32} @@ -7195,7 +7210,7 @@ fn gen_send_iseq( if !iseq_has_rest { let supplying = argc - 1 - i32::from(kw_splat) + array_length as i32; if (required_num..=required_num + opt_num).contains(&supplying) == false { - gen_counter_incr(asm, Counter::send_iseq_splat_arity_error); + gen_counter_incr(jit, asm, Counter::send_iseq_splat_arity_error); return None; } } @@ -7234,14 +7249,14 @@ fn gen_send_iseq( // If block_arg0_splat, we still need side exits after splat, but // the splat modifies the stack which breaks side exits. So bail out. if splat_call { - gen_counter_incr(asm, Counter::invokeblock_iseq_arg0_args_splat); + gen_counter_incr(jit, asm, Counter::invokeblock_iseq_arg0_args_splat); return None; } // The block_arg0_splat implementation cannot deal with optional parameters. // This is a setup_parameters_complex() situation and interacts with the // starting position of the callee. if opt_num > 1 { - gen_counter_incr(asm, Counter::invokeblock_iseq_arg0_optional); + gen_counter_incr(jit, asm, Counter::invokeblock_iseq_arg0_optional); return None; } } @@ -7275,7 +7290,7 @@ fn gen_send_iseq( } // Increment total ISEQ send count - gen_counter_incr(asm, Counter::num_send_iseq); + gen_counter_incr(jit, asm, Counter::num_send_iseq); // Shortcut for special `Primitive.attr! :leaf` builtins let builtin_attrs = unsafe { rb_yjit_iseq_builtin_attrs(iseq) }; @@ -7292,7 +7307,7 @@ fn gen_send_iseq( // adding one requires interpreter changes to support. if block_arg_type.is_some() { if iseq_has_block_param { - gen_counter_incr(asm, Counter::send_iseq_leaf_builtin_block_arg_block_param); + gen_counter_incr(jit, asm, Counter::send_iseq_leaf_builtin_block_arg_block_param); return None; } asm.stack_pop(1); @@ -7309,7 +7324,7 @@ fn gen_send_iseq( } asm_comment!(asm, "inlined leaf builtin"); - gen_counter_incr(asm, Counter::num_send_iseq_leaf); + gen_counter_incr(jit, asm, Counter::num_send_iseq_leaf); // The callee may allocate, e.g. Integer#abs on a Bignum. // Save SP for GC, save PC for allocation tracing, and prepare @@ -7343,7 +7358,7 @@ 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, captured_opnd, block, flags), block_arg_type, opt_send_call) { asm_comment!(asm, "inlined simple ISEQ"); - gen_counter_incr(asm, Counter::num_send_iseq_inline); + gen_counter_incr(jit, asm, Counter::num_send_iseq_inline); match value { IseqReturn::LocalVariable(local_idx) => { @@ -7454,7 +7469,7 @@ fn gen_send_iseq( let callee_specval = callee_ep + VM_ENV_DATA_INDEX_SPECVAL; if callee_specval < 0 { // Can't write to sp[-n] since that's where the arguments are - gen_counter_incr(asm, Counter::send_iseq_clobbering_block_arg); + gen_counter_incr(jit, asm, Counter::send_iseq_clobbering_block_arg); return None; } let proc = asm.stack_pop(1); // Pop first, as argc doesn't account for the block arg @@ -7480,7 +7495,7 @@ fn gen_send_iseq( // an array that has the same length. We will insert guards. argc = argc - 1 + array_length as i32; if argc + asm.ctx.get_stack_size() as i32 > MAX_SPLAT_LENGTH { - gen_counter_incr(asm, Counter::send_splat_too_long); + gen_counter_incr(jit, asm, Counter::send_splat_too_long); return None; } push_splat_args(array_length, asm); @@ -7853,6 +7868,7 @@ fn gen_send_iseq( // Check if we can handle a keyword call fn gen_iseq_kw_call_checks( + jit: &JITState, asm: &mut Assembler, iseq: *const rb_iseq_t, kw_arg: *const rb_callinfo_kwarg, @@ -7871,7 +7887,7 @@ fn gen_iseq_kw_call_checks( // We have so many keywords that (1 << num) encoded as a FIXNUM // (which shifts it left one more) no longer fits inside a 32-bit // immediate. Similarly, we use a u64 in case of keyword rest parameter. - gen_counter_incr(asm, Counter::send_iseq_too_many_kwargs); + gen_counter_incr(jit, asm, Counter::send_iseq_too_many_kwargs); return None; } @@ -7912,7 +7928,7 @@ fn gen_iseq_kw_call_checks( // If the keyword was never found, then we know we have a // mismatch in the names of the keyword arguments, so we need to // bail. - gen_counter_incr(asm, Counter::send_iseq_kwargs_mismatch); + gen_counter_incr(jit, asm, Counter::send_iseq_kwargs_mismatch); return None; } Some((callee_idx, _)) if callee_idx < keyword_required_num => { @@ -7925,7 +7941,7 @@ fn gen_iseq_kw_call_checks( } assert!(required_kwargs_filled <= keyword_required_num); if required_kwargs_filled != keyword_required_num { - gen_counter_incr(asm, Counter::send_iseq_kwargs_mismatch); + gen_counter_incr(jit, asm, Counter::send_iseq_kwargs_mismatch); return None; } @@ -8177,49 +8193,50 @@ fn gen_iseq_kw_call( /// short-circuit using the ? operator if we return None. /// It would be great if rust let you implement ? for your /// own types, but as of right now they don't. -fn exit_if(asm: &mut Assembler, pred: bool, counter: Counter) -> Option<()> { +fn exit_if(jit: &JITState, asm: &mut Assembler, pred: bool, counter: Counter) -> Option<()> { if pred { - gen_counter_incr(asm, counter); + gen_counter_incr(jit, asm, counter); return None } Some(()) } #[must_use] -fn exit_if_tail_call(asm: &mut Assembler, ci: *const rb_callinfo) -> Option<()> { - exit_if(asm, unsafe { vm_ci_flag(ci) } & VM_CALL_TAILCALL != 0, Counter::send_iseq_tailcall) +fn exit_if_tail_call(jit: &JITState, asm: &mut Assembler, ci: *const rb_callinfo) -> Option<()> { + exit_if(jit, asm, unsafe { vm_ci_flag(ci) } & VM_CALL_TAILCALL != 0, Counter::send_iseq_tailcall) } #[must_use] -fn exit_if_has_post(asm: &mut Assembler, iseq: *const rb_iseq_t) -> Option<()> { - exit_if(asm, unsafe { get_iseq_flags_has_post(iseq) }, Counter::send_iseq_has_post) +fn exit_if_has_post(jit: &JITState, asm: &mut Assembler, iseq: *const rb_iseq_t) -> Option<()> { + exit_if(jit, asm, unsafe { get_iseq_flags_has_post(iseq) }, Counter::send_iseq_has_post) } #[must_use] -fn exit_if_kwsplat_non_nil(asm: &mut Assembler, flags: u32, counter: Counter) -> Option<()> { +fn exit_if_kwsplat_non_nil(jit: &JITState, asm: &mut Assembler, flags: u32, counter: Counter) -> Option<()> { let kw_splat = flags & VM_CALL_KW_SPLAT != 0; let kw_splat_stack = StackOpnd((flags & VM_CALL_ARGS_BLOCKARG != 0).into()); - exit_if(asm, kw_splat && asm.ctx.get_opnd_type(kw_splat_stack) != Type::Nil, counter) + exit_if(jit, asm, kw_splat && asm.ctx.get_opnd_type(kw_splat_stack) != Type::Nil, counter) } #[must_use] -fn exit_if_has_rest_and_captured(asm: &mut Assembler, iseq_has_rest: bool, captured_opnd: Option<Opnd>) -> Option<()> { - exit_if(asm, iseq_has_rest && captured_opnd.is_some(), Counter::send_iseq_has_rest_and_captured) +fn exit_if_has_rest_and_captured(jit: &JITState, asm: &mut Assembler, iseq_has_rest: bool, captured_opnd: Option<Opnd>) -> Option<()> { + exit_if(jit, asm, iseq_has_rest && captured_opnd.is_some(), Counter::send_iseq_has_rest_and_captured) } #[must_use] -fn exit_if_has_kwrest_and_captured(asm: &mut Assembler, iseq_has_kwrest: bool, captured_opnd: Option<Opnd>) -> Option<()> { +fn exit_if_has_kwrest_and_captured(jit: &JITState, asm: &mut Assembler, iseq_has_kwrest: bool, captured_opnd: Option<Opnd>) -> Option<()> { // We need to call a C function to allocate the kwrest hash, but also need to hold the captred // block across the call, which we can't do. - exit_if(asm, iseq_has_kwrest && captured_opnd.is_some(), Counter::send_iseq_has_kwrest_and_captured) + exit_if(jit, asm, iseq_has_kwrest && captured_opnd.is_some(), Counter::send_iseq_has_kwrest_and_captured) } #[must_use] -fn exit_if_has_rest_and_supplying_kws(asm: &mut Assembler, iseq_has_rest: bool, supplying_kws: bool) -> Option<()> { +fn exit_if_has_rest_and_supplying_kws(jit: &JITState, asm: &mut Assembler, iseq_has_rest: bool, supplying_kws: bool) -> Option<()> { // There can be a gap between the rest parameter array and the supplied keywords, or // no space to put the rest array (e.g. `def foo(*arr, k:) = arr; foo(k: 1)` 1 is // sitting where the rest array should be). exit_if( + jit, asm, iseq_has_rest && supplying_kws, Counter::send_iseq_has_rest_and_kw_supplied, @@ -8227,10 +8244,11 @@ fn exit_if_has_rest_and_supplying_kws(asm: &mut Assembler, iseq_has_rest: bool, } #[must_use] -fn exit_if_supplying_kw_and_has_no_kw(asm: &mut Assembler, supplying_kws: bool, callee_kws: bool) -> Option<()> { +fn exit_if_supplying_kw_and_has_no_kw(jit: &JITState, asm: &mut Assembler, supplying_kws: bool, callee_kws: bool) -> Option<()> { // Passing keyword arguments to a callee means allocating a hash and treating // that as a positional argument. Bail for now. exit_if( + jit, asm, supplying_kws && !callee_kws, Counter::send_iseq_has_no_kw, @@ -8238,10 +8256,11 @@ fn exit_if_supplying_kw_and_has_no_kw(asm: &mut Assembler, supplying_kws: bool, } #[must_use] -fn exit_if_supplying_kws_and_accept_no_kwargs(asm: &mut Assembler, supplying_kws: bool, iseq: *const rb_iseq_t) -> Option<()> { +fn exit_if_supplying_kws_and_accept_no_kwargs(jit: &JITState, asm: &mut Assembler, supplying_kws: bool, iseq: *const rb_iseq_t) -> Option<()> { // If we have a method accepting no kwargs (**nil), exit if we have passed // it any kwargs. exit_if( + jit, asm, supplying_kws && unsafe { get_iseq_flags_accepts_no_kwarg(iseq) }, Counter::send_iseq_accepts_no_kwarg @@ -8249,12 +8268,13 @@ fn exit_if_supplying_kws_and_accept_no_kwargs(asm: &mut Assembler, supplying_kws } #[must_use] -fn exit_if_doing_kw_and_splat(asm: &mut Assembler, doing_kw_call: bool, flags: u32) -> Option<()> { - exit_if(asm, doing_kw_call && flags & VM_CALL_ARGS_SPLAT != 0, Counter::send_iseq_splat_with_kw) +fn exit_if_doing_kw_and_splat(jit: &JITState, asm: &mut Assembler, doing_kw_call: bool, flags: u32) -> Option<()> { + exit_if(jit, asm, doing_kw_call && flags & VM_CALL_ARGS_SPLAT != 0, Counter::send_iseq_splat_with_kw) } #[must_use] fn exit_if_wrong_number_arguments( + jit: &JITState, asm: &mut Assembler, args_setup_block: bool, opts_filled: i32, @@ -8267,20 +8287,21 @@ fn exit_if_wrong_number_arguments( // Too many arguments and no sink that take them let too_many = opts_filled > opt_num && !(iseq_has_rest || args_setup_block); - exit_if(asm, too_few || too_many, Counter::send_iseq_arity_error) + exit_if(jit, asm, too_few || too_many, Counter::send_iseq_arity_error) } #[must_use] -fn exit_if_doing_kw_and_opts_missing(asm: &mut Assembler, doing_kw_call: bool, opts_missing: i32) -> Option<()> { +fn exit_if_doing_kw_and_opts_missing(jit: &JITState, asm: &mut Assembler, doing_kw_call: bool, opts_missing: i32) -> Option<()> { // If we have unfilled optional arguments and keyword arguments then we // would need to adjust the arguments location to account for that. // For now we aren't handling this case. - exit_if(asm, doing_kw_call && opts_missing > 0, Counter::send_iseq_missing_optional_kw) + exit_if(jit, asm, doing_kw_call && opts_missing > 0, Counter::send_iseq_missing_optional_kw) } #[must_use] -fn exit_if_has_rest_and_optional_and_block(asm: &mut Assembler, iseq_has_rest: bool, opt_num: i32, iseq: *const rb_iseq_t, block_arg: bool) -> Option<()> { +fn exit_if_has_rest_and_optional_and_block(jit: &JITState, asm: &mut Assembler, iseq_has_rest: bool, opt_num: i32, iseq: *const rb_iseq_t, block_arg: bool) -> Option<()> { exit_if( + jit, asm, iseq_has_rest && opt_num != 0 && (unsafe { get_iseq_flags_has_block(iseq) } || block_arg), Counter::send_iseq_has_rest_opt_and_block @@ -8322,7 +8343,7 @@ fn exit_if_unsupported_block_arg_type( Some(Some(BlockArg::TProc)) } _ => { - gen_counter_incr(asm, Counter::send_iseq_block_arg_type); + gen_counter_incr(jit, asm, Counter::send_iseq_block_arg_type); None } } @@ -8374,7 +8395,7 @@ fn gen_struct_aref( if c_method_tracing_currently_enabled(jit) { // Struct accesses need fire c_call and c_return events, which we can't support // See :attr-tracing: - gen_counter_incr(asm, Counter::send_cfunc_tracing); + gen_counter_incr(jit, asm, Counter::send_cfunc_tracing); return None; } @@ -8424,7 +8445,7 @@ fn gen_struct_aset( if c_method_tracing_currently_enabled(jit) { // Struct accesses need fire c_call and c_return events, which we can't support // See :attr-tracing: - gen_counter_incr(asm, Counter::send_cfunc_tracing); + gen_counter_incr(jit, asm, Counter::send_cfunc_tracing); return None; } @@ -8489,7 +8510,7 @@ fn gen_send_dynamic<F: Fn(&mut Assembler) -> Opnd>( // Fix the interpreter SP deviated by vm_sendish asm.mov(Opnd::mem(64, CFP, RUBY_OFFSET_CFP_SP), SP); - gen_counter_incr(asm, Counter::num_send_dynamic); + gen_counter_incr(jit, asm, Counter::num_send_dynamic); jit_perf_symbol_pop!(jit, asm, PerfMap::Codegen); @@ -8529,7 +8550,7 @@ fn gen_send_general( // Dynamic stack layout. No good way to support without inlining. if ci_flags & VM_CALL_FORWARDING != 0 { - gen_counter_incr(asm, Counter::send_iseq_forwarding); + gen_counter_incr(jit, asm, Counter::send_iseq_forwarding); return None; } @@ -8546,7 +8567,7 @@ fn gen_send_general( && comptime_recv != unsafe { rb_vm_top_self() } && !unsafe { RB_TYPE_P(comptime_recv, RUBY_T_CLASS) } && !unsafe { RB_TYPE_P(comptime_recv, RUBY_T_MODULE) } { - gen_counter_incr(asm, Counter::send_singleton_class); + gen_counter_incr(jit, asm, Counter::send_singleton_class); return None; } @@ -8559,16 +8580,16 @@ fn gen_send_general( asm_comment!(asm, "call to {}", get_method_name(Some(comptime_recv_klass), mid)); // Gather some statistics about sends - gen_counter_incr(asm, Counter::num_send); + gen_counter_incr(jit, asm, Counter::num_send); if let Some(_known_klass) = asm.ctx.get_opnd_type(recv_opnd).known_class() { - gen_counter_incr(asm, Counter::num_send_known_class); + gen_counter_incr(jit, asm, Counter::num_send_known_class); } if asm.ctx.get_chain_depth() > 1 { - gen_counter_incr(asm, Counter::num_send_polymorphic); + gen_counter_incr(jit, asm, Counter::num_send_polymorphic); } // If megamorphic, let the caller fallback to dynamic dispatch if asm.ctx.get_chain_depth() >= SEND_MAX_DEPTH { - gen_counter_incr(asm, Counter::send_megamorphic); + gen_counter_incr(jit, asm, Counter::send_megamorphic); return None; } @@ -8586,7 +8607,7 @@ fn gen_send_general( // Do method lookup let mut cme = unsafe { rb_callable_method_entry(comptime_recv_klass, mid) }; if cme.is_null() { - gen_counter_incr(asm, Counter::send_cme_not_found); + gen_counter_incr(jit, asm, Counter::send_cme_not_found); return None; } @@ -8603,7 +8624,7 @@ fn gen_send_general( if flags & VM_CALL_FCALL == 0 { // Can only call private methods with FCALL callsites. // (at the moment they are callsites without a receiver or an explicit `self` receiver) - gen_counter_incr(asm, Counter::send_private_not_fcall); + gen_counter_incr(jit, asm, Counter::send_private_not_fcall); return None; } } @@ -8649,7 +8670,7 @@ fn gen_send_general( VM_METHOD_TYPE_IVAR => { // This is a .send call not supported right now for attr_reader if flags & VM_CALL_OPT_SEND != 0 { - gen_counter_incr(asm, Counter::send_send_attr_reader); + gen_counter_incr(jit, asm, Counter::send_send_attr_reader); return None; } @@ -8661,7 +8682,7 @@ fn gen_send_general( asm.stack_pop(1); } _ => { - gen_counter_incr(asm, Counter::send_getter_block_arg); + gen_counter_incr(jit, asm, Counter::send_getter_block_arg); return None; } } @@ -8681,7 +8702,7 @@ fn gen_send_general( asm.stack_pop(1); } else { // Argument count mismatch. Getters take no arguments. - gen_counter_incr(asm, Counter::send_getter_arity); + gen_counter_incr(jit, asm, Counter::send_getter_arity); return None; } } @@ -8694,7 +8715,7 @@ fn gen_send_general( // "method" we are calling into never enables those tracing // events. We are never inside the code that needs to be // invalidated when invalidation happens. - gen_counter_incr(asm, Counter::send_cfunc_tracing); + gen_counter_incr(jit, asm, Counter::send_cfunc_tracing); return None; } @@ -8714,26 +8735,26 @@ fn gen_send_general( VM_METHOD_TYPE_ATTRSET => { // This is a .send call not supported right now for attr_writer if flags & VM_CALL_OPT_SEND != 0 { - gen_counter_incr(asm, Counter::send_send_attr_writer); + gen_counter_incr(jit, asm, Counter::send_send_attr_writer); return None; } if flags & VM_CALL_ARGS_SPLAT != 0 { - gen_counter_incr(asm, Counter::send_args_splat_attrset); + gen_counter_incr(jit, asm, Counter::send_args_splat_attrset); return None; } if flags & VM_CALL_KWARG != 0 { - gen_counter_incr(asm, Counter::send_attrset_kwargs); + gen_counter_incr(jit, asm, Counter::send_attrset_kwargs); return None; } else if argc != 1 || unsafe { !RB_TYPE_P(comptime_recv, RUBY_T_OBJECT) } { - gen_counter_incr(asm, Counter::send_ivar_set_method); + gen_counter_incr(jit, asm, Counter::send_ivar_set_method); return None; } else if c_method_tracing_currently_enabled(jit) { // Can't generate code for firing c_call and c_return events // See :attr-tracing: - gen_counter_incr(asm, Counter::send_cfunc_tracing); + gen_counter_incr(jit, asm, Counter::send_cfunc_tracing); return None; } else if flags & VM_CALL_ARGS_BLOCKARG != 0 { - gen_counter_incr(asm, Counter::send_attrset_block_arg); + gen_counter_incr(jit, asm, Counter::send_attrset_block_arg); return None; } else { let ivar_name = unsafe { get_cme_def_body_attr_id(cme) }; @@ -8743,7 +8764,7 @@ fn gen_send_general( // Block method, e.g. define_method(:foo) { :my_block } VM_METHOD_TYPE_BMETHOD => { if flags & VM_CALL_ARGS_SPLAT != 0 { - gen_counter_incr(asm, Counter::send_args_splat_bmethod); + gen_counter_incr(jit, asm, Counter::send_args_splat_bmethod); return None; } return gen_send_bmethod(jit, asm, ci, cme, block, flags, argc); @@ -8756,7 +8777,7 @@ fn gen_send_general( // Send family of methods, e.g. call/apply VM_METHOD_TYPE_OPTIMIZED => { if flags & VM_CALL_ARGS_BLOCKARG != 0 { - gen_counter_incr(asm, Counter::send_optimized_block_arg); + gen_counter_incr(jit, asm, Counter::send_optimized_block_arg); return None; } @@ -8774,12 +8795,12 @@ fn gen_send_general( // currently work, we can't do stack manipulation until we will no longer // side exit. if flags & VM_CALL_OPT_SEND != 0 { - gen_counter_incr(asm, Counter::send_send_nested); + gen_counter_incr(jit, asm, Counter::send_send_nested); return None; } if argc == 0 { - gen_counter_incr(asm, Counter::send_send_wrong_args); + gen_counter_incr(jit, asm, Counter::send_send_wrong_args); return None; } @@ -8790,13 +8811,13 @@ fn gen_send_general( mid = unsafe { rb_get_symbol_id(compile_time_name) }; if mid == 0 { // This also rejects method names that need conversion - gen_counter_incr(asm, Counter::send_send_null_mid); + gen_counter_incr(jit, asm, Counter::send_send_null_mid); return None; } cme = unsafe { rb_callable_method_entry(comptime_recv_klass, mid) }; if cme.is_null() { - gen_counter_incr(asm, Counter::send_send_null_cme); + gen_counter_incr(jit, asm, Counter::send_send_null_cme); return None; } @@ -8830,24 +8851,24 @@ fn gen_send_general( OPTIMIZED_METHOD_TYPE_CALL => { if block.is_some() { - gen_counter_incr(asm, Counter::send_call_block); + gen_counter_incr(jit, asm, Counter::send_call_block); return None; } if flags & VM_CALL_KWARG != 0 { - gen_counter_incr(asm, Counter::send_call_kwarg); + gen_counter_incr(jit, asm, Counter::send_call_kwarg); return None; } if flags & VM_CALL_ARGS_SPLAT != 0 { - gen_counter_incr(asm, Counter::send_args_splat_opt_call); + gen_counter_incr(jit, asm, Counter::send_args_splat_opt_call); return None; } // Optimize for single ractor mode and avoid runtime check for // "defined with an un-shareable Proc in a different Ractor" if !assume_single_ractor_mode(jit, asm) { - gen_counter_incr(asm, Counter::send_call_multi_ractor); + gen_counter_incr(jit, asm, Counter::send_call_multi_ractor); return None; } @@ -8884,12 +8905,12 @@ fn gen_send_general( } OPTIMIZED_METHOD_TYPE_BLOCK_CALL => { - gen_counter_incr(asm, Counter::send_optimized_method_block_call); + gen_counter_incr(jit, asm, Counter::send_optimized_method_block_call); return None; } OPTIMIZED_METHOD_TYPE_STRUCT_AREF => { if flags & VM_CALL_ARGS_SPLAT != 0 { - gen_counter_incr(asm, Counter::send_args_splat_aref); + gen_counter_incr(jit, asm, Counter::send_args_splat_aref); return None; } return gen_struct_aref( @@ -8904,7 +8925,7 @@ fn gen_send_general( } OPTIMIZED_METHOD_TYPE_STRUCT_ASET => { if flags & VM_CALL_ARGS_SPLAT != 0 { - gen_counter_incr(asm, Counter::send_args_splat_aset); + gen_counter_incr(jit, asm, Counter::send_args_splat_aset); return None; } return gen_struct_aset( @@ -8923,23 +8944,23 @@ fn gen_send_general( } } VM_METHOD_TYPE_ZSUPER => { - gen_counter_incr(asm, Counter::send_zsuper_method); + gen_counter_incr(jit, asm, Counter::send_zsuper_method); return None; } VM_METHOD_TYPE_UNDEF => { - gen_counter_incr(asm, Counter::send_undef_method); + gen_counter_incr(jit, asm, Counter::send_undef_method); return None; } VM_METHOD_TYPE_NOTIMPLEMENTED => { - gen_counter_incr(asm, Counter::send_not_implemented_method); + gen_counter_incr(jit, asm, Counter::send_not_implemented_method); return None; } VM_METHOD_TYPE_MISSING => { - gen_counter_incr(asm, Counter::send_missing_method); + gen_counter_incr(jit, asm, Counter::send_missing_method); return None; } VM_METHOD_TYPE_REFINED => { - gen_counter_incr(asm, Counter::send_refined_method); + gen_counter_incr(jit, asm, Counter::send_refined_method); return None; } _ => { @@ -9088,7 +9109,7 @@ fn gen_invokeblock_specialized( // Fallback to dynamic dispatch if this callsite is megamorphic if asm.ctx.get_chain_depth() >= SEND_MAX_DEPTH { - gen_counter_incr(asm, Counter::invokeblock_megamorphic); + gen_counter_incr(jit, asm, Counter::invokeblock_megamorphic); return None; } @@ -9104,7 +9125,7 @@ fn gen_invokeblock_specialized( // Handle each block_handler type if comptime_handler.0 == VM_BLOCK_HANDLER_NONE as usize { // no block given - gen_counter_incr(asm, Counter::invokeblock_none); + gen_counter_incr(jit, asm, Counter::invokeblock_none); None } else if comptime_handler.0 & 0x3 == 0x1 { // VM_BH_ISEQ_BLOCK_P asm_comment!(asm, "get local EP"); @@ -9127,7 +9148,7 @@ fn gen_invokeblock_specialized( // If the current ISEQ is annotated to be inlined but it's not being inlined here, // generate a dynamic dispatch to avoid making this yield megamorphic. if unsafe { rb_yjit_iseq_builtin_attrs(jit.iseq) } & BUILTIN_ATTR_INLINE_BLOCK != 0 && !asm.ctx.inline() { - gen_counter_incr(asm, Counter::invokeblock_iseq_not_inlined); + gen_counter_incr(jit, asm, Counter::invokeblock_iseq_not_inlined); return None; } @@ -9150,11 +9171,11 @@ fn gen_invokeblock_specialized( } else if comptime_handler.0 & 0x3 == 0x3 { // VM_BH_IFUNC_P // We aren't handling CALLER_SETUP_ARG and CALLER_REMOVE_EMPTY_KW_SPLAT yet. if flags & VM_CALL_ARGS_SPLAT != 0 { - gen_counter_incr(asm, Counter::invokeblock_ifunc_args_splat); + gen_counter_incr(jit, asm, Counter::invokeblock_ifunc_args_splat); return None; } if flags & VM_CALL_KW_SPLAT != 0 { - gen_counter_incr(asm, Counter::invokeblock_ifunc_kw_splat); + gen_counter_incr(jit, asm, Counter::invokeblock_ifunc_kw_splat); return None; } @@ -9200,10 +9221,10 @@ fn gen_invokeblock_specialized( jump_to_next_insn(jit, asm); Some(EndBlock) } else if comptime_handler.symbol_p() { - gen_counter_incr(asm, Counter::invokeblock_symbol); + gen_counter_incr(jit, asm, Counter::invokeblock_symbol); None } else { // Proc - gen_counter_incr(asm, Counter::invokeblock_proc); + gen_counter_incr(jit, asm, Counter::invokeblock_proc); None } } @@ -9258,13 +9279,13 @@ fn gen_invokesuper_specialized( // Fallback to dynamic dispatch if this callsite is megamorphic if asm.ctx.get_chain_depth() >= SEND_MAX_DEPTH { - gen_counter_incr(asm, Counter::invokesuper_megamorphic); + gen_counter_incr(jit, asm, Counter::invokesuper_megamorphic); return None; } let me = unsafe { rb_vm_frame_method_entry(jit.get_cfp()) }; if me.is_null() { - gen_counter_incr(asm, Counter::invokesuper_no_me); + gen_counter_incr(jit, asm, Counter::invokesuper_no_me); return None; } @@ -9277,7 +9298,7 @@ fn gen_invokesuper_specialized( if current_defined_class.builtin_type() == RUBY_T_ICLASS && unsafe { RB_TYPE_P((*rbasic_ptr).klass, RUBY_T_MODULE) && FL_TEST_RAW((*rbasic_ptr).klass, VALUE(RMODULE_IS_REFINEMENT.as_usize())) != VALUE(0) } { - gen_counter_incr(asm, Counter::invokesuper_refinement); + gen_counter_incr(jit, asm, Counter::invokesuper_refinement); return None; } let comptime_superclass = @@ -9292,15 +9313,15 @@ fn gen_invokesuper_specialized( // Note, not using VM_CALL_ARGS_SIMPLE because sometimes we pass a block. if ci_flags & VM_CALL_KWARG != 0 { - gen_counter_incr(asm, Counter::invokesuper_kwarg); + gen_counter_incr(jit, asm, Counter::invokesuper_kwarg); return None; } if ci_flags & VM_CALL_KW_SPLAT != 0 { - gen_counter_incr(asm, Counter::invokesuper_kw_splat); + gen_counter_incr(jit, asm, Counter::invokesuper_kw_splat); return None; } if ci_flags & VM_CALL_FORWARDING != 0 { - gen_counter_incr(asm, Counter::invokesuper_forwarding); + gen_counter_incr(jit, asm, Counter::invokesuper_forwarding); return None; } @@ -9311,20 +9332,20 @@ fn gen_invokesuper_specialized( // check and side exit. let comptime_recv = jit.peek_at_stack(&asm.ctx, argc as isize); if unsafe { rb_obj_is_kind_of(comptime_recv, current_defined_class) } == VALUE(0) { - gen_counter_incr(asm, Counter::invokesuper_defined_class_mismatch); + gen_counter_incr(jit, asm, Counter::invokesuper_defined_class_mismatch); return None; } // Don't compile `super` on objects with singleton class to avoid retaining the receiver. if VALUE(0) != unsafe { FL_TEST(comptime_recv.class_of(), VALUE(RUBY_FL_SINGLETON as usize)) } { - gen_counter_incr(asm, Counter::invokesuper_singleton_class); + gen_counter_incr(jit, asm, Counter::invokesuper_singleton_class); return None; } // Do method lookup let cme = unsafe { rb_callable_method_entry(comptime_superclass, mid) }; if cme.is_null() { - gen_counter_incr(asm, Counter::invokesuper_no_cme); + gen_counter_incr(jit, asm, Counter::invokesuper_no_cme); return None; } @@ -9332,7 +9353,7 @@ fn gen_invokesuper_specialized( let cme_def_type = unsafe { get_cme_def_type(cme) }; if cme_def_type != VM_METHOD_TYPE_ISEQ && cme_def_type != VM_METHOD_TYPE_CFUNC { // others unimplemented - gen_counter_incr(asm, Counter::invokesuper_not_iseq_or_cfunc); + gen_counter_incr(jit, asm, Counter::invokesuper_not_iseq_or_cfunc); return None; } @@ -9799,7 +9820,7 @@ fn gen_opt_getconstant_path( } else { // Optimize for single ractor mode. if !assume_single_ractor_mode(jit, asm) { - gen_counter_incr(asm, Counter::opt_getconstant_path_multi_ractor); + gen_counter_incr(jit, asm, Counter::opt_getconstant_path_multi_ractor); return None; } @@ -9839,7 +9860,7 @@ fn gen_getblockparamproxy( unsafe { rb_obj_is_proc(comptime_handler) }.test() // block is a Proc ) { // Missing the symbol case, where we basically need to call Symbol#to_proc at runtime - gen_counter_incr(asm, Counter::gbpp_unsupported_type); + gen_counter_incr(jit, asm, Counter::gbpp_unsupported_type); return None; } diff --git a/yjit/src/options.rs b/yjit/src/options.rs index 3882c8a786..85d068595a 100644 --- a/yjit/src/options.rs +++ b/yjit/src/options.rs @@ -116,8 +116,8 @@ static YJIT_OPTIONS: [(&str, &str); 9] = [ pub enum TraceExits { // Trace all exits All, - // Trace a specific counted exit - CountedExit(Counter), + // Trace a specific counter + Counter(Counter), } #[derive(Debug)] @@ -293,7 +293,7 @@ pub fn parse_option(str_ptr: *const std::os::raw::c_char) -> Option<()> { OPTIONS.trace_exits = match opt_val { "" => Some(TraceExits::All), name => match Counter::get(name) { - Some(counter) => Some(TraceExits::CountedExit(counter)), + Some(counter) => Some(TraceExits::Counter(counter)), None => return None, }, }; |