Ruby 4.1.0dev (2026-05-17 revision 71749b882622c03028dfc55f40e5c3cceb24eaaf)
zjit.h (71749b882622c03028dfc55f40e5c3cceb24eaaf)
1#ifndef ZJIT_H
2#define ZJIT_H 1
3//
4// This file contains definitions ZJIT exposes to the CRuby codebase
5//
6
7// ZJIT_STATS controls whether to support runtime counters in the interpreter
8#ifndef ZJIT_STATS
9# define ZJIT_STATS (USE_ZJIT && RUBY_DEBUG)
10#endif
11
12// JITFrame is defined here as the single source of truth and imported into
13// Rust via bindgen. C code reads fields directly; Rust uses an impl block.
14typedef struct zjit_jit_frame {
15 // Program counter for this frame, used for backtraces and GC.
16 // NULL for C frames (they don't have a Ruby PC).
17 const VALUE *pc;
18 // The ISEQ this frame belongs to. Marked via rb_execution_context_mark.
19 // NULL for C frames.
20 const rb_iseq_t *iseq;
21 // Whether to materialize block_code when this frame is materialized.
22 // True when the ISEQ doesn't contain send/invokesuper/invokeblock
23 // (which write block_code themselves), so we must restore it.
24 // Always false for C frames.
25 bool materialize_block_code;
27
28#if USE_ZJIT
29extern void *rb_zjit_entry;
30extern const zjit_jit_frame_t rb_zjit_c_frame;
31extern uint64_t rb_zjit_call_threshold;
32extern uint64_t rb_zjit_profile_threshold;
33void rb_zjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit_exception);
34void rb_zjit_profile_insn(uint32_t insn, rb_execution_context_t *ec);
35void rb_zjit_profile_enable(const rb_iseq_t *iseq);
36void rb_zjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop);
37void rb_zjit_cme_invalidate(const rb_callable_method_entry_t *cme);
38void rb_zjit_cme_free(const rb_callable_method_entry_t *cme);
39void rb_zjit_klass_free(VALUE klass);
40void rb_zjit_invalidate_no_ep_escape(const rb_iseq_t *iseq);
41void rb_zjit_constant_state_changed(ID id);
42void rb_zjit_iseq_mark(void *payload);
43void rb_zjit_iseq_update_references(void *payload);
44void rb_zjit_mark_all_writable(void);
45void rb_zjit_mark_all_executable(void);
46void rb_zjit_iseq_free(const rb_iseq_t *iseq);
47void rb_zjit_before_ractor_spawn(void);
48void rb_zjit_tracing_invalidate_all(void);
49void rb_zjit_invalidate_no_singleton_class(VALUE klass);
50void rb_zjit_invalidate_root_box(void);
51void rb_zjit_jit_frame_update_references(zjit_jit_frame_t *jit_frame);
52
53// Special value for cfp->jit_return that means "this is a C method frame, use
54// rb_zjit_c_frame as the JITFrame". We don't control the native stack layout
55// for C frames, so there's no per-call JITFrame storage; we set this sentinel
56// instead of a heap-allocated JITFrame pointer.
57#define ZJIT_JIT_RETURN_C_FRAME 0x1
58
59static inline const zjit_jit_frame_t *
60CFP_ZJIT_FRAME(const rb_control_frame_t *cfp)
61{
62 if ((VALUE)cfp->jit_return == ZJIT_JIT_RETURN_C_FRAME) {
63 return &rb_zjit_c_frame;
64 }
65 return (const zjit_jit_frame_t *)cfp->jit_return;
66}
67#else
68#define rb_zjit_entry 0
69static inline void rb_zjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit_exception) {}
70static inline void rb_zjit_profile_insn(uint32_t insn, rb_execution_context_t *ec) {}
71static inline void rb_zjit_profile_enable(const rb_iseq_t *iseq) {}
72static inline void rb_zjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop) {}
73static inline void rb_zjit_cme_invalidate(const rb_callable_method_entry_t *cme) {}
74static inline void rb_zjit_invalidate_no_ep_escape(const rb_iseq_t *iseq) {}
75static inline void rb_zjit_constant_state_changed(ID id) {}
76static inline void rb_zjit_before_ractor_spawn(void) {}
77static inline void rb_zjit_tracing_invalidate_all(void) {}
78static inline void rb_zjit_invalidate_no_singleton_class(VALUE klass) {}
79static inline void rb_zjit_invalidate_root_box(void) {}
80static inline void rb_zjit_jit_frame_update_references(zjit_jit_frame_t *jit_frame) {}
81static inline const zjit_jit_frame_t *CFP_ZJIT_FRAME(const rb_control_frame_t *cfp) { return NULL; }
82#endif // #if USE_ZJIT
83
84#define rb_zjit_enabled_p (rb_zjit_entry != 0)
85
86// BADFrame. The high bit is set, so likely SEGV on linux and darwin if dereferenced.
87#define ZJIT_JIT_RETURN_POISON 0xbadfbadfbadfbadfULL
88
89// Return true if a given CFP has ZJIT's JITFrame.
90static inline bool
91CFP_ZJIT_FRAME_P(const rb_control_frame_t *cfp)
92{
93 if (!rb_zjit_enabled_p) return false;
94#if USE_ZJIT
95 RUBY_ASSERT((unsigned long long)cfp->jit_return != ZJIT_JIT_RETURN_POISON);
96#endif
97 return cfp->jit_return != NULL;
98}
99
100static inline const VALUE*
101CFP_PC(const rb_control_frame_t *cfp)
102{
103 if (CFP_ZJIT_FRAME_P(cfp)) {
104 return CFP_ZJIT_FRAME(cfp)->pc;
105 }
106 return cfp->pc;
107}
108
109static inline const rb_iseq_t*
110CFP_ISEQ(const rb_control_frame_t *cfp)
111{
112 if (CFP_ZJIT_FRAME_P(cfp)) {
113 return CFP_ZJIT_FRAME(cfp)->iseq;
114 }
115 return cfp->_iseq;
116}
117
118#endif // #ifndef ZJIT_H
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
Definition method.h:63
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40