diff --git a/lib/ruby_vm/rjit/insn_compiler.rb b/lib/ruby_vm/rjit/insn_compiler.rb index 83a3cf038928d8..ce3e8531a20958 100644 --- a/lib/ruby_vm/rjit/insn_compiler.rb +++ b/lib/ruby_vm/rjit/insn_compiler.rb @@ -18,7 +18,7 @@ def compile(jit, ctx, asm, insn) asm.incr_counter(:rjit_insns_count) asm.comment("Insn: #{insn.name}") - # 73/102 + # 74/102 case insn.name when :nop then nop(jit, ctx, asm) when :getlocal then getlocal(jit, ctx, asm) @@ -80,7 +80,7 @@ def compile(jit, ctx, asm, insn) # opt_newarray_max when :opt_newarray_min then opt_newarray_min(jit, ctx, asm) when :invokesuper then invokesuper(jit, ctx, asm) - # invokeblock + when :invokeblock then invokeblock(jit, ctx, asm) when :leave then leave(jit, ctx, asm) # throw when :jump then jump(jit, ctx, asm) @@ -1242,7 +1242,44 @@ def invokesuper(jit, ctx, asm) jit_call_general(jit, ctx, asm, mid, argc, flags, cme, block_handler, nil) end - # invokeblock + # @param jit [RubyVM::RJIT::JITState] + # @param ctx [RubyVM::RJIT::Context] + # @param asm [RubyVM::RJIT::Assembler] + def invokeblock(jit, ctx, asm) + unless jit.at_current_insn? + defer_compilation(jit, ctx, asm) + return EndBlock + end + + # Get call info + cd = C.rb_call_data.new(jit.operand(0)) + ci = cd.ci + argc = C.vm_ci_argc(ci) + flags = C.vm_ci_flag(ci) + + # Get block_handler + cfp = jit.cfp + lep = C.rb_vm_ep_local_ep(cfp.ep) + comptime_handler = lep[C::VM_ENV_DATA_INDEX_SPECVAL] + + # Handle each block_handler type + if comptime_handler == C::VM_BLOCK_HANDLER_NONE # no block given + asm.incr_counter(:invokeblock_none) + CantCompile + elsif comptime_handler & 0x3 == 0x1 # VM_BH_ISEQ_BLOCK_P + asm.incr_counter(:invokeblock_iseq) + CantCompile + elsif comptime_handler & 0x3 == 0x3 # VM_BH_IFUNC_P + asm.incr_counter(:invokeblock_ifunc) + CantCompile + elsif symbol?(comptime_handler) + asm.incr_counter(:invokeblock_symbol) + CantCompile + else # Proc + asm.incr_counter(:invokeblock_proc) + CantCompile + end + end # @param jit [RubyVM::RJIT::JITState] # @param ctx [RubyVM::RJIT::Context] @@ -3924,10 +3961,19 @@ def flonum?(obj) (C.to_value(obj) & C::RUBY_FLONUM_MASK) == C::RUBY_FLONUM_FLAG end + def symbol?(obj) + static_symbol?(obj) || dynamic_symbol?(obj) + end + def static_symbol?(obj) (C.to_value(obj) & 0xff) == C::RUBY_SYMBOL_FLAG end + def dynamic_symbol?(obj) + return false if C::SPECIAL_CONST_P(obj) + C::RB_TYPE_P(obj, C::RUBY_T_SYMBOL) + end + def shape_too_complex?(obj) C.rb_shape_get_shape_id(obj) == C::OBJ_TOO_COMPLEX_SHAPE_ID end diff --git a/lib/ruby_vm/rjit/stats.rb b/lib/ruby_vm/rjit/stats.rb index 2fde44bc8e443d..65bb962aac094e 100644 --- a/lib/ruby_vm/rjit/stats.rb +++ b/lib/ruby_vm/rjit/stats.rb @@ -36,6 +36,7 @@ def print_stats $stderr.puts("***RJIT: Printing RJIT statistics on exit***") print_counters(stats, prefix: 'send_', prompt: 'method call exit reasons') + print_counters(stats, prefix: 'invokeblock_', prompt: 'invokeblock exit reasons') print_counters(stats, prefix: 'invokesuper_', prompt: 'invokesuper exit reasons') print_counters(stats, prefix: 'getblockpp_', prompt: 'getblockparamproxy exit reasons') print_counters(stats, prefix: 'getivar_', prompt: 'getinstancevariable exit reasons') diff --git a/rjit_c.h b/rjit_c.h index 243e7da637496a..7190e6701ab934 100644 --- a/rjit_c.h +++ b/rjit_c.h @@ -81,6 +81,12 @@ RJIT_RUNTIME_COUNTERS( invokesuper_me_changed, invokesuper_same_me, + invokeblock_none, + invokeblock_iseq, + invokeblock_ifunc, + invokeblock_symbol, + invokeblock_proc, + getivar_megamorphic, getivar_not_heap, getivar_special_const, diff --git a/rjit_c.rb b/rjit_c.rb index aeab210f70daf8..4cf7523c06c5fc 100644 --- a/rjit_c.rb +++ b/rjit_c.rb @@ -298,6 +298,12 @@ def rjit_exit_traces Primitive.cexpr! 'rjit_exit_traces()' end + def rb_vm_ep_local_ep(ep) + _ep = ep.to_i + lep_addr = Primitive.cexpr! 'SIZET2NUM((size_t)rb_vm_ep_local_ep((const VALUE *)NUM2SIZET(_ep)))' + C.VALUE.new(lep_addr) + end + # # Utilities: Not used by RJIT, but useful for debugging # @@ -364,6 +370,7 @@ def rb_iseqw_to_iseq(iseqw) C::RUBY_T_MASK = Primitive.cexpr! %q{ SIZET2NUM(RUBY_T_MASK) } C::RUBY_T_MODULE = Primitive.cexpr! %q{ SIZET2NUM(RUBY_T_MODULE) } C::RUBY_T_STRING = Primitive.cexpr! %q{ SIZET2NUM(RUBY_T_STRING) } + C::RUBY_T_SYMBOL = Primitive.cexpr! %q{ SIZET2NUM(RUBY_T_SYMBOL) } C::SHAPE_CAPACITY_CHANGE = Primitive.cexpr! %q{ SIZET2NUM(SHAPE_CAPACITY_CHANGE) } C::SHAPE_FLAG_SHIFT = Primitive.cexpr! %q{ SIZET2NUM(SHAPE_FLAG_SHIFT) } C::SHAPE_FROZEN = Primitive.cexpr! %q{ SIZET2NUM(SHAPE_FROZEN) } @@ -1144,6 +1151,11 @@ def C.rb_rjit_runtime_counters send_bmethod_blockarg: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_bmethod_blockarg)")], invokesuper_me_changed: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokesuper_me_changed)")], invokesuper_same_me: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokesuper_same_me)")], + invokeblock_none: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_none)")], + invokeblock_iseq: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_iseq)")], + invokeblock_ifunc: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_ifunc)")], + invokeblock_symbol: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_symbol)")], + invokeblock_proc: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_proc)")], getivar_megamorphic: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), getivar_megamorphic)")], getivar_not_heap: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), getivar_not_heap)")], getivar_special_const: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), getivar_special_const)")], diff --git a/tool/rjit/bindgen.rb b/tool/rjit/bindgen.rb index cb43e33b0b6f68..e201f3504e0fc0 100755 --- a/tool/rjit/bindgen.rb +++ b/tool/rjit/bindgen.rb @@ -415,6 +415,7 @@ def push_target(target) RUBY_T_MASK RUBY_T_MODULE RUBY_T_STRING + RUBY_T_SYMBOL SHAPE_CAPACITY_CHANGE SHAPE_FLAG_SHIFT SHAPE_FROZEN