diff options
-rw-r--r-- | bootstraptest/test_yjit.rb | 20 | ||||
-rw-r--r-- | vm_trace.c | 15 |
2 files changed, 29 insertions, 6 deletions
diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb index 7361d2a725..c5bb681e84 100644 --- a/bootstraptest/test_yjit.rb +++ b/bootstraptest/test_yjit.rb @@ -2249,6 +2249,26 @@ assert_equal '[[:c_return, :itself, main]]', %q{ events } +# test c_call invalidation +assert_equal '[[:c_call, :itself]]', %q{ + # enable the event once to make sure invalidation + # happens the second time we enable it + TracePoint.new(:c_call) {}.enable{} + + def compiled + itself + end + + # assume first call compiles + compiled + + events = [] + tp = TracePoint.new(:c_call) { |tp| events << [tp.event, tp.method_id] } + tp.enable { compiled } + + events +} + # test enabling tracing for a suspended fiber assert_equal '[[:return, 42]]', %q{ def traced_method diff --git a/vm_trace.c b/vm_trace.c index caed71e96f..0b9bd53ebe 100644 --- a/vm_trace.c +++ b/vm_trace.c @@ -87,9 +87,11 @@ update_global_event_hook(rb_event_flag_t prev_events, rb_event_flag_t new_events { rb_event_flag_t new_iseq_events = new_events & ISEQ_TRACE_EVENTS; rb_event_flag_t enabled_iseq_events = ruby_vm_event_enabled_global_flags & ISEQ_TRACE_EVENTS; - bool trace_iseq_p = new_iseq_events & ~enabled_iseq_events; + bool first_time_iseq_events_p = new_iseq_events & ~enabled_iseq_events; + bool enable_c_call = (prev_events & RUBY_EVENT_C_CALL) == 0 && (new_events & RUBY_EVENT_C_CALL); + bool enable_c_return = (prev_events & RUBY_EVENT_C_RETURN) == 0 && (new_events & RUBY_EVENT_C_RETURN); - if (trace_iseq_p) { + if (first_time_iseq_events_p) { // :class events are triggered only in ISEQ_TYPE_CLASS, but mjit_target_iseq_p ignores such iseqs. // Thus we don't need to cancel JIT-ed code for :class events. if (new_iseq_events != RUBY_EVENT_CLASS) { @@ -97,13 +99,12 @@ update_global_event_hook(rb_event_flag_t prev_events, rb_event_flag_t new_events mjit_cancel_all("TracePoint is enabled"); } - /* write all ISeqs if and only if new events are added */ + // write all ISeqs only when new events are added for the first time rb_iseq_trace_set_all(new_iseq_events | enabled_iseq_events); } else { // if c_call or c_return is activated: - if (((prev_events & RUBY_EVENT_C_CALL) == 0 && (new_events & RUBY_EVENT_C_CALL)) || - ((prev_events & RUBY_EVENT_C_RETURN) == 0 && (new_events & RUBY_EVENT_C_RETURN))) { + if (enable_c_call || enable_c_return) { rb_clear_attr_ccs(); } } @@ -112,8 +113,10 @@ update_global_event_hook(rb_event_flag_t prev_events, rb_event_flag_t new_events ruby_vm_event_enabled_global_flags |= new_events; rb_objspace_set_event_hook(new_events); - if (trace_iseq_p) { + if (first_time_iseq_events_p || enable_c_call || enable_c_return) { // Invalidate all code when ISEQs are modified to use trace_* insns above. + // Also invalidate when enabling c_call or c_return because generated code + // never fires these events. // Internal events fire inside C routines so don't need special handling. // Do this after event flags updates so other ractors see updated vm events // when they wake up. |