Implement Options as part of ZJITState
This commit is contained in:
parent
464e74f20c
commit
0252ce1cd4
Notes:
git
2025-04-18 13:49:13 +00:00
@ -23,6 +23,9 @@ typedef struct ruby_cmdline_options {
|
||||
ruby_features_t warn;
|
||||
unsigned int dump;
|
||||
long backtrace_length_limit;
|
||||
#if USE_ZJIT
|
||||
void *zjit;
|
||||
#endif
|
||||
|
||||
const char *crash_report;
|
||||
|
||||
@ -39,7 +42,6 @@ typedef struct ruby_cmdline_options {
|
||||
#if USE_YJIT
|
||||
unsigned int yjit: 1;
|
||||
#endif
|
||||
unsigned int zjit: 1;
|
||||
} ruby_cmdline_options_t;
|
||||
|
||||
struct ruby_opt_message {
|
||||
|
33
ruby.c
33
ruby.c
@ -1184,6 +1184,21 @@ setup_yjit_options(const char *s)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if USE_ZJIT
|
||||
static void
|
||||
setup_zjit_options(ruby_cmdline_options_t *opt, const char *s)
|
||||
{
|
||||
// The option parsing is done in zjit/src/options.rs
|
||||
extern void *rb_zjit_init_options(void);
|
||||
extern bool rb_zjit_parse_option(void *options, const char *s);
|
||||
|
||||
if (!opt->zjit) opt->zjit = rb_zjit_init_options();
|
||||
if (!rb_zjit_parse_option(opt->zjit, s)) {
|
||||
rb_raise(rb_eRuntimeError, "invalid ZJIT option '%s' (--help will show valid zjit options)", s);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Following proc_*_option functions are tree kinds:
|
||||
*
|
||||
@ -1454,9 +1469,13 @@ proc_long_options(ruby_cmdline_options_t *opt, const char *s, long argc, char **
|
||||
#endif
|
||||
}
|
||||
else if (is_option_with_optarg("zjit", '-', true, false, false)) {
|
||||
#if USE_ZJIT
|
||||
FEATURE_SET(opt->features, FEATURE_BIT(zjit));
|
||||
extern bool rb_zjit_parse_option();
|
||||
rb_zjit_parse_option();
|
||||
setup_zjit_options(opt, s);
|
||||
#else
|
||||
rb_warn("Ruby was built without ZJIT support."
|
||||
" You may need to install rustc to build Ruby with ZJIT.");
|
||||
#endif
|
||||
}
|
||||
else if (strcmp("yydebug", s) == 0) {
|
||||
if (envopt) goto noenvopt_long;
|
||||
@ -1799,9 +1818,8 @@ ruby_opt_init(ruby_cmdline_options_t *opt)
|
||||
#endif
|
||||
#if USE_ZJIT
|
||||
if (opt->zjit) {
|
||||
fprintf(stderr, "test test\n");
|
||||
extern void rb_zjit_init();
|
||||
rb_zjit_init();
|
||||
extern void rb_zjit_init(void *options);
|
||||
rb_zjit_init(opt->zjit);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -2339,8 +2357,9 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
|
||||
}
|
||||
#endif
|
||||
#if USE_ZJIT
|
||||
if (FEATURE_SET_P(opt->features, zjit)) {
|
||||
opt->zjit = true;
|
||||
if (FEATURE_SET_P(opt->features, zjit) && !opt->zjit) {
|
||||
extern void *rb_zjit_init_options(void);
|
||||
opt->zjit = rb_zjit_init_options();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
use crate::cruby::*;
|
||||
use crate::virtualmem::*;
|
||||
use crate::options::Options;
|
||||
|
||||
/// Block of memory into which instructions can be assembled
|
||||
pub struct CodeBlock {
|
||||
@ -111,18 +113,20 @@ impl crate::virtualmem::CodePtrBase for CodeBlock {
|
||||
pub struct ZJITState {
|
||||
/// Inline code block (fast path)
|
||||
code_block: CodeBlock,
|
||||
|
||||
/// ZJIT command-line options
|
||||
options: Options,
|
||||
}
|
||||
|
||||
/// Private singleton instance of the codegen globals
|
||||
static mut ZJIT_STATE: Option<ZJITState> = None;
|
||||
|
||||
impl ZJITState {
|
||||
/// Initialize the ZJIT globals
|
||||
pub fn init() {
|
||||
let exec_mem_size: usize = 64 * 1024 * 1024; // TODO: support the option
|
||||
|
||||
/// Initialize the ZJIT globals, given options allocated by rb_zjit_init_options()
|
||||
pub fn init(options: *const u8) {
|
||||
#[cfg(not(test))]
|
||||
let cb = {
|
||||
let exec_mem_size: usize = 64 * 1024 * 1024; // TODO: implement the option
|
||||
let virt_block: *mut u8 = unsafe { rb_zjit_reserve_addr_space(64 * 1024 * 1024) };
|
||||
|
||||
// Memory protection syscalls need page-aligned addresses, so check it here. Assuming
|
||||
@ -153,16 +157,18 @@ impl ZJITState {
|
||||
CodeBlock::new(mem_block.clone())
|
||||
};
|
||||
|
||||
#[cfg(not(test))]
|
||||
let options = unsafe { Box::from_raw(options as *mut Options) };
|
||||
#[cfg(not(test))] // TODO: can we get rid of this #[cfg]?
|
||||
{
|
||||
let zjit_state = ZJITState {
|
||||
code_block: cb,
|
||||
options: *options,
|
||||
};
|
||||
|
||||
// Initialize the codegen globals instance
|
||||
#[cfg(not(test))]
|
||||
unsafe {
|
||||
ZJIT_STATE = Some(zjit_state);
|
||||
unsafe { ZJIT_STATE = Some(zjit_state); }
|
||||
}
|
||||
mem::drop(options);
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the codegen globals instance
|
||||
@ -174,4 +180,9 @@ impl ZJITState {
|
||||
pub fn get_code_block() -> &'static mut CodeBlock {
|
||||
&mut ZJITState::get_instance().code_block
|
||||
}
|
||||
|
||||
// Get a mutable reference to the options
|
||||
pub fn get_options() -> &'static mut Options {
|
||||
&mut ZJITState::get_instance().options
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ mod virtualmem;
|
||||
mod asm;
|
||||
mod backend;
|
||||
mod disasm;
|
||||
mod options;
|
||||
|
||||
use backend::x86_emit;
|
||||
use codegen::ZJITState;
|
||||
@ -19,12 +20,13 @@ use crate::cruby::*;
|
||||
#[no_mangle]
|
||||
pub static mut rb_zjit_enabled_p: bool = false;
|
||||
|
||||
/// Initialize ZJIT, given options allocated by rb_zjit_init_options()
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rb_zjit_init() {
|
||||
pub extern "C" fn rb_zjit_init(options: *const u8) {
|
||||
// Catch panics to avoid UB for unwinding into C frames.
|
||||
// See https://doc.rust-lang.org/nomicon/exception-safety.html
|
||||
let result = std::panic::catch_unwind(|| {
|
||||
ZJITState::init();
|
||||
ZJITState::init(options);
|
||||
|
||||
rb_bug_panic_hook();
|
||||
|
||||
@ -71,12 +73,6 @@ fn rb_bug_panic_hook() {
|
||||
}));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rb_zjit_parse_option() -> bool {
|
||||
println!("parsing zjit options");
|
||||
false
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rb_zjit_iseq_gen_entry_point(iseq: IseqPtr, _ec: EcPtr) -> *const u8 {
|
||||
ir::iseq_to_ssa(iseq).unwrap();
|
||||
|
56
zjit/src/options.rs
Normal file
56
zjit/src/options.rs
Normal file
@ -0,0 +1,56 @@
|
||||
use std::{ffi::CStr, os::raw::c_char};
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Options {
|
||||
/// Dump all compiled instructions of target cb.
|
||||
pub dump_disasm: bool,
|
||||
}
|
||||
|
||||
/// Allocate Options on the heap, initialize it, and return the address of it.
|
||||
/// The return value will be modified by rb_zjit_parse_option() and then
|
||||
/// passed to rb_zjit_init() for initialization.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rb_zjit_init_options() -> *const u8 {
|
||||
let options = Options {
|
||||
dump_disasm: false,
|
||||
};
|
||||
Box::into_raw(Box::new(options)) as *const u8
|
||||
}
|
||||
|
||||
/// Parse a --zjit* command-line flag
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rb_zjit_parse_option(options: *const u8, str_ptr: *const c_char) -> bool {
|
||||
let options = unsafe { &mut *(options as *mut Options) };
|
||||
parse_option(options, str_ptr).is_some()
|
||||
}
|
||||
|
||||
/// Expected to receive what comes after the third dash in "--zjit-*".
|
||||
/// Empty string means user passed only "--zjit". C code rejects when
|
||||
/// they pass exact "--zjit-".
|
||||
fn parse_option(options: &mut Options, str_ptr: *const std::os::raw::c_char) -> Option<()> {
|
||||
let c_str: &CStr = unsafe { CStr::from_ptr(str_ptr) };
|
||||
let opt_str: &str = c_str.to_str().ok()?;
|
||||
|
||||
// Split the option name and value strings
|
||||
// Note that some options do not contain an assignment
|
||||
let parts = opt_str.split_once('=');
|
||||
let (opt_name, opt_val) = match parts {
|
||||
Some((before_eq, after_eq)) => (before_eq, after_eq),
|
||||
None => (opt_str, ""),
|
||||
};
|
||||
|
||||
// Match on the option name and value strings
|
||||
match (opt_name, opt_val) {
|
||||
("", "") => {}, // Simply --zjit
|
||||
|
||||
("dump-disasm", "") => options.dump_disasm = true,
|
||||
|
||||
// Option name not recognized
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
// Option successfully parsed
|
||||
return Some(());
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user