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 "ractor_core.h"
35STATIC_ASSERT(pointer_tagging_scheme,
USE_FLONUM);
37enum zjit_struct_offsets {
40 RUBY_OFFSET_THREAD_RACTOR = offsetof(
rb_thread_t, ractor),
52 int32_t ractor_newobj_cache;
53 int32_t ractor_objspace;
56 .ractor_newobj_cache = offsetof(
rb_ractor_t, newobj_cache),
66 .materialize_block_code =
false,
69#if !defined(_WIN32) && defined(MAP_ANONYMOUS)
70uint8_t *rb_jit_align_ptr(uint8_t *ptr, uint32_t multiple);
81rb_zjit_reserve_low_addr_space(
size_t size)
83 void *mem_block = MAP_FAILED;
88 mem_block = mmap(NULL, size, PROT_NONE,
89 MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0);
94 #if defined(MAP_FIXED_NOREPLACE) && defined(_SC_PAGESIZE)
95 if (mem_block == MAP_FAILED) {
97 const uintptr_t probe_stride = 64 * 1024 * 1024;
98 const uint32_t page_size = (uint32_t)sysconf(_SC_PAGESIZE);
99 const uintptr_t limit = (uintptr_t)INT32_MAX - size;
100 for (uintptr_t addr = probe_stride; addr < limit; addr += probe_stride) {
102 void *req = rb_jit_align_ptr((uint8_t *)addr, page_size);
103 mem_block = mmap(req, size, PROT_NONE,
104 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE, -1, 0);
105 if (mem_block != MAP_FAILED)
break;
110 if (mem_block == MAP_FAILED)
return NULL;
114 if ((uintptr_t)mem_block + size > (uintptr_t)INT32_MAX) {
115 munmap(mem_block, size);
118 ruby_annotate_mmap(mem_block, size,
"Ruby:rb_zjit_reserve_low_addr_space");
125void *rb_zjit_reserve_low_addr_space(
size_t size) {
return NULL; }
129void rb_zjit_profile_disable(
const rb_iseq_t *iseq);
130int rb_zjit_insn_to_bare_insn(
int insn);
140 uintptr_t code_ptr = (uintptr_t)rb_zjit_iseq_gen_entry_point(iseq, ec, jit_exception);
143 ISEQ_BODY(iseq)->jit_exception = (rb_jit_func_t)code_ptr;
146 ISEQ_BODY(iseq)->jit_entry = (rb_jit_func_t)code_ptr;
155rb_zjit_profile_enable(
const rb_iseq_t *iseq)
158 const void *
const *insn_table = rb_vm_get_insns_address_table();
160 unsigned int insn_idx = 0;
161 while (insn_idx < ISEQ_BODY(iseq)->iseq_size) {
162 int insn = rb_vm_insn_addr2opcode((
void *)ISEQ_BODY(iseq)->iseq_encoded[insn_idx]);
163 int zjit_insn = vm_bare_insn_to_zjit_insn(insn);
164 if (insn != zjit_insn) {
165 ISEQ_BODY(iseq)->iseq_encoded[insn_idx] = (
VALUE)insn_table[zjit_insn];
167 insn_idx += insn_len(insn);
173rb_zjit_profile_disable(
const rb_iseq_t *iseq)
176 const void *
const *insn_table = rb_vm_get_insns_address_table();
178 unsigned int insn_idx = 0;
179 while (insn_idx < ISEQ_BODY(iseq)->iseq_size) {
180 int insn = rb_vm_insn_addr2opcode((
void *)ISEQ_BODY(iseq)->iseq_encoded[insn_idx]);
181 int bare_insn = vm_zjit_insn_to_bare_insn(insn);
182 if (insn != bare_insn) {
183 ISEQ_BODY(iseq)->iseq_encoded[insn_idx] = (
VALUE)insn_table[bare_insn];
185 insn_idx += insn_len(insn);
191rb_zjit_insn_to_bare_insn(
int insn)
193 return vm_zjit_insn_to_bare_insn(insn);
198rb_zjit_iseq_insn_set(
const rb_iseq_t *iseq,
unsigned int insn_idx,
enum ruby_vminsn_type bare_insn)
201 int insn = rb_vm_insn_addr2opcode((
void *)ISEQ_BODY(iseq)->iseq_encoded[insn_idx]);
202 RUBY_ASSERT(vm_zjit_insn_to_bare_insn(insn) == (
int)bare_insn);
204 const void *
const *insn_table = rb_vm_get_insns_address_table();
205 ISEQ_BODY(iseq)->iseq_encoded[insn_idx] = (
VALUE)insn_table[bare_insn];
209rb_zjit_print_exception(
void)
211 VALUE exception = rb_errinfo();
212 rb_set_errinfo(
Qnil);
213 assert(
RTEST(exception));
214 rb_warn(
"Ruby error: %"PRIsVALUE
"",
rb_funcall(exception, rb_intern(
"full_message"), 0));
218rb_zjit_singleton_class_p(
VALUE klass)
220 return RCLASS_SINGLETON_P(klass);
227rb_zjit_new_obj_shape(
VALUE flags,
size_t alloc_size)
232 shape_id = ROOT_SHAPE_ID;
235 shape_id = ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_EXTENDED;
238 shape_id = ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_RDATA;
241 shape_id = ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER;
246 shape_id = rb_shape_transition_frozen(shape_id);
249 shape_id = rb_shape_transition_slot_size(shape_id, rb_gc_size_slot_size(alloc_size));
251 return (flags & SHAPE_FLAG_MASK) | ((
VALUE)shape_id << SHAPE_FLAG_SHIFT);
258 return result ? pushval :
Qnil;
262rb_zjit_method_tracing_currently_enabled(
void)
265 if (rb_multi_ractor_p()) {
266 tracing_events = ruby_vm_event_enabled_global_flags;
272 tracing_events = rb_ec_ractor_hooks(GET_EC())->events;
284rb_zjit_iseq_tracing_currently_enabled(
void)
287 if (rb_multi_ractor_p()) {
288 tracing_events = ruby_vm_event_enabled_global_flags;
291 tracing_events = rb_ec_ractor_hooks(GET_EC())->events;
294 return tracing_events & ISEQ_TRACE_EVENTS;
298rb_zjit_insn_leaf(
int insn,
const VALUE *opes)
300 return insn_leaf(insn, opes);
304rb_zjit_local_id(
const rb_iseq_t *iseq,
unsigned idx)
306 return ISEQ_BODY(iseq)->local_table[idx];
315rb_zjit_class_initialized_p(
VALUE klass)
317 return RCLASS_INITIALIZED_P(klass);
325rb_zjit_class_has_default_allocator(
VALUE klass)
327 assert(RCLASS_INITIALIZED_P(klass));
328 assert(!RCLASS_SINGLETON_P(klass));
330 return alloc == rb_class_allocate_instance;
334VALUE rb_vm_untag_block_handler(
VALUE block_handler);
#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_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.