diff --git a/crates/lb/src/runtime.rs b/crates/lb/src/runtime.rs index a154a1a..d69939e 100644 --- a/crates/lb/src/runtime.rs +++ b/crates/lb/src/runtime.rs @@ -14,6 +14,7 @@ pub type ErrorFn = dyn Fn(&luajit::Error); pub struct Builder { registry: Registry, report_err: Rc, + jit_opts: Vec, prohibit_globals: bool, } @@ -25,6 +26,14 @@ impl Builder { Some(trace) => eprintln!("unhandled lua error: {err}\n{trace}"), None => eprintln!("unhandled lua error: {err}"), }), + jit_opts: vec![ + // more aggressive jit options based on OpenResty's defaults + // https://github.com/openresty/luajit2#updated-jit-default-parameters + "maxtrace=8000".into(), + "maxrecord=16000".into(), + "minstitch=3".into(), + "maxmcode=40960".into(), + ], prohibit_globals: false, } } @@ -43,6 +52,18 @@ impl Builder { self } + pub fn jit_opt(&mut self, opt: impl AsRef) -> &mut Self { + self.jit_opts.push(opt.as_ref().into()); + self + } + + pub fn jit_opts(&mut self, opts: impl IntoIterator>) -> &mut Self { + for opt in opts { + self.jit_opt(opt); + } + self + } + pub fn module(&mut self) -> &mut Self { self.registry.preload::(); self @@ -54,21 +75,11 @@ impl Builder { state.eval(&chunk, 0, Some(0))?; if self.prohibit_globals { - let mut s = state.guard(); - s.eval( - &Chunk::new(luaify_chunk!({ - return |self, key, value| { - error(("undeclared local variable '%s'").format(key), 2); - }; - })), - 0, - Some(1), - ) - .unwrap(); - s.push(NewTable::new()); - (s.push("__index"), s.push_idx(-3), s.set(-3)); - (s.push("__newindex"), s.push_idx(-3), s.set(-3)); - s.set_metatable(Index::globals()); + state_prohibit_globals(&mut state)?; + } + + for opt in self.jit_opts.iter() { + state_set_jitopt(&mut state, opt)?; } Ok(Runtime { @@ -81,6 +92,60 @@ impl Builder { } } +fn state_prohibit_globals(state: &mut State) -> luajit::Result<()> { + let mut s = state.guard(); + let chunk = Chunk::new(luaify_chunk!({ + return |self, key, value| { + error(("undeclared local variable '%s'").format(key), 2); + }; + })) + .with_path("[luby]"); + s.eval(&chunk, 0, Some(1)).unwrap(); + s.push(NewTable::new()); + (s.push("__index"), s.push_idx(-3), s.set(-3)); + (s.push("__newindex"), s.push_idx(-3), s.set(-3)); + s.set_metatable(Index::globals()); + Ok(()) +} + +fn state_set_jitopt(state: &mut State, opt: &str) -> luajit::Result<()> { + let mut s = state.guard(); + if let Some((cmd, opt)) = parse_jitlib_cmd(opt) + && let Ok(_) = s.require(format!("jit.{cmd}"), Some(1)) + { + // require("jit.{cmd}").start(opt) + (s.push("start"), s.get(-2)); + s.push(opt); + s.call(1, Some(0))?; + } else { + s.require("jit", Some(1)).unwrap(); + match opt { + cmd @ ("on" | "off" | "flush") => { + // require("jit").() + (s.push(cmd), s.get(-2)); + s.call(0, Some(0))?; + } + _ => { + // require("jit").opt.start(opt) + (s.push("opt"), s.get(-2)); + (s.push("start"), s.get(-2)); + s.push(opt); + s.call(1, Some(0))?; + } + } + } + Ok(()) +} + +fn parse_jitlib_cmd(cmd: &str) -> Option<(&str, &str)> { + match cmd { + "p" => Some(("p", "Flspv10")), // default -jp flags + "v" => Some(("v", "-")), // default -jv flags + "dump" => Some(("dump", "tirs")), // default -jdump flags + _ => cmd.split_once('='), + } +} + #[derive(Deref, DerefMut)] pub struct Runtime { #[deref] diff --git a/src/main.rs b/src/main.rs index 85d2ad1..263f148 100644 --- a/src/main.rs +++ b/src/main.rs @@ -231,60 +231,18 @@ fn init_tokio(args: &Args) -> tokio::runtime::Runtime { } fn init_lua(args: &Args) -> lb::runtime::Runtime { - let mut rt = { - let mut rt = lb::runtime::Builder::new(); - luby::open(&mut rt); + let mut rt = lb::runtime::Builder::new(); + luby::open(&mut rt); - if args.dump.iter().find(|s| *s == "cdef").is_some() { - print!("{}", rt.registry()); // for cdef debugging - } - - rt.unhandled_error(error_cb) - .prohibit_globals(!args.allow_globals) - .build() - .unwrap() - }; - - for arg in args.jit.iter() { - let mut s = rt.guard(); - let res = if let Some((cmd, flags)) = parse_jitlib_cmd(arg) - && let Ok(_) = s.require(format!("jit.{cmd}"), Some(1)) - { - (s.push("start"), s.get(-2)); - s.push(flags); - s.call(1, Some(0)) // require("jit.{cmd}").start(flags) - } else { - s.require("jit", Some(1)).unwrap(); - match arg.as_str() { - cmd @ ("on" | "off" | "flush") => { - (s.push(cmd), s.get(-2)); - s.call(0, Some(0)) // require("jit").[on/off/flush]() - } - flags => { - (s.push("opt"), s.get(-2)); - (s.push("start"), s.get(-2)); - s.push(flags); - s.call(1, Some(0)) // require("jit").opt.start(flags) - } - } - }; - - if let Err(err) = res { - drop(s); - rt.report_error(&err); - } + if args.dump.iter().find(|s| *s == "cdef").is_some() { + print!("{}", rt.registry()); // for cdef debugging } - rt -} - -fn parse_jitlib_cmd(s: &str) -> Option<(&str, &str)> { - match s { - "p" => Some(("p", "Flspv10")), // default -jp flags - "v" => Some(("v", "-")), // default -jv flags - "dump" => Some(("dump", "tirs")), // default -jdump flags - _ => s.split_once('='), - } + rt.unhandled_error(error_cb) + .prohibit_globals(!args.allow_globals) + .jit_opts(args.jit.iter()) + .build() + .unwrap() } async fn main_async(args: Args, cx: &mut lb::runtime::Context) -> ExitCode {