Ruby 2.7.7p221 (2022-11-24 revision 168ec2b1e5ad0e4688e963d9de019557c78feed9)
mjit.h
Go to the documentation of this file.
1/**********************************************************************
2
3 mjit.h - Interface to MRI method JIT compiler for Ruby's main thread
4
5 Copyright (C) 2017 Vladimir Makarov <vmakarov@redhat.com>.
6
7**********************************************************************/
8
9#ifndef RUBY_MJIT_H
10#define RUBY_MJIT_H 1
11
12#include "ruby.h"
13#include "debug_counter.h"
14
15#if USE_MJIT
16
17// Special address values of a function generated from the
18// corresponding iseq by MJIT:
20 // ISEQ was not queued yet for the machine code generation
22 // ISEQ is already queued for the machine code generation but the
23 // code is not ready yet for the execution
25 // ISEQ included not compilable insn, some internal assertion failed
26 // or the unit is unloaded
28 // End mark
30};
31
32// MJIT options which can be defined on the MRI command line.
33struct mjit_options {
34 // Converted from "jit" feature flag to tell the enablement
35 // information to ruby_show_version().
36 char on;
37 // Save temporary files after MRI finish. The temporary files
38 // include the pre-compiled header, C code file generated for ISEQ,
39 // and the corresponding object file.
40 char save_temps;
41 // Print MJIT warnings to stderr.
42 char warnings;
43 // Disable compiler optimization and add debug symbols. It can be
44 // very slow.
45 char debug;
46 // Add arbitrary cflags.
47 char* debug_flags;
48 // If not 0, all ISeqs are synchronously compiled. For testing.
49 unsigned int wait;
50 // Number of calls to trigger JIT compilation. For testing.
51 unsigned int min_calls;
52 // Force printing info about MJIT work of level VERBOSE or
53 // less. 0=silence, 1=medium, 2=verbose.
54 int verbose;
55 // Maximal permitted number of iseq JIT codes in a MJIT memory
56 // cache.
58};
59
60// State of optimization switches
62 // Disable getinstancevariable/setinstancevariable optimizations based on inline cache
64 // Disable send/opt_send_without_block optimizations based on inline cache
66 // Disable method inlining
68};
69
71
75
79extern void rb_mjit_recompile_iseq(const rb_iseq_t *iseq);
81
82extern bool mjit_compile(FILE *f, const rb_iseq_t *iseq, const char *funcname);
83extern void mjit_init(const struct mjit_options *opts);
84extern void mjit_gc_start_hook(void);
85extern void mjit_gc_exit_hook(void);
86extern void mjit_free_iseq(const rb_iseq_t *iseq);
87extern void mjit_update_references(const rb_iseq_t *iseq);
88extern void mjit_mark(void);
89extern struct mjit_cont *mjit_cont_new(rb_execution_context_t *ec);
90extern void mjit_cont_free(struct mjit_cont *cont);
91extern void mjit_add_class_serial(rb_serial_t class_serial);
92extern void mjit_remove_class_serial(rb_serial_t class_serial);
93
94// A threshold used to reject long iseqs from JITting as such iseqs
95// takes too much time to be compiled.
96#define JIT_ISEQ_SIZE_THRESHOLD 1000
97
98// Return TRUE if given ISeq body should be compiled by MJIT
99static inline int
100mjit_target_iseq_p(struct rb_iseq_constant_body *body)
101{
102 return (body->type == ISEQ_TYPE_METHOD || body->type == ISEQ_TYPE_BLOCK)
104}
105
106// Try to execute the current iseq in ec. Use JIT code if it is ready.
107// If it is not, add ISEQ to the compilation queue and return Qundef.
108static inline VALUE
109mjit_exec(rb_execution_context_t *ec)
110{
111 const rb_iseq_t *iseq;
112 struct rb_iseq_constant_body *body;
113 long unsigned total_calls;
114 mjit_func_t func;
115
116 if (!mjit_call_p)
117 return Qundef;
118 RB_DEBUG_COUNTER_INC(mjit_exec);
119
120 iseq = ec->cfp->iseq;
121 body = iseq->body;
122 total_calls = ++body->total_calls;
123
124 func = body->jit_func;
126# ifdef MJIT_HEADER
127 RB_DEBUG_COUNTER_INC(mjit_frame_JT2VM);
128# else
129 RB_DEBUG_COUNTER_INC(mjit_frame_VM2VM);
130# endif
131 switch ((enum rb_mjit_iseq_func)func) {
133 RB_DEBUG_COUNTER_INC(mjit_exec_not_added);
134 if (total_calls == mjit_opts.min_calls && mjit_target_iseq_p(body)) {
135 RB_DEBUG_COUNTER_INC(mjit_exec_not_added_add_iseq);
137 if (UNLIKELY(mjit_opts.wait)) {
138 return rb_mjit_wait_call(ec, body);
139 }
140 }
141 return Qundef;
143 RB_DEBUG_COUNTER_INC(mjit_exec_not_ready);
144 return Qundef;
146 RB_DEBUG_COUNTER_INC(mjit_exec_not_compiled);
147 return Qundef;
148 default: // to avoid warning with LAST_JIT_ISEQ_FUNC
149 break;
150 }
151 }
152
153# ifdef MJIT_HEADER
154 RB_DEBUG_COUNTER_INC(mjit_frame_JT2JT);
155# else
156 RB_DEBUG_COUNTER_INC(mjit_frame_VM2JT);
157# endif
158 RB_DEBUG_COUNTER_INC(mjit_exec_call_func);
159 return func(ec, ec->cfp);
160}
161
162void mjit_child_after_fork(void);
163
164#else // USE_MJIT
165static inline struct mjit_cont *mjit_cont_new(rb_execution_context_t *ec){return NULL;}
166static inline void mjit_cont_free(struct mjit_cont *cont){}
167static inline void mjit_gc_start_hook(void){}
168static inline void mjit_gc_exit_hook(void){}
169static inline void mjit_free_iseq(const rb_iseq_t *iseq){}
170static inline void mjit_mark(void){}
171static inline void mjit_add_class_serial(rb_serial_t class_serial){}
172static inline void mjit_remove_class_serial(rb_serial_t class_serial){}
173static inline VALUE mjit_exec(rb_execution_context_t *ec) { return Qundef; /* unreachable */ }
174static inline void mjit_child_after_fork(void){}
175
176#endif // USE_MJIT
177#endif // RUBY_MJIT_H
#define NULL
_Bool mjit_call_p
Definition: mjit_worker.c:180
void mjit_gc_exit_hook(void)
#define Qundef
void mjit_update_references(const rb_iseq_t *iseq)
VALUE(* mjit_func_t)(rb_execution_context_t *, rb_control_frame_t *)
_Bool mjit_compile(FILE *f, const rb_iseq_t *iseq, const char *funcname)
#define RUBY_SYMBOL_EXPORT_BEGIN
unsigned long VALUE
#define JIT_ISEQ_SIZE_THRESHOLD
void mjit_child_after_fork(void)
void mjit_init(const struct mjit_options *opts)
#define RUBY_SYMBOL_EXPORT_END
unsigned long long rb_serial_t
struct mjit_options mjit_opts
Definition: mjit_worker.c:174
@ NOT_COMPILED_JIT_ISEQ_FUNC
@ NOT_READY_JIT_ISEQ_FUNC
@ NOT_ADDED_JIT_ISEQ_FUNC
const rb_iseq_t * iseq
#define UNLIKELY(x)
__uintptr_t uintptr_t
void mjit_free_iseq(const rb_iseq_t *iseq)
void rb_mjit_add_iseq_to_process(const rb_iseq_t *iseq)
void rb_mjit_recompile_iseq(const rb_iseq_t *iseq)
void mjit_remove_class_serial(rb_serial_t class_serial)
VALUE rb_mjit_wait_call(rb_execution_context_t *ec, struct rb_iseq_constant_body *body)
#define RUBY_EXTERN
void mjit_cont_free(struct mjit_cont *cont)
void mjit_add_class_serial(rb_serial_t class_serial)
void mjit_mark(void)
struct rb_mjit_compile_info * rb_mjit_iseq_compile_info(const struct rb_iseq_constant_body *body)
struct mjit_cont * mjit_cont_new(rb_execution_context_t *ec)
void mjit_gc_start_hook(void)
#define RB_DEBUG_COUNTER_INC(type)
#define f
enum rb_iseq_constant_body::iseq_type type
VALUE(* jit_func)(struct rb_execution_context_struct *, struct rb_control_frame_struct *)
struct rb_iseq_constant_body * body