summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bootstraptest/test_yjit.rb20
-rw-r--r--vm_trace.c15
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.