Skip to content

Commit 328ef59

Browse files
committed
ZJIT: Remove JITed code after TracePoint is enabled
1 parent f9bffff commit 328ef59

12 files changed

Lines changed: 135 additions & 52 deletions

File tree

jit.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,3 +492,54 @@ rb_jit_vm_unlock(unsigned int *recursive_lock_level, const char *file, int line)
492492
{
493493
rb_vm_lock_leave(recursive_lock_level, file, line);
494494
}
495+
496+
void
497+
rb_iseq_reset_jit_func(const rb_iseq_t *iseq)
498+
{
499+
RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(iseq, imemo_iseq));
500+
iseq->body->jit_entry = NULL;
501+
iseq->body->jit_exception = NULL;
502+
// Enable re-compiling this ISEQ. Event when it's invalidated for TracePoint,
503+
// we'd like to re-compile ISEQs that haven't been converted to trace_* insns.
504+
iseq->body->jit_entry_calls = 0;
505+
iseq->body->jit_exception_calls = 0;
506+
}
507+
508+
// Callback type for rb_jit_for_each_iseq
509+
typedef void (*rb_iseq_callback)(const rb_iseq_t *iseq, void *data);
510+
511+
// Callback data for rb_jit_for_each_iseq
512+
struct iseq_callback_data {
513+
rb_iseq_callback callback;
514+
void *data;
515+
};
516+
517+
// Heap-walking callback for rb_jit_for_each_iseq
518+
static int
519+
for_each_iseq_i(void *vstart, void *vend, size_t stride, void *data)
520+
{
521+
const struct iseq_callback_data *callback_data = (struct iseq_callback_data *)data;
522+
VALUE v = (VALUE)vstart;
523+
for (; v != (VALUE)vend; v += stride) {
524+
void *ptr = rb_asan_poisoned_object_p(v);
525+
rb_asan_unpoison_object(v, false);
526+
527+
if (rb_obj_is_iseq(v)) {
528+
rb_iseq_t *iseq = (rb_iseq_t *)v;
529+
callback_data->callback(iseq, callback_data->data);
530+
}
531+
532+
if (ptr) {
533+
rb_asan_poison_object(v);
534+
}
535+
}
536+
return 0;
537+
}
538+
539+
// Walk all ISEQs in the heap and invoke the callback - shared between YJIT and ZJIT
540+
void
541+
rb_jit_for_each_iseq(rb_iseq_callback callback, void *data)
542+
{
543+
struct iseq_callback_data callback_data = { .callback = callback, .data = data };
544+
rb_objspace_each_objects(for_each_iseq_i, (void *)&callback_data);
545+
}

test/ruby/test_zjit.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2148,6 +2148,44 @@ def test
21482148
}
21492149
end
21502150

2151+
def test_global_tracepoint
2152+
assert_compiles 'true', %q{
2153+
def foo = 1
2154+
2155+
foo
2156+
foo
2157+
2158+
called = false
2159+
2160+
tp = TracePoint.new(:return) { |event|
2161+
if event.method_id == :foo
2162+
called = true
2163+
end
2164+
}
2165+
tp.enable do
2166+
foo
2167+
end
2168+
called
2169+
}
2170+
end
2171+
2172+
def test_local_tracepoint
2173+
assert_compiles 'true', %q{
2174+
def foo = 1
2175+
2176+
foo
2177+
foo
2178+
2179+
called = false
2180+
2181+
tp = TracePoint.new(:return) { |_| called = true }
2182+
tp.enable(target: method(:foo)) do
2183+
foo
2184+
end
2185+
called
2186+
}
2187+
end
2188+
21512189
private
21522190

21532191
# Assert that every method call in `test_script` can be compiled by ZJIT

vm_trace.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "vm_core.h"
3636
#include "ruby/ractor.h"
3737
#include "yjit.h"
38+
#include "zjit.h"
3839

3940
#include "builtin.h"
4041

@@ -135,6 +136,7 @@ update_global_event_hook(rb_event_flag_t prev_events, rb_event_flag_t new_events
135136
// Do this after event flags updates so other ractors see updated vm events
136137
// when they wake up.
137138
rb_yjit_tracing_invalidate_all();
139+
rb_zjit_tracing_invalidate_all();
138140
}
139141
}
140142

@@ -1285,6 +1287,7 @@ rb_tracepoint_enable_for_target(VALUE tpval, VALUE target, VALUE target_line)
12851287
}
12861288

12871289
rb_yjit_tracing_invalidate_all();
1290+
rb_zjit_tracing_invalidate_all();
12881291

12891292
ruby_vm_event_local_num++;
12901293

yjit.c

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -413,18 +413,6 @@ rb_iseq_set_yjit_payload(const rb_iseq_t *iseq, void *payload)
413413
iseq->body->yjit_payload = payload;
414414
}
415415

416-
void
417-
rb_iseq_reset_jit_func(const rb_iseq_t *iseq)
418-
{
419-
RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(iseq, imemo_iseq));
420-
iseq->body->jit_entry = NULL;
421-
iseq->body->jit_exception = NULL;
422-
// Enable re-compiling this ISEQ. Event when it's invalidated for TracePoint,
423-
// we'd like to re-compile ISEQs that haven't been converted to trace_* insns.
424-
iseq->body->jit_entry_calls = 0;
425-
iseq->body->jit_exception_calls = 0;
426-
}
427-
428416
rb_proc_t *
429417
rb_yjit_get_proc_ptr(VALUE procv)
430418
{
@@ -643,41 +631,6 @@ rb_yjit_constcache_shareable(const struct iseq_inline_constant_cache_entry *ice)
643631
return (ice->flags & IMEMO_CONST_CACHE_SHAREABLE) != 0;
644632
}
645633

646-
// Used for passing a callback and other data over rb_objspace_each_objects
647-
struct iseq_callback_data {
648-
rb_iseq_callback callback;
649-
void *data;
650-
};
651-
652-
// Heap-walking callback for rb_yjit_for_each_iseq().
653-
static int
654-
for_each_iseq_i(void *vstart, void *vend, size_t stride, void *data)
655-
{
656-
const struct iseq_callback_data *callback_data = (struct iseq_callback_data *)data;
657-
VALUE v = (VALUE)vstart;
658-
for (; v != (VALUE)vend; v += stride) {
659-
void *ptr = rb_asan_poisoned_object_p(v);
660-
rb_asan_unpoison_object(v, false);
661-
662-
if (rb_obj_is_iseq(v)) {
663-
rb_iseq_t *iseq = (rb_iseq_t *)v;
664-
callback_data->callback(iseq, callback_data->data);
665-
}
666-
667-
asan_poison_object_if(ptr, v);
668-
}
669-
return 0;
670-
}
671-
672-
// Iterate through the whole GC heap and invoke a callback for each iseq.
673-
// Used for global code invalidation.
674-
void
675-
rb_yjit_for_each_iseq(rb_iseq_callback callback, void *data)
676-
{
677-
struct iseq_callback_data callback_data = { .callback = callback, .data = data };
678-
rb_objspace_each_objects(for_each_iseq_i, (void *)&callback_data);
679-
}
680-
681634
// For running write barriers from Rust. Required when we add a new edge in the
682635
// object graph from `old` to `young`.
683636
void

yjit/bindgen/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,6 @@ fn main() {
333333
.allowlist_function("rb_yjit_constcache_shareable")
334334
.allowlist_function("rb_iseq_reset_jit_func")
335335
.allowlist_function("rb_yjit_dump_iseq_loc")
336-
.allowlist_function("rb_yjit_for_each_iseq")
337336
.allowlist_function("rb_yjit_obj_written")
338337
.allowlist_function("rb_yjit_str_simple_append")
339338
.allowlist_function("rb_RSTRING_PTR")
@@ -355,6 +354,7 @@ fn main() {
355354
.allowlist_function("rb_jit_multi_ractor_p")
356355
.allowlist_function("rb_jit_vm_lock_then_barrier")
357356
.allowlist_function("rb_jit_vm_unlock")
357+
.allowlist_function("rb_jit_for_each_iseq")
358358
.allowlist_type("robject_offsets")
359359

360360
// from vm_sync.h

yjit/src/core.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1818,7 +1818,7 @@ pub fn for_each_iseq<F: FnMut(IseqPtr)>(mut callback: F) {
18181818
callback(iseq);
18191819
}
18201820
let mut data: &mut dyn FnMut(IseqPtr) = &mut callback;
1821-
unsafe { rb_yjit_for_each_iseq(Some(callback_wrapper), (&mut data) as *mut _ as *mut c_void) };
1821+
unsafe { rb_jit_for_each_iseq(Some(callback_wrapper), (&mut data) as *mut _ as *mut c_void) };
18221822
}
18231823

18241824
/// Iterate over all on-stack ISEQs

yjit/src/cruby_bindings.inc.rs

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

zjit.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ void rb_zjit_constant_state_changed(ID id);
2323
void rb_zjit_iseq_mark(void *payload);
2424
void rb_zjit_iseq_update_references(void *payload);
2525
void rb_zjit_before_ractor_spawn(void);
26+
void rb_zjit_tracing_invalidate_all(void);
2627
#else
2728
#define rb_zjit_enabled_p false
2829
static inline void rb_zjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit_exception) {}
@@ -33,6 +34,7 @@ static inline void rb_zjit_cme_invalidate(const rb_callable_method_entry_t *cme)
3334
static inline void rb_zjit_invalidate_ep_is_bp(const rb_iseq_t *iseq) {}
3435
static inline void rb_zjit_constant_state_changed(ID id) {}
3536
static inline void rb_zjit_before_ractor_spawn(void) {}
37+
static inline void rb_zjit_tracing_invalidate_all(void) {}
3638
#endif // #if USE_ZJIT
3739

3840
#endif // #ifndef ZJIT_H

zjit/bindgen/src/main.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,6 @@ fn main() {
349349
.allowlist_function("rb_full_cfunc_return")
350350
.allowlist_function("rb_assert_(iseq|cme)_handle")
351351
.allowlist_function("rb_IMEMO_TYPE_P")
352-
.allowlist_function("rb_iseq_reset_jit_func")
353352
.allowlist_function("rb_RSTRING_PTR")
354353
.allowlist_function("rb_RSTRING_LEN")
355354
.allowlist_function("rb_ENCODING_GET")
@@ -368,6 +367,8 @@ fn main() {
368367
.allowlist_function("rb_jit_multi_ractor_p")
369368
.allowlist_function("rb_jit_vm_lock_then_barrier")
370369
.allowlist_function("rb_jit_vm_unlock")
370+
.allowlist_function("rb_jit_for_each_iseq")
371+
.allowlist_function("rb_iseq_reset_jit_func")
371372
.allowlist_type("robject_offsets")
372373

373374
// from vm_sync.h

zjit/src/cruby_bindings.inc.rs

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)