blob: bfa9188d3e9bb2d4e3e7b2f84dafca4d86f8cd00 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
use crate::codegen::*;
use crate::core::*;
use crate::cruby::*;
use crate::invariants::*;
use crate::options::*;
use crate::stats::YjitExitLocations;
use std::os::raw;
use std::sync::atomic::{AtomicBool, Ordering};
/// For tracking whether the user enabled YJIT through command line arguments or environment
/// variables. AtomicBool to avoid `unsafe`. On x86 it compiles to simple movs.
/// See <https://doc.rust-lang.org/std/sync/atomic/enum.Ordering.html>
/// See [rb_yjit_enabled_p]
static YJIT_ENABLED: AtomicBool = AtomicBool::new(false);
/// Parse one command-line option.
/// This is called from ruby.c
#[no_mangle]
pub extern "C" fn rb_yjit_parse_option(str_ptr: *const raw::c_char) -> bool {
return parse_option(str_ptr).is_some();
}
/// Is YJIT on? The interpreter uses this function to decide whether to increment
/// ISEQ call counters. See jit_exec().
/// This is used frequently since it's used on every method call in the interpreter.
#[no_mangle]
pub extern "C" fn rb_yjit_enabled_p() -> raw::c_int {
// Note that we might want to call this function from signal handlers so
// might need to ensure signal-safety(7).
YJIT_ENABLED.load(Ordering::Acquire).into()
}
/// Like rb_yjit_enabled_p, but for Rust code.
pub fn yjit_enabled_p() -> bool {
YJIT_ENABLED.load(Ordering::Acquire)
}
/// After how many calls YJIT starts compiling a method
#[no_mangle]
pub extern "C" fn rb_yjit_call_threshold() -> raw::c_uint {
get_option!(call_threshold) as raw::c_uint
}
/// This function is called from C code
#[no_mangle]
pub extern "C" fn rb_yjit_init_rust() {
// TODO: need to make sure that command-line options have been
// initialized by CRuby
// Catch panics to avoid UB for unwinding into C frames.
// See https://doc.rust-lang.org/nomicon/exception-safety.html
// TODO: set a panic handler so the we don't print a message
// everytime we panic.
let result = std::panic::catch_unwind(|| {
Invariants::init();
CodegenGlobals::init();
YjitExitLocations::init();
// YJIT enabled and initialized successfully
YJIT_ENABLED.store(true, Ordering::Release);
});
if let Err(_) = result {
println!("YJIT: rb_yjit_init_rust() panicked. Aborting.");
std::process::abort();
}
}
/// Called from C code to begin compiling a function
/// NOTE: this should be wrapped in RB_VM_LOCK_ENTER(), rb_vm_barrier() on the C side
#[no_mangle]
pub extern "C" fn rb_yjit_iseq_gen_entry_point(iseq: IseqPtr, ec: EcPtr) -> *const u8 {
let maybe_code_ptr = gen_entry_point(iseq, ec);
match maybe_code_ptr {
Some(ptr) => ptr.raw_ptr(),
None => std::ptr::null(),
}
}
/// Simulate a situation where we are out of executable memory
#[no_mangle]
pub extern "C" fn rb_yjit_simulate_oom_bang(_ec: EcPtr, _ruby_self: VALUE) -> VALUE {
// If YJIT is not enabled, do nothing
if !yjit_enabled_p() {
return Qnil;
}
// Enabled in debug mode only for security
if cfg!(debug_assertions) {
let cb = CodegenGlobals::get_inline_cb();
let ocb = CodegenGlobals::get_outlined_cb().unwrap();
cb.set_pos(cb.get_mem_size() - 1);
ocb.set_pos(ocb.get_mem_size() - 1);
}
return Qnil;
}
|