Optimize `WrappedFailure` userdata detection.
This is done by comparing a metatable pointer to previously saved one (it never changes).
This commit is contained in:
parent
f7ee6dc635
commit
059e41bafb
17
src/lua.rs
17
src/lua.rs
|
@ -111,6 +111,9 @@ pub(crate) struct ExtraData {
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
recycled_thread_cache: Vec<c_int>,
|
recycled_thread_cache: Vec<c_int>,
|
||||||
|
|
||||||
|
// Address of `WrappedFailure` metatable
|
||||||
|
wrapped_failure_mt_ptr: *const c_void,
|
||||||
|
|
||||||
// Index of `Option<Waker>` userdata on the ref thread
|
// Index of `Option<Waker>` userdata on the ref thread
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
ref_waker_idx: c_int,
|
ref_waker_idx: c_int,
|
||||||
|
@ -538,6 +541,13 @@ impl Lua {
|
||||||
"Error while creating ref thread",
|
"Error while creating ref thread",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let wrapped_failure_mt_ptr = {
|
||||||
|
get_gc_metatable::<WrappedFailure>(state);
|
||||||
|
let ptr = ffi::lua_topointer(state, -1);
|
||||||
|
ffi::lua_pop(state, 1);
|
||||||
|
ptr
|
||||||
|
};
|
||||||
|
|
||||||
// Create empty Waker slot on the ref thread
|
// Create empty Waker slot on the ref thread
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
let ref_waker_idx = {
|
let ref_waker_idx = {
|
||||||
|
@ -568,6 +578,7 @@ impl Lua {
|
||||||
multivalue_cache: Vec::with_capacity(MULTIVALUE_CACHE_SIZE),
|
multivalue_cache: Vec::with_capacity(MULTIVALUE_CACHE_SIZE),
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
recycled_thread_cache: Vec::new(),
|
recycled_thread_cache: Vec::new(),
|
||||||
|
wrapped_failure_mt_ptr,
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
ref_waker_idx,
|
ref_waker_idx,
|
||||||
#[cfg(not(feature = "luau"))]
|
#[cfg(not(feature = "luau"))]
|
||||||
|
@ -2293,6 +2304,8 @@ impl Lua {
|
||||||
// Uses 2 stack spaces, does not call checkstack
|
// Uses 2 stack spaces, does not call checkstack
|
||||||
pub(crate) unsafe fn pop_value(&self) -> Value {
|
pub(crate) unsafe fn pop_value(&self) -> Value {
|
||||||
let state = self.state;
|
let state = self.state;
|
||||||
|
let extra = &mut *self.extra.get();
|
||||||
|
|
||||||
match ffi::lua_type(state, -1) {
|
match ffi::lua_type(state, -1) {
|
||||||
ffi::LUA_TNIL => {
|
ffi::LUA_TNIL => {
|
||||||
ffi::lua_pop(state, 1);
|
ffi::lua_pop(state, 1);
|
||||||
|
@ -2353,9 +2366,11 @@ impl Lua {
|
||||||
ffi::LUA_TFUNCTION => Value::Function(Function(self.pop_ref())),
|
ffi::LUA_TFUNCTION => Value::Function(Function(self.pop_ref())),
|
||||||
|
|
||||||
ffi::LUA_TUSERDATA => {
|
ffi::LUA_TUSERDATA => {
|
||||||
|
let wrapped_failure_mt_ptr = extra.wrapped_failure_mt_ptr;
|
||||||
// We must prevent interaction with userdata types other than UserData OR a WrappedError.
|
// We must prevent interaction with userdata types other than UserData OR a WrappedError.
|
||||||
// WrappedPanics are automatically resumed.
|
// WrappedPanics are automatically resumed.
|
||||||
match get_gc_userdata::<WrappedFailure>(state, -1).as_mut() {
|
match get_gc_userdata::<WrappedFailure>(state, -1, wrapped_failure_mt_ptr).as_mut()
|
||||||
|
{
|
||||||
Some(WrappedFailure::Error(err)) => {
|
Some(WrappedFailure::Error(err)) => {
|
||||||
let err = err.clone();
|
let err = err.clone();
|
||||||
ffi::lua_pop(state, 1);
|
ffi::lua_pop(state, 1);
|
||||||
|
|
26
src/util.rs
26
src/util.rs
|
@ -203,7 +203,7 @@ pub unsafe fn pop_error(state: *mut ffi::lua_State, err_code: c_int) -> Error {
|
||||||
"pop_error called with non-error return code"
|
"pop_error called with non-error return code"
|
||||||
);
|
);
|
||||||
|
|
||||||
match get_gc_userdata::<WrappedFailure>(state, -1).as_mut() {
|
match get_gc_userdata::<WrappedFailure>(state, -1, ptr::null()).as_mut() {
|
||||||
Some(WrappedFailure::Error(err)) => {
|
Some(WrappedFailure::Error(err)) => {
|
||||||
ffi::lua_pop(state, 1);
|
ffi::lua_pop(state, 1);
|
||||||
err.clone()
|
err.clone()
|
||||||
|
@ -394,17 +394,29 @@ pub unsafe fn push_gc_userdata<T: Any>(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uses 2 stack spaces, does not call checkstack
|
// Uses 2 stack spaces, does not call checkstack
|
||||||
pub unsafe fn get_gc_userdata<T: Any>(state: *mut ffi::lua_State, index: c_int) -> *mut T {
|
pub unsafe fn get_gc_userdata<T: Any>(
|
||||||
|
state: *mut ffi::lua_State,
|
||||||
|
index: c_int,
|
||||||
|
mt_ptr: *const c_void,
|
||||||
|
) -> *mut T {
|
||||||
let ud = ffi::lua_touserdata(state, index) as *mut T;
|
let ud = ffi::lua_touserdata(state, index) as *mut T;
|
||||||
if ud.is_null() || ffi::lua_getmetatable(state, index) == 0 {
|
if ud.is_null() || ffi::lua_getmetatable(state, index) == 0 {
|
||||||
return ptr::null_mut();
|
return ptr::null_mut();
|
||||||
}
|
}
|
||||||
|
if !mt_ptr.is_null() {
|
||||||
|
let ud_mt_ptr = ffi::lua_topointer(state, -1);
|
||||||
|
ffi::lua_pop(state, 1);
|
||||||
|
if !ptr::eq(ud_mt_ptr, mt_ptr) {
|
||||||
|
return ptr::null_mut();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
get_gc_metatable::<T>(state);
|
get_gc_metatable::<T>(state);
|
||||||
let res = ffi::lua_rawequal(state, -1, -2);
|
let res = ffi::lua_rawequal(state, -1, -2);
|
||||||
ffi::lua_pop(state, 2);
|
ffi::lua_pop(state, 2);
|
||||||
if res == 0 {
|
if res == 0 {
|
||||||
return ptr::null_mut();
|
return ptr::null_mut();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ud
|
ud
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -679,7 +691,7 @@ pub unsafe extern "C" fn error_traceback(state: *mut ffi::lua_State) -> c_int {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if get_gc_userdata::<WrappedFailure>(state, -1).is_null() {
|
if get_gc_userdata::<WrappedFailure>(state, -1, ptr::null()).is_null() {
|
||||||
let s = ffi::luaL_tolstring(state, -1, ptr::null_mut());
|
let s = ffi::luaL_tolstring(state, -1, ptr::null_mut());
|
||||||
if ffi::lua_checkstack(state, ffi::LUA_TRACEBACK_STACK) != 0 {
|
if ffi::lua_checkstack(state, ffi::LUA_TRACEBACK_STACK) != 0 {
|
||||||
ffi::luaL_traceback(state, state, s, 0);
|
ffi::luaL_traceback(state, state, s, 0);
|
||||||
|
@ -706,7 +718,7 @@ pub unsafe extern "C" fn safe_pcall(state: *mut ffi::lua_State) -> c_int {
|
||||||
ffi::lua_gettop(state)
|
ffi::lua_gettop(state)
|
||||||
} else {
|
} else {
|
||||||
if let Some(WrappedFailure::Panic(_)) =
|
if let Some(WrappedFailure::Panic(_)) =
|
||||||
get_gc_userdata::<WrappedFailure>(state, -1).as_ref()
|
get_gc_userdata::<WrappedFailure>(state, -1, ptr::null()).as_ref()
|
||||||
{
|
{
|
||||||
ffi::lua_error(state);
|
ffi::lua_error(state);
|
||||||
}
|
}
|
||||||
|
@ -722,7 +734,7 @@ pub unsafe extern "C" fn safe_xpcall(state: *mut ffi::lua_State) -> c_int {
|
||||||
ffi::luaL_checkstack(state, 2, ptr::null());
|
ffi::luaL_checkstack(state, 2, ptr::null());
|
||||||
|
|
||||||
if let Some(WrappedFailure::Panic(_)) =
|
if let Some(WrappedFailure::Panic(_)) =
|
||||||
get_gc_userdata::<WrappedFailure>(state, -1).as_ref()
|
get_gc_userdata::<WrappedFailure>(state, -1, ptr::null()).as_ref()
|
||||||
{
|
{
|
||||||
1
|
1
|
||||||
} else {
|
} else {
|
||||||
|
@ -752,7 +764,7 @@ pub unsafe extern "C" fn safe_xpcall(state: *mut ffi::lua_State) -> c_int {
|
||||||
ffi::lua_gettop(state) - 1
|
ffi::lua_gettop(state) - 1
|
||||||
} else {
|
} else {
|
||||||
if let Some(WrappedFailure::Panic(_)) =
|
if let Some(WrappedFailure::Panic(_)) =
|
||||||
get_gc_userdata::<WrappedFailure>(state, -1).as_ref()
|
get_gc_userdata::<WrappedFailure>(state, -1, ptr::null()).as_ref()
|
||||||
{
|
{
|
||||||
ffi::lua_error(state);
|
ffi::lua_error(state);
|
||||||
}
|
}
|
||||||
|
@ -836,7 +848,7 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
|
||||||
callback_error(state, |_| {
|
callback_error(state, |_| {
|
||||||
check_stack(state, 3)?;
|
check_stack(state, 3)?;
|
||||||
|
|
||||||
let err_buf = match get_gc_userdata::<WrappedFailure>(state, -1).as_ref() {
|
let err_buf = match get_gc_userdata::<WrappedFailure>(state, -1, ptr::null()).as_ref() {
|
||||||
Some(WrappedFailure::Error(error)) => {
|
Some(WrappedFailure::Error(error)) => {
|
||||||
let err_buf_key = &ERROR_PRINT_BUFFER_KEY as *const u8 as *const c_void;
|
let err_buf_key = &ERROR_PRINT_BUFFER_KEY as *const u8 as *const c_void;
|
||||||
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, err_buf_key);
|
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, err_buf_key);
|
||||||
|
|
Loading…
Reference in New Issue