From c36808b25191c8367093b8802433e9aede410e45 Mon Sep 17 00:00:00 2001 From: Alex Orlenko Date: Fri, 1 Dec 2023 11:59:56 +0000 Subject: [PATCH 1/8] Faster `Function::call()` for lua51/jit/luau --- src/function.rs | 7 +++---- src/lua.rs | 31 +++++++++++++++++++++++++++---- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/function.rs b/src/function.rs index bc9416f9..7182b4a3 100644 --- a/src/function.rs +++ b/src/function.rs @@ -6,12 +6,11 @@ use std::slice; use crate::error::{Error, Result}; use crate::lua::Lua; -use crate::memory::MemoryState; use crate::table::Table; use crate::types::{Callback, LuaRef, MaybeSend}; use crate::util::{ - assert_stack, check_stack, error_traceback, linenumber_to_usize, pop_error, ptr_to_lossy_str, - ptr_to_str, StackGuard, + assert_stack, check_stack, linenumber_to_usize, pop_error, ptr_to_lossy_str, ptr_to_str, + StackGuard, }; use crate::value::{FromLuaMulti, IntoLua, IntoLuaMulti, Value}; @@ -131,7 +130,7 @@ impl<'lua> Function<'lua> { check_stack(state, 2)?; // Push error handler - MemoryState::relax_limit_with(state, || ffi::lua_pushcfunction(state, error_traceback)); + lua.push_error_traceback(); let stack_start = ffi::lua_gettop(state); // Push function and the arguments lua.push_ref(&self.0); diff --git a/src/lua.rs b/src/lua.rs index e56f77ec..9127e8eb 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -31,10 +31,10 @@ use crate::types::{ use crate::userdata::{AnyUserData, MetaMethod, UserData, UserDataCell}; use crate::userdata_impl::{UserDataProxy, UserDataRegistry}; use crate::util::{ - self, assert_stack, check_stack, get_destructed_userdata_metatable, get_gc_metatable, - get_gc_userdata, get_main_state, get_userdata, init_error_registry, init_gc_metatable, - init_userdata_metatable, pop_error, push_gc_userdata, push_string, push_table, rawset_field, - safe_pcall, safe_xpcall, short_type_name, StackGuard, WrappedFailure, + self, assert_stack, check_stack, error_traceback, get_destructed_userdata_metatable, + get_gc_metatable, get_gc_userdata, get_main_state, get_userdata, init_error_registry, + init_gc_metatable, init_userdata_metatable, pop_error, push_gc_userdata, push_string, + push_table, rawset_field, safe_pcall, safe_xpcall, short_type_name, StackGuard, WrappedFailure, }; use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, MultiValue, Nil, Value}; @@ -499,6 +499,13 @@ impl Lua { ptr }; + // Store `error_traceback` function on the ref stack + #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))] + { + ffi::lua_pushcfunction(ref_thread, error_traceback); + assert_eq!(ffi::lua_gettop(ref_thread), ExtraData::ERROR_TRACEBACK_IDX); + } + // Create ExtraData let extra = Arc::new(UnsafeCell::new(ExtraData { inner: MaybeUninit::uninit(), @@ -2601,6 +2608,16 @@ impl Lua { LuaRef::new(self, index) } + #[inline] + pub(crate) unsafe fn push_error_traceback(&self) { + let state = self.state(); + #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))] + ffi::lua_xpush(self.ref_thread(), state, ExtraData::ERROR_TRACEBACK_IDX); + // Lua 5.2+ support light C functions that does not require extra allocations + #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] + ffi::lua_pushcfunction(state, error_traceback); + } + unsafe fn register_userdata_metatable<'lua, T: 'static>( &'lua self, mut registry: UserDataRegistry<'lua, T>, @@ -3211,6 +3228,12 @@ impl LuaInner { } } +impl ExtraData { + // Index of `error_traceback` function in auxiliary thread stack + #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))] + const ERROR_TRACEBACK_IDX: c_int = 1; +} + struct StateGuard<'a>(&'a LuaInner, *mut ffi::lua_State); impl<'a> StateGuard<'a> { From 642201a7e09f01092ca760821bee849dc94f8094 Mon Sep 17 00:00:00 2001 From: Alex Orlenko Date: Fri, 1 Dec 2023 18:11:06 +0000 Subject: [PATCH 2/8] Remove locals from __mlua_async_poll helper --- src/lua.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lua.rs b/src/lua.rs index 9127e8eb..e677dacf 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -3030,7 +3030,6 @@ impl Lua { self.load( r#" local poll = get_poll(...) - local pending, yield, unpack = pending, yield, unpack while true do local nres, res, res2 = poll() if nres ~= nil then From e4d6e9228785a603aeb1edfddbd62feac4031b7e Mon Sep 17 00:00:00 2001 From: Alex Orlenko Date: Sat, 2 Dec 2023 15:01:40 +0000 Subject: [PATCH 3/8] (async) Move "pending" poll value from env to poll_future() results --- src/lua.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/lua.rs b/src/lua.rs index e677dacf..13c348c0 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -2961,11 +2961,15 @@ impl Lua { let fut = &mut (*upvalue).data; let mut ctx = Context::from_waker(lua.waker()); match fut.as_mut().poll(&mut ctx) { - Poll::Pending => Ok(0), + Poll::Pending => { + ffi::lua_pushnil(state); + let pending = &ASYNC_POLL_PENDING as *const u8 as *mut c_void; + ffi::lua_pushlightuserdata(state, pending); + Ok(2) + } Poll::Ready(nresults) => { - let nresults = nresults?; - match nresults { - 0..=2 => { + match nresults? { + nresults @ 0..=2 => { // Fast path for up to 2 results without creating a table ffi::lua_pushinteger(state, nresults as _); if nresults > 0 { @@ -2973,7 +2977,7 @@ impl Lua { } Ok(nresults + 1) } - _ => { + nresults => { let results = MultiValue::from_stack_multi(nresults, lua)?; ffi::lua_pushinteger(state, nresults as _); lua.push_value(Value::Table(lua.create_sequence_from(results)?))?; @@ -3017,15 +3021,13 @@ impl Lua { let coroutine = self.globals().get::<_, Table>("coroutine")?; - let env = self.create_table_with_capacity(0, 4)?; + let env = self.create_table_with_capacity(0, 3)?; env.set("get_poll", get_poll)?; + // Cache `yield` function env.set("yield", coroutine.get::<_, Function>("yield")?)?; unsafe { env.set("unpack", self.create_c_function(unpack)?)?; } - env.set("pending", { - LightUserData(&ASYNC_POLL_PENDING as *const u8 as *mut c_void) - })?; self.load( r#" @@ -3043,7 +3045,7 @@ impl Lua { return unpack(res, nres) end end - yield(pending) + yield(res) -- `res` is a "pending" value end "#, ) From a4c919231c5bbd6ad65b419b7f08d5976272c288 Mon Sep 17 00:00:00 2001 From: Alex Orlenko Date: Sun, 3 Dec 2023 19:55:27 +0000 Subject: [PATCH 4/8] Don't clone function name when calling async userdata method --- src/userdata_impl.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/userdata_impl.rs b/src/userdata_impl.rs index 8692a4cd..97807586 100644 --- a/src/userdata_impl.rs +++ b/src/userdata_impl.rs @@ -218,7 +218,7 @@ impl<'lua, T: 'static> UserDataRegistry<'lua, T> { MR: Future> + 's, R: IntoLuaMulti<'lua>, { - let name = get_function_name::(name); + let name = Arc::new(get_function_name::(name)); let method = Arc::new(method); Box::new(move |lua, mut args| unsafe { @@ -312,7 +312,7 @@ impl<'lua, T: 'static> UserDataRegistry<'lua, T> { MR: Future> + 's, R: IntoLuaMulti<'lua>, { - let name = get_function_name::(name); + let name = Arc::new(get_function_name::(name)); let method = Arc::new(method); Box::new(move |lua, mut args| unsafe { From b16f3895a0d14b1ef80c9c0f07b97f990f124c32 Mon Sep 17 00:00:00 2001 From: Peter Marheine Date: Wed, 6 Dec 2023 21:09:25 +1100 Subject: [PATCH 5/8] lua54: use changed return type for lua_rawlen Lua 5.4 changed lua_rawlen to return lua_Unsigned, versus size_t in earlier versions. Change the C API signature to match, and add a wrapper function with the same name that maintains a stable Rust API by casting to usize. --- mlua-sys/src/lua54/lua.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mlua-sys/src/lua54/lua.rs b/mlua-sys/src/lua54/lua.rs index 66633bb3..7eab2af2 100644 --- a/mlua-sys/src/lua54/lua.rs +++ b/mlua-sys/src/lua54/lua.rs @@ -149,13 +149,20 @@ extern "C-unwind" { pub fn lua_tointegerx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Integer; pub fn lua_toboolean(L: *mut lua_State, idx: c_int) -> c_int; pub fn lua_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char; - pub fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize; + #[link_name = "lua_rawlen"] + fn lua_rawlen_(L: *mut lua_State, idx: c_int) -> lua_Unsigned; pub fn lua_tocfunction(L: *mut lua_State, idx: c_int) -> Option; pub fn lua_touserdata(L: *mut lua_State, idx: c_int) -> *mut c_void; pub fn lua_tothread(L: *mut lua_State, idx: c_int) -> *mut lua_State; pub fn lua_topointer(L: *mut lua_State, idx: c_int) -> *const c_void; } +// lua_rawlen's return type changed from size_t to lua_Unsigned int in Lua 5.4. +// This adapts the crate API to the new Lua ABI. +pub unsafe fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize { + lua_rawlen_(L, idx) as usize +} + // // Comparison and arithmetic functions // From e3f34f319cc9eb5cc4f87074a313f98c1dff70ca Mon Sep 17 00:00:00 2001 From: Peter Marheine Date: Wed, 6 Dec 2023 21:16:52 +1100 Subject: [PATCH 6/8] Correct C return type for lua_error The definition of lua_error in all of Lua 5.1 through 5.4 says lua_error returns int, but the Rust definition of the same function treats it as void (because it's known not to return). This causes link-time errors when building for wasm targets because the wasm linker is aware of function return types and errors out if they differ between definition and declaration. --- mlua-sys/src/lua51/lua.rs | 11 ++++++++++- mlua-sys/src/lua52/lua.rs | 11 ++++++++++- mlua-sys/src/lua53/lua.rs | 11 ++++++++++- mlua-sys/src/lua54/lua.rs | 11 ++++++++++- 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/mlua-sys/src/lua51/lua.rs b/mlua-sys/src/lua51/lua.rs index 925e9c7f..5cd351d8 100644 --- a/mlua-sys/src/lua51/lua.rs +++ b/mlua-sys/src/lua51/lua.rs @@ -228,13 +228,22 @@ extern "C-unwind" { // #[cfg_attr(all(windows, raw_dylib), link(name = "lua51", kind = "raw-dylib"))] extern "C-unwind" { - pub fn lua_error(L: *mut lua_State) -> !; + #[link_name = "lua_error"] + fn lua_error_(L: *mut lua_State) -> c_int; pub fn lua_next(L: *mut lua_State, idx: c_int) -> c_int; pub fn lua_concat(L: *mut lua_State, n: c_int); pub fn lua_getallocf(L: *mut lua_State, ud: *mut *mut c_void) -> lua_Alloc; pub fn lua_setallocf(L: *mut lua_State, f: lua_Alloc, ud: *mut c_void); } +// lua_error does not return but is declared to return int, and Rust translates +// ! to void which can cause link-time errors if the platform linker is aware +// of return types and requires they match (for example: wasm does this). +pub unsafe fn lua_error(L: *mut lua_State) -> ! { + lua_error_(L); + unreachable!(); +} + // // Some useful macros (implemented as Rust functions) // diff --git a/mlua-sys/src/lua52/lua.rs b/mlua-sys/src/lua52/lua.rs index 760140b7..d668d678 100644 --- a/mlua-sys/src/lua52/lua.rs +++ b/mlua-sys/src/lua52/lua.rs @@ -308,7 +308,8 @@ extern "C-unwind" { // // Miscellaneous functions // - pub fn lua_error(L: *mut lua_State) -> !; + #[link_name = "lua_error"] + fn lua_error_(L: *mut lua_State) -> c_int; pub fn lua_next(L: *mut lua_State, idx: c_int) -> c_int; pub fn lua_concat(L: *mut lua_State, n: c_int); pub fn lua_len(L: *mut lua_State, idx: c_int); @@ -316,6 +317,14 @@ extern "C-unwind" { pub fn lua_setallocf(L: *mut lua_State, f: lua_Alloc, ud: *mut c_void); } +// lua_error does not return but is declared to return int, and Rust translates +// ! to void which can cause link-time errors if the platform linker is aware +// of return types and requires they match (for example: wasm does this). +pub unsafe fn lua_error(L: *mut lua_State) -> ! { + lua_error_(L); + unreachable!(); +} + // // Some useful macros (implemented as Rust functions) // diff --git a/mlua-sys/src/lua53/lua.rs b/mlua-sys/src/lua53/lua.rs index d918de48..393ff3c7 100644 --- a/mlua-sys/src/lua53/lua.rs +++ b/mlua-sys/src/lua53/lua.rs @@ -314,7 +314,8 @@ extern "C-unwind" { // // Miscellaneous functions // - pub fn lua_error(L: *mut lua_State) -> !; + #[link_name = "lua_error"] + fn lua_error_(L: *mut lua_State) -> c_int; pub fn lua_next(L: *mut lua_State, idx: c_int) -> c_int; pub fn lua_concat(L: *mut lua_State, n: c_int); pub fn lua_len(L: *mut lua_State, idx: c_int); @@ -323,6 +324,14 @@ extern "C-unwind" { pub fn lua_setallocf(L: *mut lua_State, f: lua_Alloc, ud: *mut c_void); } +// lua_error does not return but is declared to return int, and Rust translates +// ! to void which can cause link-time errors if the platform linker is aware +// of return types and requires they match (for example: wasm does this). +pub unsafe fn lua_error(L: *mut lua_State) -> ! { + lua_error_(L); + unreachable!(); +} + // // Some useful macros (implemented as Rust functions) // diff --git a/mlua-sys/src/lua54/lua.rs b/mlua-sys/src/lua54/lua.rs index 7eab2af2..b1348661 100644 --- a/mlua-sys/src/lua54/lua.rs +++ b/mlua-sys/src/lua54/lua.rs @@ -343,7 +343,8 @@ extern "C-unwind" { // // Miscellaneous functions // - pub fn lua_error(L: *mut lua_State) -> !; + #[link_name = "lua_error"] + fn lua_error_(L: *mut lua_State) -> c_int; pub fn lua_next(L: *mut lua_State, idx: c_int) -> c_int; pub fn lua_concat(L: *mut lua_State, n: c_int); pub fn lua_len(L: *mut lua_State, idx: c_int); @@ -355,6 +356,14 @@ extern "C-unwind" { pub fn lua_closeslot(L: *mut lua_State, idx: c_int); } +// lua_error does not return but is declared to return int, and Rust translates +// ! to void which can cause link-time errors if the platform linker is aware +// of return types and requires they match (for example: wasm does this). +pub unsafe fn lua_error(L: *mut lua_State) -> ! { + lua_error_(L); + unreachable!(); +} + // // Some useful macros (implemented as Rust functions) // From 4c9258020182b8c17c8e4479577937618e0ba938 Mon Sep 17 00:00:00 2001 From: eatradish Date: Fri, 8 Dec 2023 11:16:52 +0800 Subject: [PATCH 7/8] Add loongarch64 architecture support --- mlua-sys/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/mlua-sys/src/lib.rs b/mlua-sys/src/lib.rs index 72a2fed5..48225e22 100644 --- a/mlua-sys/src/lib.rs +++ b/mlua-sys/src/lib.rs @@ -65,6 +65,7 @@ pub const SYS_MIN_ALIGN: usize = 8; target_arch = "sparc64", target_arch = "riscv64", target_arch = "wasm64", + target_arch = "loongarch64", ))] #[doc(hidden)] pub const SYS_MIN_ALIGN: usize = 16; From 61e846326c78ffa77601a55eb68136ce7d3dfbc0 Mon Sep 17 00:00:00 2001 From: Joel Natividad <1980690+jqnatividad@users.noreply.github.com> Date: Sun, 10 Dec 2023 12:04:37 -0500 Subject: [PATCH 8/8] Update Cargo.toml (#342) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index dd34daa7..4750c955 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ num-traits = { version = "0.2.14" } rustc-hash = "1.0" futures-util = { version = "0.3", optional = true, default-features = false, features = ["std"] } serde = { version = "1.0", optional = true } -erased-serde = { version = "0.3", optional = true } +erased-serde = { version = "0.4", optional = true } serde-value = { version = "0.7", optional = true } parking_lot = { version = "0.12", optional = true }