Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions depend
Original file line number Diff line number Diff line change
Expand Up @@ -19732,6 +19732,7 @@ vm_trace.$(OBJEXT): {$(VPATH)}vm_opts.h
vm_trace.$(OBJEXT): {$(VPATH)}vm_sync.h
vm_trace.$(OBJEXT): {$(VPATH)}vm_trace.c
vm_trace.$(OBJEXT): {$(VPATH)}yjit.h
vm_trace.$(OBJEXT): {$(VPATH)}zjit.h
weakmap.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
weakmap.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
weakmap.$(OBJEXT): $(CCAN_DIR)/list/list.h
Expand Down
26 changes: 14 additions & 12 deletions ext/-test-/tracepoint/gc_hook.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "ruby/debug.h"

static int invoking; /* TODO: should not be global variable */
extern VALUE tp_mBug;

static VALUE
invoke_proc_ensure(VALUE _)
Expand All @@ -17,9 +18,9 @@ invoke_proc_begin(VALUE proc)
}

static void
invoke_proc(void *data)
invoke_proc(void *ivar_name)
{
VALUE proc = (VALUE)data;
VALUE proc = rb_ivar_get(tp_mBug, rb_intern(ivar_name));
invoking += 1;
rb_ensure(invoke_proc_begin, proc, invoke_proc_ensure, 0);
}
Expand All @@ -40,42 +41,43 @@ gc_start_end_i(VALUE tpval, void *data)
}

static VALUE
set_gc_hook(VALUE module, VALUE proc, rb_event_flag_t event, const char *tp_str, const char *proc_str)
set_gc_hook(VALUE proc, rb_event_flag_t event, const char *tp_str, const char *proc_str)
{
VALUE tpval;
ID tp_key = rb_intern(tp_str);

/* disable previous keys */
if (rb_ivar_defined(module, tp_key) != 0 &&
RTEST(tpval = rb_ivar_get(module, tp_key))) {
if (rb_ivar_defined(tp_mBug, tp_key) != 0 &&
RTEST(tpval = rb_ivar_get(tp_mBug, tp_key))) {
rb_tracepoint_disable(tpval);
rb_ivar_set(module, tp_key, Qnil);
rb_ivar_set(tp_mBug, tp_key, Qnil);
}

if (RTEST(proc)) {
if (!rb_obj_is_proc(proc)) {
rb_raise(rb_eTypeError, "trace_func needs to be Proc");
}

tpval = rb_tracepoint_new(0, event, gc_start_end_i, (void *)proc);
rb_ivar_set(module, tp_key, tpval);
rb_ivar_set(tp_mBug, rb_intern(proc_str), proc);
tpval = rb_tracepoint_new(0, event, gc_start_end_i, (void *)proc_str);
rb_ivar_set(tp_mBug, tp_key, tpval);
rb_tracepoint_enable(tpval);
}

return proc;
}

static VALUE
set_after_gc_start(VALUE module, VALUE proc)
set_after_gc_start(VALUE _self, VALUE proc)
{
return set_gc_hook(module, proc, RUBY_INTERNAL_EVENT_GC_START,
return set_gc_hook(proc, RUBY_INTERNAL_EVENT_GC_START,
"__set_after_gc_start_tpval__", "__set_after_gc_start_proc__");
}

static VALUE
start_after_gc_exit(VALUE module, VALUE proc)
start_after_gc_exit(VALUE _self, VALUE proc)
{
return set_gc_hook(module, proc, RUBY_INTERNAL_EVENT_GC_EXIT,
return set_gc_hook(proc, RUBY_INTERNAL_EVENT_GC_EXIT,
"__set_after_gc_exit_tpval__", "__set_after_gc_exit_proc__");
}

Expand Down
10 changes: 6 additions & 4 deletions ext/-test-/tracepoint/tracepoint.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "ruby/ruby.h"
#include "ruby/debug.h"

VALUE tp_mBug;

struct tracepoint_track {
size_t newobj_count;
size_t free_count;
Expand Down Expand Up @@ -89,8 +91,8 @@ void Init_gc_hook(VALUE);
void
Init_tracepoint(void)
{
VALUE mBug = rb_define_module("Bug");
Init_gc_hook(mBug);
rb_define_module_function(mBug, "tracepoint_track_objspace_events", tracepoint_track_objspace_events, 0);
rb_define_module_function(mBug, "tracepoint_specify_normal_and_internal_events", tracepoint_specify_normal_and_internal_events, 0);
tp_mBug = rb_define_module("Bug"); // GC root
Init_gc_hook(tp_mBug);
rb_define_module_function(tp_mBug, "tracepoint_track_objspace_events", tracepoint_track_objspace_events, 0);
rb_define_module_function(tp_mBug, "tracepoint_specify_normal_and_internal_events", tracepoint_specify_normal_and_internal_events, 0);
}
48 changes: 48 additions & 0 deletions jit.c
Original file line number Diff line number Diff line change
Expand Up @@ -492,3 +492,51 @@ rb_jit_vm_unlock(unsigned int *recursive_lock_level, const char *file, int line)
{
rb_vm_lock_leave(recursive_lock_level, file, line);
}

void
rb_iseq_reset_jit_func(const rb_iseq_t *iseq)
{
RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(iseq, imemo_iseq));
iseq->body->jit_entry = NULL;
iseq->body->jit_exception = NULL;
// Enable re-compiling this ISEQ. Event when it's invalidated for TracePoint,
// we'd like to re-compile ISEQs that haven't been converted to trace_* insns.
iseq->body->jit_entry_calls = 0;
iseq->body->jit_exception_calls = 0;
}

// Callback data for rb_jit_for_each_iseq
struct iseq_callback_data {
rb_iseq_callback callback;
void *data;
};

// Heap-walking callback for rb_jit_for_each_iseq
static int
for_each_iseq_i(void *vstart, void *vend, size_t stride, void *data)
{
const struct iseq_callback_data *callback_data = (struct iseq_callback_data *)data;
VALUE v = (VALUE)vstart;
for (; v != (VALUE)vend; v += stride) {
void *ptr = rb_asan_poisoned_object_p(v);
rb_asan_unpoison_object(v, false);

if (rb_obj_is_iseq(v)) {
rb_iseq_t *iseq = (rb_iseq_t *)v;
callback_data->callback(iseq, callback_data->data);
}

if (ptr) {
rb_asan_poison_object(v);
}
}
return 0;
}

// Walk all ISEQs in the heap and invoke the callback - shared between YJIT and ZJIT
void
rb_jit_for_each_iseq(rb_iseq_callback callback, void *data)
{
struct iseq_callback_data callback_data = { .callback = callback, .data = data };
rb_objspace_each_objects(for_each_iseq_i, (void *)&callback_data);
}
2 changes: 1 addition & 1 deletion test/-ext-/tracepoint/test_tracepoint.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def run(hook)
end

def test_teardown_with_active_GC_end_hook
assert_separately([], 'require("-test-/tracepoint"); Bug.after_gc_exit_hook = proc {}')
assert_separately([], 'require("-test-/tracepoint"); Bug.after_gc_exit_hook = proc {}; GC.start')
end

end
1 change: 0 additions & 1 deletion test/.excludes-zjit/ErrorHighlightTest.rb

This file was deleted.

2 changes: 0 additions & 2 deletions test/.excludes-zjit/TestObjSpace.rb

This file was deleted.

2 changes: 0 additions & 2 deletions test/.excludes-zjit/TestParse.rb

This file was deleted.

1 change: 0 additions & 1 deletion test/.excludes-zjit/TestRegexp.rb

This file was deleted.

3 changes: 0 additions & 3 deletions test/.excludes-zjit/TestTimeout.rb

This file was deleted.

2 changes: 1 addition & 1 deletion test/io/wait/test_io_wait.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def test_wait_readable_eof
ret = nil
assert_nothing_raised(Timeout::Error) do
q.push(true)
t = EnvUtil.apply_timeout_scale(0.1)
t = EnvUtil.apply_timeout_scale(1)
Timeout.timeout(t) { ret = @r.wait_readable }
end
assert_equal @r, ret
Expand Down
2 changes: 1 addition & 1 deletion test/ruby/test_gc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,7 @@ def test_interrupt_in_finalizer
Signal.trap(:INT, 'DEFAULT')
pid = $$
Thread.start do
10.times {
1000.times {
sleep 0.1
Process.kill("INT", pid) rescue break
}
Expand Down
2 changes: 1 addition & 1 deletion test/ruby/test_settracefunc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2724,7 +2724,7 @@ def obj.example
end

def test_disable_local_tracepoint_in_trace
assert_normal_exit <<-EOS
assert_normal_exit(<<-EOS, timeout: 60)
def foo
trace = TracePoint.new(:b_return){|tp|
tp.disable
Expand Down
38 changes: 38 additions & 0 deletions test/ruby/test_zjit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2202,6 +2202,44 @@ def test
}
end

def test_global_tracepoint
assert_compiles 'true', %q{
def foo = 1

foo
foo

called = false

tp = TracePoint.new(:return) { |event|
if event.method_id == :foo
called = true
end
}
tp.enable do
foo
end
called
}
end

def test_local_tracepoint
assert_compiles 'true', %q{
def foo = 1

foo
foo

called = false

tp = TracePoint.new(:return) { |_| called = true }
tp.enable(target: method(:foo)) do
foo
end
called
}
end

private

# Assert that every method call in `test_script` can be compiled by ZJIT
Expand Down
3 changes: 3 additions & 0 deletions vm_trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "vm_core.h"
#include "ruby/ractor.h"
#include "yjit.h"
#include "zjit.h"

#include "builtin.h"

Expand Down Expand Up @@ -135,6 +136,7 @@ update_global_event_hook(rb_event_flag_t prev_events, rb_event_flag_t new_events
// Do this after event flags updates so other ractors see updated vm events
// when they wake up.
rb_yjit_tracing_invalidate_all();
rb_zjit_tracing_invalidate_all();
}
}

Expand Down Expand Up @@ -1285,6 +1287,7 @@ rb_tracepoint_enable_for_target(VALUE tpval, VALUE target, VALUE target_line)
}

rb_yjit_tracing_invalidate_all();
rb_zjit_tracing_invalidate_all();

ruby_vm_event_local_num++;

Expand Down
47 changes: 0 additions & 47 deletions yjit.c
Original file line number Diff line number Diff line change
Expand Up @@ -413,18 +413,6 @@ rb_iseq_set_yjit_payload(const rb_iseq_t *iseq, void *payload)
iseq->body->yjit_payload = payload;
}

void
rb_iseq_reset_jit_func(const rb_iseq_t *iseq)
{
RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(iseq, imemo_iseq));
iseq->body->jit_entry = NULL;
iseq->body->jit_exception = NULL;
// Enable re-compiling this ISEQ. Event when it's invalidated for TracePoint,
// we'd like to re-compile ISEQs that haven't been converted to trace_* insns.
iseq->body->jit_entry_calls = 0;
iseq->body->jit_exception_calls = 0;
}

rb_proc_t *
rb_yjit_get_proc_ptr(VALUE procv)
{
Expand Down Expand Up @@ -643,41 +631,6 @@ rb_yjit_constcache_shareable(const struct iseq_inline_constant_cache_entry *ice)
return (ice->flags & IMEMO_CONST_CACHE_SHAREABLE) != 0;
}

// Used for passing a callback and other data over rb_objspace_each_objects
struct iseq_callback_data {
rb_iseq_callback callback;
void *data;
};

// Heap-walking callback for rb_yjit_for_each_iseq().
static int
for_each_iseq_i(void *vstart, void *vend, size_t stride, void *data)
{
const struct iseq_callback_data *callback_data = (struct iseq_callback_data *)data;
VALUE v = (VALUE)vstart;
for (; v != (VALUE)vend; v += stride) {
void *ptr = rb_asan_poisoned_object_p(v);
rb_asan_unpoison_object(v, false);

if (rb_obj_is_iseq(v)) {
rb_iseq_t *iseq = (rb_iseq_t *)v;
callback_data->callback(iseq, callback_data->data);
}

asan_poison_object_if(ptr, v);
}
return 0;
}

// Iterate through the whole GC heap and invoke a callback for each iseq.
// Used for global code invalidation.
void
rb_yjit_for_each_iseq(rb_iseq_callback callback, void *data)
{
struct iseq_callback_data callback_data = { .callback = callback, .data = data };
rb_objspace_each_objects(for_each_iseq_i, (void *)&callback_data);
}

// For running write barriers from Rust. Required when we add a new edge in the
// object graph from `old` to `young`.
void
Expand Down
2 changes: 1 addition & 1 deletion yjit/bindgen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,6 @@ fn main() {
.allowlist_function("rb_yjit_constcache_shareable")
.allowlist_function("rb_iseq_reset_jit_func")
.allowlist_function("rb_yjit_dump_iseq_loc")
.allowlist_function("rb_yjit_for_each_iseq")
.allowlist_function("rb_yjit_obj_written")
.allowlist_function("rb_yjit_str_simple_append")
.allowlist_function("rb_RSTRING_PTR")
Expand All @@ -355,6 +354,7 @@ fn main() {
.allowlist_function("rb_jit_multi_ractor_p")
.allowlist_function("rb_jit_vm_lock_then_barrier")
.allowlist_function("rb_jit_vm_unlock")
.allowlist_function("rb_jit_for_each_iseq")
.allowlist_type("robject_offsets")

// from vm_sync.h
Expand Down
2 changes: 1 addition & 1 deletion yjit/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1818,7 +1818,7 @@ pub fn for_each_iseq<F: FnMut(IseqPtr)>(mut callback: F) {
callback(iseq);
}
let mut data: &mut dyn FnMut(IseqPtr) = &mut callback;
unsafe { rb_yjit_for_each_iseq(Some(callback_wrapper), (&mut data) as *mut _ as *mut c_void) };
unsafe { rb_jit_for_each_iseq(Some(callback_wrapper), (&mut data) as *mut _ as *mut c_void) };
}

/// Iterate over all on-stack ISEQs
Expand Down
4 changes: 2 additions & 2 deletions yjit/src/cruby_bindings.inc.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions zjit.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ void rb_zjit_constant_state_changed(ID id);
void rb_zjit_iseq_mark(void *payload);
void rb_zjit_iseq_update_references(void *payload);
void rb_zjit_before_ractor_spawn(void);
void rb_zjit_tracing_invalidate_all(void);
#else
#define rb_zjit_enabled_p false
static inline void rb_zjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit_exception) {}
Expand All @@ -33,6 +34,7 @@ static inline void rb_zjit_cme_invalidate(const rb_callable_method_entry_t *cme)
static inline void rb_zjit_invalidate_ep_is_bp(const rb_iseq_t *iseq) {}
static inline void rb_zjit_constant_state_changed(ID id) {}
static inline void rb_zjit_before_ractor_spawn(void) {}
static inline void rb_zjit_tracing_invalidate_all(void) {}
#endif // #if USE_ZJIT

#endif // #ifndef ZJIT_H
Loading