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"
13 #include "vm_callinfo.h"
16 #include "insns_info.inc"
18 #include "vm_insnhelper.h"
20 #include "probes_helper.h"
22 #include "ruby/debug.h"
23 #include "internal/cont.h"
26 // For mmapp(), sysconf()
35 rb_zjit_get_page_size(void)
37 #if defined(_SC_PAGESIZE)
38 long page_size
= sysconf(_SC_PAGESIZE
);
39 if (page_size
<= 0) rb_bug("zjit: failed to get page size");
41 // 1 GiB limit. x86 CPUs with PDPE1GB can do this and anything larger is unexpected.
42 // Though our design sort of assume we have fine grained control over memory protection
43 // which require small page sizes.
44 if (page_size
> 0x40000000l
) rb_bug("zjit page size too large");
46 return (uint32_t)page_size
;
48 #error "ZJIT supports POSIX only for now"
52 #if defined(MAP_FIXED_NOREPLACE) && defined(_SC_PAGESIZE)
53 // Align the current write position to a multiple of bytes
55 align_ptr(uint8_t *ptr
, uint32_t multiple
)
57 // Compute the pointer modulo the given alignment boundary
58 uint32_t rem
= ((uint32_t)(uintptr_t)ptr
) % multiple
;
60 // If the pointer is already aligned, stop
64 // Pad the pointer by the necessary amount to align it
65 uint32_t pad
= multiple
- rem
;
71 // Address space reservation. Memory pages are mapped on an as needed basis.
72 // See the Rust mm module for details.
74 rb_zjit_reserve_addr_space(uint32_t mem_size
)
80 #if defined(MAP_FIXED_NOREPLACE) && defined(_SC_PAGESIZE)
81 uint32_t const page_size
= (uint32_t)sysconf(_SC_PAGESIZE
);
82 uint8_t *const cfunc_sample_addr
= (void *)(uintptr_t)&rb_zjit_reserve_addr_space
;
83 uint8_t *const probe_region_end
= cfunc_sample_addr
+ INT32_MAX
;
84 // Align the requested address to page size
85 uint8_t *req_addr
= align_ptr(cfunc_sample_addr
, page_size
);
87 // Probe for addresses close to this function using MAP_FIXED_NOREPLACE
88 // to improve odds of being in range for 32-bit relative call instructions.
94 MAP_PRIVATE
| MAP_ANONYMOUS
| MAP_FIXED_NOREPLACE
,
99 // If we succeeded, stop
100 if (mem_block
!= MAP_FAILED
) {
101 ruby_annotate_mmap(mem_block
, mem_size
, "Ruby:rb_zjit_reserve_addr_space");
105 // -4MiB. Downwards to probe away from the heap. (On x86/A64 Linux
106 // main_code_addr < heap_addr, and in case we are in a shared
107 // library mapped higher than the heap, downwards is still better
108 // since it's towards the end of the heap rather than the stack.)
109 req_addr
-= 4 * 1024 * 1024;
110 } while (req_addr
< probe_region_end
);
112 // On MacOS and other platforms
114 // Try to map a chunk of memory as executable
116 (void *)rb_zjit_reserve_addr_space
,
119 MAP_PRIVATE
| MAP_ANONYMOUS
,
126 if (mem_block
== MAP_FAILED
) {
127 // Try again without the address hint (e.g., valgrind)
132 MAP_PRIVATE
| MAP_ANONYMOUS
,
137 if (mem_block
!= MAP_FAILED
) {
138 ruby_annotate_mmap(mem_block
, mem_size
, "Ruby:rb_zjit_reserve_addr_space:fallback");
142 // Check that the memory mapping was successful
143 if (mem_block
== MAP_FAILED
) {
144 perror("ruby: zjit: mmap:");
145 if(errno
== ENOMEM
) {
146 // No crash report if it's only insufficient memory
149 rb_bug("mmap failed");
154 // Windows not supported for now
160 rb_RSTRING_LEN(VALUE str
)
162 return RSTRING_LEN(str
);
166 rb_RSTRING_PTR(VALUE str
)
168 return RSTRING_PTR(str
);
171 void rb_zjit_profile_disable(const rb_iseq_t
*iseq
);
174 rb_zjit_compile_iseq(const rb_iseq_t
*iseq
, rb_execution_context_t
*ec
, bool jit_exception
)
179 // Convert ZJIT instructions back to bare instructions
180 rb_zjit_profile_disable(iseq
);
182 // Compile a block version starting at the current instruction
183 uint8_t *rb_zjit_iseq_gen_entry_point(const rb_iseq_t
*iseq
, rb_execution_context_t
*ec
); // defined in Rust
184 uintptr_t code_ptr
= (uintptr_t)rb_zjit_iseq_gen_entry_point(iseq
, ec
);
186 // TODO: support jit_exception
187 iseq
->body
->jit_entry
= (rb_jit_func_t
)code_ptr
;
193 rb_iseq_encoded_size(const rb_iseq_t
*iseq
)
195 return iseq
->body
->iseq_size
;
198 // Get the opcode given a program counter. Can return trace opcode variants.
200 rb_iseq_opcode_at_pc(const rb_iseq_t
*iseq
, const VALUE
*pc
)
202 // ZJIT should only use iseqs after AST to bytecode compilation
203 RUBY_ASSERT_ALWAYS(FL_TEST_RAW((VALUE
)iseq
, ISEQ_TRANSLATED
));
205 const VALUE at_pc
= *pc
;
206 return rb_vm_insn_addr2opcode((const void *)at_pc
);
209 // Get the PC for a given index in an iseq
211 rb_iseq_pc_at_idx(const rb_iseq_t
*iseq
, uint32_t insn_idx
)
213 RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(iseq
, imemo_iseq
));
214 RUBY_ASSERT_ALWAYS(insn_idx
< iseq
->body
->iseq_size
);
215 VALUE
*encoded
= iseq
->body
->iseq_encoded
;
216 VALUE
*pc
= &encoded
[insn_idx
];
221 rb_insn_name(VALUE insn
)
223 return insn_name(insn
);
226 struct rb_control_frame_struct
*
227 rb_get_ec_cfp(const rb_execution_context_t
*ec
)
233 rb_get_cfp_iseq(struct rb_control_frame_struct
*cfp
)
239 rb_get_cfp_pc(struct rb_control_frame_struct
*cfp
)
241 return (VALUE
*)cfp
->pc
;
245 rb_get_cfp_sp(struct rb_control_frame_struct
*cfp
)
251 rb_get_cfp_self(struct rb_control_frame_struct
*cfp
)
257 rb_get_cfp_ep(struct rb_control_frame_struct
*cfp
)
259 return (VALUE
*)cfp
->ep
;
263 rb_get_cfp_ep_level(struct rb_control_frame_struct
*cfp
, uint32_t lv
)
266 const VALUE
*ep
= (VALUE
*)cfp
->ep
;
267 for (i
= 0; i
< lv
; i
++) {
268 ep
= VM_ENV_PREV_EP(ep
);
273 extern VALUE
*rb_vm_base_ptr(struct rb_control_frame_struct
*cfp
);
276 rb_get_cme_def_type(const rb_callable_method_entry_t
*cme
)
278 if (UNDEFINED_METHOD_ENTRY_P(cme
)) {
279 return VM_METHOD_TYPE_UNDEF
;
282 return cme
->def
->type
;
287 rb_get_cme_def_body_attr_id(const rb_callable_method_entry_t
*cme
)
289 return cme
->def
->body
.attr
.id
;
292 enum method_optimized_type
293 rb_get_cme_def_body_optimized_type(const rb_callable_method_entry_t
*cme
)
295 return cme
->def
->body
.optimized
.type
;
299 rb_get_cme_def_body_optimized_index(const rb_callable_method_entry_t
*cme
)
301 return cme
->def
->body
.optimized
.index
;
305 rb_get_cme_def_body_cfunc(const rb_callable_method_entry_t
*cme
)
307 return UNALIGNED_MEMBER_PTR(cme
->def
, body
.cfunc
);
311 rb_get_def_method_serial(const rb_method_definition_t
*def
)
313 return def
->method_serial
;
317 rb_get_def_original_id(const rb_method_definition_t
*def
)
319 return def
->original_id
;
323 rb_get_mct_argc(const rb_method_cfunc_t
*mct
)
329 rb_get_mct_func(const rb_method_cfunc_t
*mct
)
331 return (void*)(uintptr_t)mct
->func
; // this field is defined as type VALUE (*func)(ANYARGS)
335 rb_get_def_iseq_ptr(rb_method_definition_t
*def
)
337 return def_iseq_ptr(def
);
341 rb_get_iseq_body_local_iseq(const rb_iseq_t
*iseq
)
343 return iseq
->body
->local_iseq
;
347 rb_get_iseq_body_iseq_encoded(const rb_iseq_t
*iseq
)
349 return iseq
->body
->iseq_encoded
;
353 rb_get_iseq_body_stack_max(const rb_iseq_t
*iseq
)
355 return iseq
->body
->stack_max
;
359 rb_get_iseq_body_type(const rb_iseq_t
*iseq
)
361 return iseq
->body
->type
;
365 rb_get_iseq_flags_has_lead(const rb_iseq_t
*iseq
)
367 return iseq
->body
->param
.flags
.has_lead
;
371 rb_get_iseq_flags_has_opt(const rb_iseq_t
*iseq
)
373 return iseq
->body
->param
.flags
.has_opt
;
377 rb_get_iseq_flags_has_kw(const rb_iseq_t
*iseq
)
379 return iseq
->body
->param
.flags
.has_kw
;
383 rb_get_iseq_flags_has_post(const rb_iseq_t
*iseq
)
385 return iseq
->body
->param
.flags
.has_post
;
389 rb_get_iseq_flags_has_kwrest(const rb_iseq_t
*iseq
)
391 return iseq
->body
->param
.flags
.has_kwrest
;
395 rb_get_iseq_flags_anon_kwrest(const rb_iseq_t
*iseq
)
397 return iseq
->body
->param
.flags
.anon_kwrest
;
401 rb_get_iseq_flags_has_rest(const rb_iseq_t
*iseq
)
403 return iseq
->body
->param
.flags
.has_rest
;
407 rb_get_iseq_flags_ruby2_keywords(const rb_iseq_t
*iseq
)
409 return iseq
->body
->param
.flags
.ruby2_keywords
;
413 rb_get_iseq_flags_has_block(const rb_iseq_t
*iseq
)
415 return iseq
->body
->param
.flags
.has_block
;
419 rb_get_iseq_flags_ambiguous_param0(const rb_iseq_t
*iseq
)
421 return iseq
->body
->param
.flags
.ambiguous_param0
;
425 rb_get_iseq_flags_accepts_no_kwarg(const rb_iseq_t
*iseq
)
427 return iseq
->body
->param
.flags
.accepts_no_kwarg
;
431 rb_get_iseq_flags_forwardable(const rb_iseq_t
*iseq
)
433 return iseq
->body
->param
.flags
.forwardable
;
436 // This is defined only as a named struct inside rb_iseq_constant_body.
437 // By giving it a separate typedef, we make it nameable by rust-bindgen.
438 // Bindgen's temp/anon name isn't guaranteed stable.
439 typedef struct rb_iseq_param_keyword rb_iseq_param_keyword_struct
;
441 const rb_iseq_param_keyword_struct
*
442 rb_get_iseq_body_param_keyword(const rb_iseq_t
*iseq
)
444 return iseq
->body
->param
.keyword
;
448 rb_get_iseq_body_param_size(const rb_iseq_t
*iseq
)
450 return iseq
->body
->param
.size
;
454 rb_get_iseq_body_param_lead_num(const rb_iseq_t
*iseq
)
456 return iseq
->body
->param
.lead_num
;
460 rb_get_iseq_body_param_opt_num(const rb_iseq_t
*iseq
)
462 return iseq
->body
->param
.opt_num
;
466 rb_get_iseq_body_param_opt_table(const rb_iseq_t
*iseq
)
468 return iseq
->body
->param
.opt_table
;
472 rb_get_iseq_body_local_table_size(const rb_iseq_t
*iseq
)
474 return iseq
->body
->local_table_size
;
478 rb_get_cikw_keyword_len(const struct rb_callinfo_kwarg
*cikw
)
480 return cikw
->keyword_len
;
484 rb_get_cikw_keywords_idx(const struct rb_callinfo_kwarg
*cikw
, int idx
)
486 return cikw
->keywords
[idx
];
489 const struct rb_callinfo
*
490 rb_get_call_data_ci(const struct rb_call_data
*cd
)
495 // The FL_TEST() macro
497 rb_FL_TEST(VALUE obj
, VALUE flags
)
499 return RB_FL_TEST(obj
, flags
);
502 // The FL_TEST_RAW() macro, normally an internal implementation detail
504 rb_FL_TEST_RAW(VALUE obj
, VALUE flags
)
506 return FL_TEST_RAW(obj
, flags
);
509 // The RB_TYPE_P macro
511 rb_RB_TYPE_P(VALUE obj
, enum ruby_value_type t
)
513 return RB_TYPE_P(obj
, t
);
517 rb_RSTRUCT_LEN(VALUE st
)
519 return RSTRUCT_LEN(st
);
523 rb_BASIC_OP_UNREDEFINED_P(enum ruby_basic_operators bop
, uint32_t klass
)
525 return BASIC_OP_UNREDEFINED_P(bop
, klass
);
529 rb_zjit_multi_ractor_p(void)
531 return rb_multi_ractor_p();
536 rb_assert_iseq_handle(VALUE handle
)
538 RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(handle
, imemo_iseq
));
542 rb_zjit_constcache_shareable(const struct iseq_inline_constant_cache_entry
*ice
)
544 return (ice
->flags
& IMEMO_CONST_CACHE_SHAREABLE
) != 0;
548 rb_assert_cme_handle(VALUE handle
)
550 RUBY_ASSERT_ALWAYS(!rb_objspace_garbage_object_p(handle
));
551 RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(handle
, imemo_ment
));
555 rb_IMEMO_TYPE_P(VALUE imemo
, enum imemo_type imemo_type
)
557 return IMEMO_TYPE_P(imemo
, imemo_type
);
560 // Release the VM lock. The lock level must point to the same integer used to
563 rb_zjit_vm_unlock(unsigned int *recursive_lock_level
, const char *file
, int line
)
565 rb_vm_lock_leave(recursive_lock_level
, file
, line
);
569 rb_zjit_mark_writable(void *mem_block
, uint32_t mem_size
)
571 return mprotect(mem_block
, mem_size
, PROT_READ
| PROT_WRITE
) == 0;
575 rb_zjit_mark_executable(void *mem_block
, uint32_t mem_size
)
577 // Do not call mprotect when mem_size is zero. Some platforms may return
578 // an error for it. https://github.com/Shopify/ruby/issues/450
582 if (mprotect(mem_block
, mem_size
, PROT_READ
| PROT_EXEC
)) {
583 rb_bug("Couldn't make JIT page (%p, %lu bytes) executable, errno: %s",
584 mem_block
, (unsigned long)mem_size
, strerror(errno
));
588 // Free the specified memory block.
590 rb_zjit_mark_unused(void *mem_block
, uint32_t mem_size
)
592 // On Linux, you need to use madvise MADV_DONTNEED to free memory.
593 // We might not need to call this on macOS, but it's not really documented.
594 // We generally prefer to do the same thing on both to ease testing too.
595 madvise(mem_block
, mem_size
, MADV_DONTNEED
);
597 // On macOS, mprotect PROT_NONE seems to reduce RSS.
598 // We also call this on Linux to avoid executing unused pages.
599 return mprotect(mem_block
, mem_size
, PROT_NONE
) == 0;
602 // Invalidate icache for arm64.
603 // `start` is inclusive and `end` is exclusive.
605 rb_zjit_icache_invalidate(void *start
, void *end
)
607 // Clear/invalidate the instruction cache. Compiles to nothing on x86_64
608 // but required on ARM before running freshly written code.
609 // On Darwin it's the same as calling sys_icache_invalidate().
611 __builtin___clear_cache(start
, end
);
612 #elif defined(__aarch64__)
613 #error No instruction cache clear available with this compiler on Aarch64!
618 rb_vm_ci_argc(const struct rb_callinfo
*ci
)
620 return vm_ci_argc(ci
);
624 rb_vm_ci_mid(const struct rb_callinfo
*ci
)
626 return vm_ci_mid(ci
);
630 rb_vm_ci_flag(const struct rb_callinfo
*ci
)
632 return vm_ci_flag(ci
);
635 const struct rb_callinfo_kwarg
*
636 rb_vm_ci_kwarg(const struct rb_callinfo
*ci
)
638 return vm_ci_kwarg(ci
);
641 rb_method_visibility_t
642 rb_METHOD_ENTRY_VISI(const rb_callable_method_entry_t
*me
)
644 return METHOD_ENTRY_VISI(me
);
648 rb_yarv_class_of(VALUE obj
)
650 return rb_class_of(obj
);
653 // Acquire the VM lock and then signal all other Ruby threads (ractors) to
654 // contend for the VM lock, putting them to sleep. ZJIT uses this to evict
655 // threads running inside generated code so among other things, it can
656 // safely change memory protection of regions housing generated code.
658 rb_zjit_vm_lock_then_barrier(unsigned int *recursive_lock_level
, const char *file
, int line
)
660 rb_vm_lock_enter(recursive_lock_level
, file
, line
);
665 rb_RCLASS_ORIGIN(VALUE c
)
667 return RCLASS_ORIGIN(c
);
670 // Convert a given ISEQ's instructions to zjit_* instructions
672 rb_zjit_profile_enable(const rb_iseq_t
*iseq
)
674 // This table encodes an opcode into the instruction's address
675 const void *const *insn_table
= rb_vm_get_insns_address_table();
677 unsigned int insn_idx
= 0;
678 while (insn_idx
< iseq
->body
->iseq_size
) {
679 int insn
= rb_vm_insn_addr2opcode((void *)iseq
->body
->iseq_encoded
[insn_idx
]);
680 int zjit_insn
= vm_bare_insn_to_zjit_insn(insn
);
681 if (insn
!= zjit_insn
) {
682 iseq
->body
->iseq_encoded
[insn_idx
] = (VALUE
)insn_table
[zjit_insn
];
684 insn_idx
+= insn_len(insn
);
688 // Convert a given ISEQ's ZJIT instructions to bare instructions
690 rb_zjit_profile_disable(const rb_iseq_t
*iseq
)
692 // This table encodes an opcode into the instruction's address
693 const void *const *insn_table
= rb_vm_get_insns_address_table();
695 unsigned int insn_idx
= 0;
696 while (insn_idx
< iseq
->body
->iseq_size
) {
697 int insn
= rb_vm_insn_addr2opcode((void *)iseq
->body
->iseq_encoded
[insn_idx
]);
698 int bare_insn
= vm_zjit_insn_to_bare_insn(insn
);
699 if (insn
!= bare_insn
) {
700 iseq
->body
->iseq_encoded
[insn_idx
] = (VALUE
)insn_table
[bare_insn
];
702 insn_idx
+= insn_len(insn
);
706 // Get profiling information for ISEQ
708 rb_iseq_get_zjit_payload(const rb_iseq_t
*iseq
)
710 RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(iseq
, imemo_iseq
));
712 return iseq
->body
->zjit_payload
;
715 // Body is NULL when constructing the iseq.
720 // Set profiling information for ISEQ
722 rb_iseq_set_zjit_payload(const rb_iseq_t
*iseq
, void *payload
)
724 RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(iseq
, imemo_iseq
));
725 RUBY_ASSERT_ALWAYS(iseq
->body
);
726 RUBY_ASSERT_ALWAYS(NULL
== iseq
->body
->zjit_payload
);
727 iseq
->body
->zjit_payload
= payload
;
730 // Primitives used by zjit.rb
731 VALUE
rb_zjit_assert_compiles(rb_execution_context_t
*ec
, VALUE self
);
734 rb_zjit_print_exception(void)
736 VALUE exception
= rb_errinfo();
737 rb_set_errinfo(Qnil
);
738 assert(RTEST(exception
));
739 rb_warn("Ruby error: %"PRIsVALUE
"", rb_funcall(exception
, rb_intern("full_message"), 0));
742 // Preprocessed zjit.rb generated during build
743 #include "zjit.rbinc"