From e71d618d10c7097c99b243de9540c050ec461eec Mon Sep 17 00:00:00 2001 From: luaneko Date: Wed, 25 Jun 2025 14:27:43 +1000 Subject: [PATCH] Add luajit v,p,dump command support --- Cargo.lock | 8 ++++ Cargo.toml | 1 + crates/lb/Cargo.toml | 1 + src/main.rs | 105 ++++++++++++++++++++++++++++++++----------- 4 files changed, 88 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 14937aa..5d5812d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -800,6 +800,7 @@ dependencies = [ "luaffi", "luaify", "luajit", + "sysexits", "tokio", ] @@ -911,6 +912,7 @@ dependencies = [ "luajit", "mimalloc", "owo-colors", + "sysexits", "tokio", "tracing", "tracing-subscriber", @@ -1403,6 +1405,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +[[package]] +name = "sysexits" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "198f60d1f7f003f168507691e42d082df109ef0f05c6fd006e22528371a5f1b4" + [[package]] name = "thiserror" version = "2.0.12" diff --git a/Cargo.toml b/Cargo.toml index 43ade95..bc56d45 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ lb = { version = "0.1.0", path = "crates/lb" } luajit = { version = "0.1.0", path = "crates/luajit", features = ["runtime"] } mimalloc = "0.1.47" owo-colors = "4.2.1" +sysexits = "0.9.0" tokio = { version = "1.45.1", features = ["full", "tracing"] } tracing = "0.1.41" tracing-subscriber = "0.3.19" diff --git a/crates/lb/Cargo.toml b/crates/lb/Cargo.toml index 1d1bf7c..6dce9fc 100644 --- a/crates/lb/Cargo.toml +++ b/crates/lb/Cargo.toml @@ -8,6 +8,7 @@ camino = "1.1.10" derive_more = { version = "2.0.1", features = ["full"] } luaffi = { version = "0.1.0", path = "../luaffi" } luajit = { version = "0.1.0", path = "../luajit" } +sysexits = "0.9.0" tokio = { version = "1.45.1", features = ["rt", "time", "fs", "net", "process", "signal"] } [dev-dependencies] diff --git a/src/main.rs b/src/main.rs index c4c0247..40b65c2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,8 @@ use clap::Parser; use mimalloc::MiMalloc; use owo_colors::OwoColorize; -use std::{backtrace::Backtrace, net::SocketAddr, num::NonZero, panic, process::ExitCode, thread}; +use std::{backtrace::Backtrace, fmt::Display, net::SocketAddr, num::NonZero, panic, thread}; +use sysexits::ExitCode; #[global_allocator] static GLOBAL: MiMalloc = MiMalloc; @@ -29,8 +30,8 @@ fn panic_cb(panic: &panic::PanicHookInfo) { eprintln!( "{}", - "This is a bug in luby! Please kindly report this at https://git.lua.re/luaneko/luby." - .red() + "This is a bug in luby. Please kindly report this at https://git.lua.re/luaneko/luby." + .yellow() ); } @@ -38,25 +39,29 @@ fn panic_cb(panic: &panic::PanicHookInfo) { struct Args { /// Paths to scripts to execute. #[clap(value_name = "SCRIPTS")] - paths: Vec, + path: Vec, /// Strings to execute. #[clap(long, short = 'e', value_name = "CHUNK")] - evals: Vec, + eval: Vec, /// Libraries to require on startup. #[clap(long, short = 'l', value_name = "NAME")] - libs: Vec, + lib: Vec, /// Console log level. #[clap(long, value_name = "LEVEL", default_value = "debug")] - log_level: tracing::Level, + log: tracing::Level, - /// Number of runtime worker threads. + /// LuaJIT control commands. + #[clap(long, short = 'j', value_name = "CMD=FLAGS")] + jit: Vec, + + /// Number of tokio worker threads. #[clap(long, value_name = "THREADS", default_value_t = Self::threads())] threads: NonZero, - /// Number of runtime blocking threads. + /// Number of tokio blocking threads. #[clap(long, value_name = "THREADS", default_value_t = Self::blocking_threads())] blocking_threads: NonZero, @@ -65,7 +70,12 @@ struct Args { enable_console: bool, /// tokio-console publish address. - #[clap(long, value_name = "ADDRESS", default_value = "127.0.0.1:6669")] + #[clap( + long, + value_name = "ADDRESS", + default_value = "127.0.0.1:6669", + requires = "enable_console" + )] console_addr: SocketAddr, } @@ -79,7 +89,14 @@ impl Args { } } -fn main() -> ExitCode { +fn exit_err(code: ExitCode) -> impl FnOnce(E) -> T { + move |err| { + eprintln!("{}", err.red()); + code.exit() + } +} + +fn main() -> Result<(), ExitCode> { panic::set_hook(Box::new(panic_cb)); let args = Args::parse(); @@ -91,7 +108,7 @@ fn main() -> ExitCode { tokio.block_on(async { lua.await; - main.await.unwrap_or_else(|err| panic!("{err}")) + main.await.unwrap() }) } @@ -103,7 +120,7 @@ fn init_logger(args: &Args) { .compact() .with_env_filter( tracing_subscriber::EnvFilter::builder() - .with_default_directive(LevelFilter::from(args.log_level).into()) + .with_default_directive(LevelFilter::from(args.log).into()) .from_env_lossy(), ) .with_file(false) @@ -137,38 +154,72 @@ fn init_tokio(args: &Args) -> tokio::runtime::Runtime { .thread_name("luby") .max_blocking_threads(args.blocking_threads.get()) .build() - .expect("failed to initialise runtime") + .unwrap_or_else(exit_err(ExitCode::OsErr)) } -fn init_lua(_args: &Args) -> lb::runtime::Runtime { +fn init_lua(args: &Args) -> lb::runtime::Runtime { let rt = lb::runtime::Builder::new(); - rt.build().expect("failed to initialise runtime") + let mut rt = rt.build().unwrap_or_else(exit_err(ExitCode::Software)); + + for arg in args.jit.iter() { + let mut s = rt.guard(); + if let Some((cmd, flags)) = parse_jitlib_cmd(arg) + && let Ok(_) = s.require(format!("jit.{cmd}"), 1) + { + (s.push("start"), s.get(-2), s.push(flags)); + s.call(1, 0) + } else { + s.require("jit", 1).unwrap(); + match arg.as_str() { + cmd @ ("on" | "off" | "flush") => { + (s.push(cmd), s.get(-2)); + s.call(0, 0) + } + arg => { + (s.push("opt"), s.get(-2)); + (s.push("start"), s.get(-2), s.push(arg)); + s.call(1, 0) + } + } + } + .unwrap_or_else(exit_err(ExitCode::Usage)); + } + + rt } -async fn main_async(args: Args, state: &mut luajit::State) -> ExitCode { - for ref path in args.paths { +fn parse_jitlib_cmd(s: &str) -> Option<(&str, &str)> { + match s { + "p" => Some(("p", "Flspv10")), + "v" => Some(("v", "-")), + "dump" => Some(("dump", "tirs")), + _ => s.split_once('='), + } +} + +async fn main_async(args: Args, state: &mut luajit::State) -> Result<(), ExitCode> { + for ref path in args.path { + let mut s = state.guard(); let chunk = match std::fs::read(path) { Ok(chunk) => chunk, Err(err) => { - eprintln!("{}", format_args!("{path}: {err}").red()); // read file error - return ExitCode::FAILURE; + eprintln!("{}", format_args!("{path}: {err}").red()); + ExitCode::NoInput.exit(); } }; - if let Err(err) = state.load(&luajit::Chunk::new(chunk).path(path)) { - eprintln!("{}", err.red()); // syntax error - return ExitCode::FAILURE; - } + s.load(&luajit::Chunk::new(chunk).path(path)) + .unwrap_or_else(exit_err(ExitCode::NoInput)); - if let Err(err) = state.call_async(0, 0).await { + if let Err(err) = s.call_async(0, 0).await { match err.trace() { Some(trace) => eprintln!("{}\n{trace}", err.red()), // runtime error None => eprintln!("{}", err.red()), } - return ExitCode::FAILURE; + ExitCode::DataErr.exit(); } } - ExitCode::SUCCESS + Ok(()) }