summaryrefslogtreecommitdiff
path: root/rjit.c
diff options
context:
space:
mode:
Diffstat (limited to 'rjit.c')
-rw-r--r--rjit.c88
1 files changed, 56 insertions, 32 deletions
diff --git a/rjit.c b/rjit.c
index 4ce6af4d4b..72660394b3 100644
--- a/rjit.c
+++ b/rjit.c
@@ -101,6 +101,9 @@ VALUE rb_rjit_raw_samples = 0;
// Line numbers for --rjit-trace-exits
VALUE rb_rjit_line_samples = 0;
+// Postponed job handle for triggering rjit_iseq_update_references
+static rb_postponed_job_handle_t rjit_iseq_update_references_pjob;
+
// A default threshold used to add iseq to JIT.
#define DEFAULT_CALL_THRESHOLD 10
// Size of executable memory block in MiB.
@@ -118,15 +121,21 @@ rb_rjit_setup_options(const char *s, struct rb_rjit_options *rjit_opt)
if (l == 0) {
return;
}
- else if (opt_match_arg(s, l, "call-threshold")) {
- rjit_opt->call_threshold = atoi(s + 1);
- }
else if (opt_match_arg(s, l, "exec-mem-size")) {
rjit_opt->exec_mem_size = atoi(s + 1);
}
+ else if (opt_match_arg(s, l, "call-threshold")) {
+ rjit_opt->call_threshold = atoi(s + 1);
+ }
else if (opt_match_noarg(s, l, "stats")) {
rjit_opt->stats = true;
}
+ else if (opt_match_noarg(s, l, "disable")) {
+ rjit_opt->disable = true;
+ }
+ else if (opt_match_noarg(s, l, "trace")) {
+ rjit_opt->trace = true;
+ }
else if (opt_match_noarg(s, l, "trace-exits")) {
rjit_opt->trace_exits = true;
}
@@ -136,24 +145,20 @@ rb_rjit_setup_options(const char *s, struct rb_rjit_options *rjit_opt)
else if (opt_match_noarg(s, l, "verify-ctx")) {
rjit_opt->verify_ctx = true;
}
- // --rjit=pause is an undocumented feature for experiments
- else if (opt_match_noarg(s, l, "pause")) {
- rjit_opt->pause = true;
- }
else {
rb_raise(rb_eRuntimeError,
- "invalid RJIT option `%s' (--help will show valid RJIT options)", s);
+ "invalid RJIT option '%s' (--help will show valid RJIT options)", s);
}
}
#define M(shortopt, longopt, desc) RUBY_OPT_MESSAGE(shortopt, longopt, desc)
const struct ruby_opt_message rb_rjit_option_messages[] = {
- M("--rjit-stats", "", "Enable collecting RJIT statistics"),
-#if RJIT_STATS
- M("--rjit-trace-exits", "", "Trace side exit locations"),
-#endif
- M("--rjit-exec-mem-size=num", "", "Size of executable memory block in MiB (default: " STRINGIZE(DEFAULT_EXEC_MEM_SIZE) ")"),
- M("--rjit-call-threshold=num", "", "Number of calls to trigger JIT (default: " STRINGIZE(DEFAULT_CALL_THRESHOLD) ")"),
+ M("--rjit-exec-mem-size=num", "", "Size of executable memory block in MiB (default: " STRINGIZE(DEFAULT_EXEC_MEM_SIZE) ")."),
+ M("--rjit-call-threshold=num", "", "Number of calls to trigger JIT (default: " STRINGIZE(DEFAULT_CALL_THRESHOLD) ")."),
+ M("--rjit-stats", "", "Enable collecting RJIT statistics."),
+ M("--rjit-disable", "", "Disable RJIT for lazily enabling it with RubyVM::RJIT.enable."),
+ M("--rjit-trace", "", "Allow TracePoint during JIT compilation."),
+ M("--rjit-trace-exits", "", "Trace side exit locations."),
#ifdef HAVE_LIBCAPSTONE
M("--rjit-dump-disasm", "", "Dump all JIT code"),
#endif
@@ -163,32 +168,47 @@ const struct ruby_opt_message rb_rjit_option_messages[] = {
struct rb_rjit_runtime_counters rb_rjit_counters = { 0 };
-#if RJIT_STATS
-void
-rb_rjit_collect_vm_usage_insn(int insn)
-{
- if (!rjit_stats_p) return;
- rb_rjit_counters.vm_insns_count++;
-}
-#endif // YJIT_STATS
-
extern VALUE rb_gc_enable(void);
extern VALUE rb_gc_disable(void);
+extern uint64_t rb_vm_insns_count;
-#define WITH_RJIT_ISOLATED(stmt) do { \
+// Disable GC, TracePoint, JIT, stats, and $!
+#define WITH_RJIT_ISOLATED_USING_PC(using_pc, stmt) do { \
VALUE was_disabled = rb_gc_disable(); \
+ \
rb_hook_list_t *global_hooks = rb_ec_ractor_hooks(GET_EC()); \
rb_rjit_global_events = global_hooks->events; \
- global_hooks->events = 0; \
+ \
+ const VALUE *pc = NULL; \
+ if (rb_rjit_opts.trace) { \
+ pc = GET_EC()->cfp->pc; \
+ if (!using_pc) GET_EC()->cfp->pc = 0; /* avoid crashing on calc_lineno */ \
+ } \
+ else global_hooks->events = 0; \
+ \
bool original_call_p = rb_rjit_call_p; \
- rjit_stats_p = false; \
rb_rjit_call_p = false; \
+ \
+ rjit_stats_p = false; \
+ uint64_t insns_count = rb_vm_insns_count; \
+ \
+ VALUE err = rb_errinfo(); \
+ \
stmt; \
- rb_rjit_call_p = (rjit_cancel_p ? false : original_call_p); \
+ \
+ rb_set_errinfo(err); \
+ \
+ rb_vm_insns_count = insns_count; \
rjit_stats_p = rb_rjit_opts.stats; \
- global_hooks->events = rb_rjit_global_events; \
+ \
+ rb_rjit_call_p = (rjit_cancel_p ? false : original_call_p); \
+ \
+ if (rb_rjit_opts.trace) GET_EC()->cfp->pc = pc; \
+ else global_hooks->events = rb_rjit_global_events; \
+ \
if (!was_disabled) rb_gc_enable(); \
} while (0);
+#define WITH_RJIT_ISOLATED(stmt) WITH_RJIT_ISOLATED_USING_PC(false, stmt)
void
rb_rjit_cancel_all(const char *reason)
@@ -301,7 +321,7 @@ rb_rjit_iseq_update_references(struct rb_iseq_constant_body *const body)
// Asynchronously hook the Ruby code to avoid allocation during GC.compact.
// Using _one because it's too slow to invalidate all for each ISEQ. Thus
// not giving an ISEQ pointer.
- rb_postponed_job_register_one(0, rjit_iseq_update_references, NULL);
+ rb_postponed_job_trigger(rjit_iseq_update_references_pjob);
}
void
@@ -354,7 +374,7 @@ rb_rjit_compile(const rb_iseq_t *iseq)
RB_VM_LOCK_ENTER();
rb_vm_barrier();
- WITH_RJIT_ISOLATED({
+ WITH_RJIT_ISOLATED_USING_PC(true, {
VALUE iseq_ptr = rb_funcall(rb_cRJITIseqPtr, rb_intern("new"), 1, SIZET2NUM((size_t)iseq));
VALUE cfp_ptr = rb_funcall(rb_cRJITCfpPtr, rb_intern("new"), 1, SIZET2NUM((size_t)GET_EC()->cfp));
rb_funcall(rb_RJITCompiler, rb_intern("compile"), 2, iseq_ptr, cfp_ptr);
@@ -373,7 +393,7 @@ rb_rjit_entry_stub_hit(VALUE branch_stub)
rb_control_frame_t *cfp = GET_EC()->cfp;
- WITH_RJIT_ISOLATED({
+ WITH_RJIT_ISOLATED_USING_PC(true, {
VALUE cfp_ptr = rb_funcall(rb_cRJITCfpPtr, rb_intern("new"), 1, SIZET2NUM((size_t)cfp));
result = rb_funcall(rb_RJITCompiler, rb_intern("entry_stub_hit"), 2, branch_stub, cfp_ptr);
});
@@ -429,6 +449,10 @@ rb_rjit_init(const struct rb_rjit_options *opts)
rb_rjit_enabled = false;
return;
}
+ rjit_iseq_update_references_pjob = rb_postponed_job_preregister(0, rjit_iseq_update_references, NULL);
+ if (rjit_iseq_update_references_pjob == POSTPONED_JOB_HANDLE_INVALID) {
+ rb_bug("Could not preregister postponed job for RJIT");
+ }
rb_mRJITC = rb_const_get(rb_mRJIT, rb_intern("C"));
VALUE rb_cRJITCompiler = rb_const_get(rb_mRJIT, rb_intern("Compiler"));
rb_RJITCompiler = rb_funcall(rb_cRJITCompiler, rb_intern("new"), 0);
@@ -441,7 +465,7 @@ rb_rjit_init(const struct rb_rjit_options *opts)
}
// Enable RJIT and stats from here
- rb_rjit_call_p = !rb_rjit_opts.pause;
+ rb_rjit_call_p = !rb_rjit_opts.disable;
rjit_stats_p = rb_rjit_opts.stats;
}