diff options
Diffstat (limited to 'zjit.h')
| -rw-r--r-- | zjit.h | 89 |
1 files changed, 85 insertions, 4 deletions
@@ -9,8 +9,25 @@ # define ZJIT_STATS (USE_ZJIT && RUBY_DEBUG) #endif +// JITFrame is defined here as the single source of truth and imported into +// Rust via bindgen. C code reads fields directly; Rust uses an impl block. +typedef struct zjit_jit_frame { + // Program counter for this frame, used for backtraces and GC. + // NULL for C frames (they don't have a Ruby PC). + const VALUE *pc; + // The ISEQ this frame belongs to. Marked via rb_execution_context_mark. + // NULL for C frames. + const rb_iseq_t *iseq; + // Whether to materialize block_code when this frame is materialized. + // True when the ISEQ doesn't contain send/invokesuper/invokeblock + // (which write block_code themselves), so we must restore it. + // Always false for C frames. + bool materialize_block_code; +} zjit_jit_frame_t; + #if USE_ZJIT -extern bool rb_zjit_enabled_p; +extern void *rb_zjit_entry; +extern const zjit_jit_frame_t rb_zjit_c_frame; extern uint64_t rb_zjit_call_threshold; extern uint64_t rb_zjit_profile_threshold; void rb_zjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit_exception); @@ -18,21 +35,85 @@ void rb_zjit_profile_insn(uint32_t insn, rb_execution_context_t *ec); void rb_zjit_profile_enable(const rb_iseq_t *iseq); void rb_zjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop); void rb_zjit_cme_invalidate(const rb_callable_method_entry_t *cme); -void rb_zjit_invalidate_ep_is_bp(const rb_iseq_t *iseq); +void rb_zjit_cme_free(const rb_callable_method_entry_t *cme); +void rb_zjit_klass_free(VALUE klass); +void rb_zjit_invalidate_no_ep_escape(const rb_iseq_t *iseq); 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_mark_all_writable(void); +void rb_zjit_mark_all_executable(void); +void rb_zjit_iseq_free(const rb_iseq_t *iseq); void rb_zjit_before_ractor_spawn(void); +void rb_zjit_tracing_invalidate_all(void); +void rb_zjit_invalidate_no_singleton_class(VALUE klass); +void rb_zjit_invalidate_root_box(void); +void rb_zjit_jit_frame_update_references(zjit_jit_frame_t *jit_frame); +void rb_zjit_materialize_frames(const rb_execution_context_t *ec, rb_control_frame_t *cfp); + +// Special value for cfp->jit_return that means "this is a C method frame, use +// rb_zjit_c_frame as the JITFrame". We don't control the native stack layout +// for C frames, so there's no per-call JITFrame storage; we set this sentinel +// instead of a heap-allocated JITFrame pointer. +#define ZJIT_JIT_RETURN_C_FRAME 0x1 + +static inline const zjit_jit_frame_t * +CFP_ZJIT_FRAME(const rb_control_frame_t *cfp) +{ + if ((VALUE)cfp->jit_return == ZJIT_JIT_RETURN_C_FRAME) { + return &rb_zjit_c_frame; + } + else { + // Read JITFrame from the stack slot. gen_entry_point() writes an initial + // frame describing the entry PC + iseq; subsequent gen_save_pc_for_gc() + // calls update it with a more accurate PC before any non-leaf C call. + return (const zjit_jit_frame_t *)((VALUE *)cfp->jit_return)[-1]; + } +} #else -#define rb_zjit_enabled_p false +#define rb_zjit_entry 0 static inline void rb_zjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit_exception) {} static inline void rb_zjit_profile_insn(uint32_t insn, rb_execution_context_t *ec) {} static inline void rb_zjit_profile_enable(const rb_iseq_t *iseq) {} static inline void rb_zjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop) {} 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_invalidate_no_ep_escape(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) {} +static inline void rb_zjit_invalidate_no_singleton_class(VALUE klass) {} +static inline void rb_zjit_invalidate_root_box(void) {} +static inline void rb_zjit_jit_frame_update_references(zjit_jit_frame_t *jit_frame) {} +static inline void rb_zjit_materialize_frames(const rb_execution_context_t *ec, rb_control_frame_t *cfp) {} +static inline const zjit_jit_frame_t *CFP_ZJIT_FRAME(const rb_control_frame_t *cfp) { return NULL; } #endif // #if USE_ZJIT +#define rb_zjit_enabled_p (rb_zjit_entry != 0) + +// Return true if a given CFP has ZJIT's JITFrame. +static inline bool +CFP_ZJIT_FRAME_P(const rb_control_frame_t *cfp) +{ + if (!rb_zjit_enabled_p) return false; + return cfp->jit_return != NULL; +} + +static inline const VALUE* +CFP_PC(const rb_control_frame_t *cfp) +{ + if (CFP_ZJIT_FRAME_P(cfp)) { + return CFP_ZJIT_FRAME(cfp)->pc; + } + return cfp->pc; +} + +static inline const rb_iseq_t* +CFP_ISEQ(const rb_control_frame_t *cfp) +{ + if (CFP_ZJIT_FRAME_P(cfp)) { + return CFP_ZJIT_FRAME(cfp)->iseq; + } + return cfp->_iseq; +} + #endif // #ifndef ZJIT_H |
