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;
|
ruby_features_t warn;
|
||||||
unsigned int dump;
|
unsigned int dump;
|
||||||
long backtrace_length_limit;
|
long backtrace_length_limit;
|
||||||
|
#if USE_ZJIT
|
||||||
|
void *zjit;
|
||||||
|
#endif
|
||||||
|
|
||||||
const char *crash_report;
|
const char *crash_report;
|
||||||
|
|
||||||
@ -39,7 +42,6 @@ typedef struct ruby_cmdline_options {
|
|||||||
#if USE_YJIT
|
#if USE_YJIT
|
||||||
unsigned int yjit: 1;
|
unsigned int yjit: 1;
|
||||||
#endif
|
#endif
|
||||||
unsigned int zjit: 1;
|
|
||||||
} ruby_cmdline_options_t;
|
} ruby_cmdline_options_t;
|
||||||
|
|
||||||
struct ruby_opt_message {
|
struct ruby_opt_message {
|
||||||
|
33
ruby.c
33
ruby.c
@ -1184,6 +1184,21 @@ setup_yjit_options(const char *s)
|
|||||||
}
|
}
|
||||||
#endif
|
#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:
|
* 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
|
#endif
|
||||||
}
|
}
|
||||||
else if (is_option_with_optarg("zjit", '-', true, false, false)) {
|
else if (is_option_with_optarg("zjit", '-', true, false, false)) {
|
||||||
|
#if USE_ZJIT
|
||||||
FEATURE_SET(opt->features, FEATURE_BIT(zjit));
|
FEATURE_SET(opt->features, FEATURE_BIT(zjit));
|
||||||
extern bool rb_zjit_parse_option();
|
setup_zjit_options(opt, s);
|
||||||
rb_zjit_parse_option();
|
#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) {
|
else if (strcmp("yydebug", s) == 0) {
|
||||||
if (envopt) goto noenvopt_long;
|
if (envopt) goto noenvopt_long;
|
||||||
@ -1799,9 +1818,8 @@ ruby_opt_init(ruby_cmdline_options_t *opt)
|
|||||||
#endif
|
#endif
|
||||||
#if USE_ZJIT
|
#if USE_ZJIT
|
||||||
if (opt->zjit) {
|
if (opt->zjit) {
|
||||||
fprintf(stderr, "test test\n");
|
extern void rb_zjit_init(void *options);
|
||||||
extern void rb_zjit_init();
|
rb_zjit_init(opt->zjit);
|
||||||
rb_zjit_init();
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -2339,8 +2357,9 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if USE_ZJIT
|
#if USE_ZJIT
|
||||||
if (FEATURE_SET_P(opt->features, zjit)) {
|
if (FEATURE_SET_P(opt->features, zjit) && !opt->zjit) {
|
||||||
opt->zjit = true;
|
extern void *rb_zjit_init_options(void);
|
||||||
|
opt->zjit = rb_zjit_init_options();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
|
use std::mem;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use crate::cruby::*;
|
use crate::cruby::*;
|
||||||
use crate::virtualmem::*;
|
use crate::virtualmem::*;
|
||||||
|
use crate::options::Options;
|
||||||
|
|
||||||
/// Block of memory into which instructions can be assembled
|
/// Block of memory into which instructions can be assembled
|
||||||
pub struct CodeBlock {
|
pub struct CodeBlock {
|
||||||
@ -111,18 +113,20 @@ impl crate::virtualmem::CodePtrBase for CodeBlock {
|
|||||||
pub struct ZJITState {
|
pub struct ZJITState {
|
||||||
/// Inline code block (fast path)
|
/// Inline code block (fast path)
|
||||||
code_block: CodeBlock,
|
code_block: CodeBlock,
|
||||||
|
|
||||||
|
/// ZJIT command-line options
|
||||||
|
options: Options,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Private singleton instance of the codegen globals
|
/// Private singleton instance of the codegen globals
|
||||||
static mut ZJIT_STATE: Option<ZJITState> = None;
|
static mut ZJIT_STATE: Option<ZJITState> = None;
|
||||||
|
|
||||||
impl ZJITState {
|
impl ZJITState {
|
||||||
/// Initialize the ZJIT globals
|
/// Initialize the ZJIT globals, given options allocated by rb_zjit_init_options()
|
||||||
pub fn init() {
|
pub fn init(options: *const u8) {
|
||||||
let exec_mem_size: usize = 64 * 1024 * 1024; // TODO: support the option
|
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
let cb = {
|
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) };
|
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
|
// Memory protection syscalls need page-aligned addresses, so check it here. Assuming
|
||||||
@ -153,16 +157,18 @@ impl ZJITState {
|
|||||||
CodeBlock::new(mem_block.clone())
|
CodeBlock::new(mem_block.clone())
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(test))]
|
let options = unsafe { Box::from_raw(options as *mut Options) };
|
||||||
let zjit_state = ZJITState {
|
#[cfg(not(test))] // TODO: can we get rid of this #[cfg]?
|
||||||
code_block: cb,
|
{
|
||||||
};
|
let zjit_state = ZJITState {
|
||||||
|
code_block: cb,
|
||||||
|
options: *options,
|
||||||
|
};
|
||||||
|
|
||||||
// Initialize the codegen globals instance
|
// 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
|
/// Get a mutable reference to the codegen globals instance
|
||||||
@ -174,4 +180,9 @@ impl ZJITState {
|
|||||||
pub fn get_code_block() -> &'static mut CodeBlock {
|
pub fn get_code_block() -> &'static mut CodeBlock {
|
||||||
&mut ZJITState::get_instance().code_block
|
&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 asm;
|
||||||
mod backend;
|
mod backend;
|
||||||
mod disasm;
|
mod disasm;
|
||||||
|
mod options;
|
||||||
|
|
||||||
use backend::x86_emit;
|
use backend::x86_emit;
|
||||||
use codegen::ZJITState;
|
use codegen::ZJITState;
|
||||||
@ -19,12 +20,13 @@ use crate::cruby::*;
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub static mut rb_zjit_enabled_p: bool = false;
|
pub static mut rb_zjit_enabled_p: bool = false;
|
||||||
|
|
||||||
|
/// Initialize ZJIT, given options allocated by rb_zjit_init_options()
|
||||||
#[no_mangle]
|
#[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.
|
// Catch panics to avoid UB for unwinding into C frames.
|
||||||
// See https://doc.rust-lang.org/nomicon/exception-safety.html
|
// See https://doc.rust-lang.org/nomicon/exception-safety.html
|
||||||
let result = std::panic::catch_unwind(|| {
|
let result = std::panic::catch_unwind(|| {
|
||||||
ZJITState::init();
|
ZJITState::init(options);
|
||||||
|
|
||||||
rb_bug_panic_hook();
|
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]
|
#[no_mangle]
|
||||||
pub extern "C" fn rb_zjit_iseq_gen_entry_point(iseq: IseqPtr, _ec: EcPtr) -> *const u8 {
|
pub extern "C" fn rb_zjit_iseq_gen_entry_point(iseq: IseqPtr, _ec: EcPtr) -> *const u8 {
|
||||||
ir::iseq_to_ssa(iseq).unwrap();
|
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