Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

YJIT: Fix invalidation for c_call and c_return #6719

Merged
merged 1 commit into from Nov 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 20 additions & 0 deletions bootstraptest/test_yjit.rb
Expand Up @@ -2249,6 +2249,26 @@ def shouldnt_compile
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
Expand Down
15 changes: 9 additions & 6 deletions vm_trace.c
Expand Up @@ -87,23 +87,24 @@ 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) {
// Stop calling all JIT-ed code. We can't rewrite existing JIT-ed code to trace_ insns for now.
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();
}
}
Expand All @@ -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.
Expand Down