2#include "internal/sanitizers.h"
3#include "internal/string.h"
4#include "internal/hash.h"
5#include "internal/variable.h"
6#include "internal/compile.h"
7#include "internal/class.h"
8#include "internal/fixnum.h"
9#include "internal/numeric.h"
10#include "internal/gc.h"
11#include "internal/vm.h"
14#include "vm_callinfo.h"
17#include "insns_info.inc"
19#include "vm_insnhelper.h"
21#include "probes_helper.h"
25#include "internal/cont.h"
26#include "internal/jit.h"
27#include "ractor_core.h"
36STATIC_ASSERT(pointer_tagging_scheme,
USE_FLONUM);
38enum zjit_struct_offsets {
41 RUBY_OFFSET_THREAD_RACTOR = offsetof(
rb_thread_t, ractor),
53 int32_t ractor_newobj_cache;
54 int32_t ractor_objspace;
57 .ractor_newobj_cache = offsetof(
rb_ractor_t, newobj_cache),
67 .materialize_block_code =
false,
70#if !defined(_WIN32) && defined(MAP_ANONYMOUS)
71uint8_t *rb_jit_align_ptr(uint8_t *ptr, uint32_t multiple);
82rb_zjit_reserve_low_addr_space(
size_t size)
84 void *mem_block = MAP_FAILED;
89 mem_block = mmap(NULL, size, PROT_NONE,
90 MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0);
95 #if defined(MAP_FIXED_NOREPLACE) && defined(_SC_PAGESIZE)
96 if (mem_block == MAP_FAILED) {
98 const uintptr_t probe_stride = 64 * 1024 * 1024;
99 const uint32_t page_size = (uint32_t)sysconf(_SC_PAGESIZE);
100 const uintptr_t limit = (uintptr_t)INT32_MAX - size;
101 for (uintptr_t addr = probe_stride; addr < limit; addr += probe_stride) {
103 void *req = rb_jit_align_ptr((uint8_t *)addr, page_size);
104 mem_block = mmap(req, size, PROT_NONE,
105 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE, -1, 0);
106 if (mem_block != MAP_FAILED)
break;
111 if (mem_block == MAP_FAILED)
return NULL;
115 if ((uintptr_t)mem_block + size > (uintptr_t)INT32_MAX) {
116 munmap(mem_block, size);
119 ruby_annotate_mmap(mem_block, size,
"Ruby:rb_zjit_reserve_low_addr_space");
126void *rb_zjit_reserve_low_addr_space(
size_t size) {
return NULL; }
130void rb_zjit_profile_disable(
const rb_iseq_t *iseq);
131int rb_zjit_insn_to_bare_insn(
int insn);
141 uintptr_t code_ptr = (uintptr_t)rb_zjit_iseq_gen_entry_point(iseq, ec, jit_exception);
144 ISEQ_BODY(iseq)->jit_exception = (rb_jit_func_t)code_ptr;
147 ISEQ_BODY(iseq)->jit_entry = (rb_jit_func_t)code_ptr;
154rb_zjit_iseq_set_jit_entry(
const rb_iseq_t *iseq,
void *code_ptr)
156 ISEQ_BODY(iseq)->jit_entry = (rb_jit_func_t)code_ptr;
163rb_zjit_profile_enable(
const rb_iseq_t *iseq)
166 const void *
const *insn_table = rb_vm_get_insns_address_table();
168 unsigned int insn_idx = 0;
169 while (insn_idx < ISEQ_BODY(iseq)->iseq_size) {
170 int insn = rb_vm_insn_addr2opcode((
void *)ISEQ_BODY(iseq)->iseq_encoded[insn_idx]);
171 int zjit_insn = vm_bare_insn_to_zjit_insn(insn);
172 if (insn != zjit_insn) {
173 ISEQ_BODY(iseq)->iseq_encoded[insn_idx] = (
VALUE)insn_table[zjit_insn];
175 insn_idx += insn_len(insn);
182rb_zjit_iseq_has_profiled_enough(
const rb_iseq_t *iseq)
186 if (body->jit_entry_calls < rb_zjit_profile_threshold) {
189 body->jit_entry_calls = rb_zjit_profile_threshold;
190 rb_zjit_profile_enable(iseq);
193 body->jit_entry_calls++;
196 return body->jit_entry_calls >= rb_zjit_call_threshold;
201rb_zjit_profile_disable(
const rb_iseq_t *iseq)
204 const void *
const *insn_table = rb_vm_get_insns_address_table();
206 unsigned int insn_idx = 0;
207 while (insn_idx < ISEQ_BODY(iseq)->iseq_size) {
208 int insn = rb_vm_insn_addr2opcode((
void *)ISEQ_BODY(iseq)->iseq_encoded[insn_idx]);
209 int bare_insn = vm_zjit_insn_to_bare_insn(insn);
210 if (insn != bare_insn) {
211 ISEQ_BODY(iseq)->iseq_encoded[insn_idx] = (
VALUE)insn_table[bare_insn];
213 insn_idx += insn_len(insn);
219rb_zjit_insn_to_bare_insn(
int insn)
221 return vm_zjit_insn_to_bare_insn(insn);
226rb_zjit_iseq_insn_set(
const rb_iseq_t *iseq,
unsigned int insn_idx,
enum ruby_vminsn_type bare_insn)
229 int insn = rb_vm_insn_addr2opcode((
void *)ISEQ_BODY(iseq)->iseq_encoded[insn_idx]);
230 RUBY_ASSERT(vm_zjit_insn_to_bare_insn(insn) == (
int)bare_insn);
232 const void *
const *insn_table = rb_vm_get_insns_address_table();
233 ISEQ_BODY(iseq)->iseq_encoded[insn_idx] = (
VALUE)insn_table[bare_insn];
237rb_zjit_print_exception(
void)
239 VALUE exception = rb_errinfo();
240 rb_set_errinfo(
Qnil);
241 assert(
RTEST(exception));
242 rb_warn(
"Ruby error: %"PRIsVALUE
"",
rb_funcall(exception, rb_intern(
"full_message"), 0));
246rb_zjit_singleton_class_p(
VALUE klass)
248 return RCLASS_SINGLETON_P(klass);
255rb_zjit_new_obj_shape(
VALUE flags,
size_t alloc_size)
260 shape_id = ROOT_SHAPE_ID;
263 shape_id = ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_EXTENDED;
266 shape_id = ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_RDATA;
269 shape_id = ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER;
274 shape_id = rb_shape_transition_frozen(shape_id);
277 shape_id = rb_shape_transition_slot_size(shape_id, rb_gc_size_slot_size(alloc_size));
279 return (flags & SHAPE_FLAG_MASK) | ((
VALUE)shape_id << SHAPE_FLAG_SHIFT);
286 return result ? pushval :
Qnil;
290rb_zjit_method_tracing_currently_enabled(
void)
293 if (rb_multi_ractor_p()) {
294 tracing_events = ruby_vm_event_enabled_global_flags;
300 tracing_events = rb_ec_ractor_hooks(GET_EC())->events;
312rb_zjit_iseq_tracing_currently_enabled(
void)
315 if (rb_multi_ractor_p()) {
316 tracing_events = ruby_vm_event_enabled_global_flags;
319 tracing_events = rb_ec_ractor_hooks(GET_EC())->events;
322 return tracing_events & ISEQ_TRACE_EVENTS;
326rb_zjit_insn_leaf(
int insn,
const VALUE *opes)
328 return insn_leaf(insn, opes);
332rb_zjit_local_id(
const rb_iseq_t *iseq,
unsigned idx)
334 return ISEQ_BODY(iseq)->local_table[idx];
343rb_zjit_class_initialized_p(
VALUE klass)
345 return RCLASS_INITIALIZED_P(klass);
352rb_zjit_can_load_superclass_p(
VALUE klass)
360bool rb_zjit_class_has_struct_allocator(
VALUE klass);
365rb_zjit_class_has_default_allocator(
VALUE klass)
367 assert(RCLASS_INITIALIZED_P(klass));
368 assert(!RCLASS_SINGLETON_P(klass));
370 return alloc == rb_class_allocate_instance;
375bool rb_vm_once_done_value(
ISE is,
VALUE *result);
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
#define RUBY_EVENT_C_CALL
A method, written in C, is called.
#define RUBY_EVENT_C_RETURN
Return from a method, written in C.
uint32_t rb_event_flag_t
Represents event(s).
#define T_MASK
Old name of RUBY_T_MASK.
#define T_STRUCT
Old name of RUBY_T_STRUCT.
#define T_DATA
Old name of RUBY_T_DATA.
#define Qnil
Old name of RUBY_Qnil.
#define T_OBJECT
Old name of RUBY_T_OBJECT.
#define FL_FREEZE
Old name of RUBY_FL_FREEZE.
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
VALUE rb_cBasicObject
BasicObject class.
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ivar_defined(VALUE obj, ID name)
Queries if the instance variable is defined at the object.
VALUE(* rb_alloc_func_t)(VALUE klass)
This is the type of functions that ruby calls when trying to allocate an object.
#define RTEST
This is an old name of RB_TEST.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.