Move away from metatable hashmap cache to direct keys

This commit is contained in:
Alex Orlenko 2021-07-08 15:37:18 +01:00
parent 84fe5f7f76
commit adbc9ccc9b
No known key found for this signature in database
GPG Key ID: 4C150C250863B96D
3 changed files with 96 additions and 84 deletions

View File

@ -27,10 +27,10 @@ use crate::userdata::{
}; };
use crate::util::{ use crate::util::{
self, assert_stack, callback_error, check_stack, get_destructed_userdata_metatable, self, assert_stack, callback_error, check_stack, get_destructed_userdata_metatable,
get_gc_metatable_for, get_gc_userdata, get_main_state, get_userdata, get_wrapped_error, get_gc_metatable, get_gc_userdata, get_main_state, get_userdata, get_wrapped_error,
init_error_registry, init_gc_metatable_for, init_userdata_metatable, pop_error, init_error_registry, init_gc_metatable, init_userdata_metatable, pop_error, push_gc_userdata,
push_gc_userdata, push_string, push_table, push_userdata, push_wrapped_error, rawset_field, push_string, push_table, push_userdata, push_wrapped_error, rawset_field, safe_pcall,
safe_pcall, safe_xpcall, StackGuard, WrappedError, WrappedPanic, safe_xpcall, StackGuard, WrappedError, WrappedPanic, WRAPPED_ERROR_MT, WRAPPED_PANIC_MT,
}; };
use crate::value::{FromLua, FromLuaMulti, MultiValue, Nil, ToLua, ToLuaMulti, Value}; use crate::value::{FromLua, FromLuaMulti, MultiValue, Nil, ToLua, ToLuaMulti, Value};
@ -148,11 +148,24 @@ impl LuaOptions {
} }
} }
static CALLBACK_MT: u8 = 0;
static CALLBACK_UPVALUE_MT: u8 = 0;
static EXTRA_MT: u8 = 0;
pub(crate) static EXTRA_REGISTRY_KEY: u8 = 0;
#[cfg(feature = "async")] #[cfg(feature = "async")]
pub(crate) static ASYNC_POLL_PENDING: u8 = 0; static ASYNC_CALLBACK_MT: u8 = 0;
#[cfg(feature = "async")]
static ASYNC_CALLBACK_UPVALUE_MT: u8 = 0;
#[cfg(feature = "async")]
static ASYNC_POLL_UPVALUE_MT: u8 = 0;
#[cfg(feature = "async")]
pub(crate) static WAKER_MT: u8 = 0;
#[cfg(feature = "async")] #[cfg(feature = "async")]
pub(crate) static WAKER_REGISTRY_KEY: u8 = 0; pub(crate) static WAKER_REGISTRY_KEY: u8 = 0;
pub(crate) static EXTRA_REGISTRY_KEY: u8 = 0; #[cfg(feature = "async")]
pub(crate) static ASYNC_POLL_PENDING: u8 = 0;
/// Requires `feature = "send"` /// Requires `feature = "send"`
#[cfg(feature = "send")] #[cfg(feature = "send")]
@ -396,18 +409,19 @@ impl Lua {
// Create the internal metatables and place them in the registry // Create the internal metatables and place them in the registry
// to prevent them from being garbage collected. // to prevent them from being garbage collected.
init_gc_metatable_for::<Callback>(state, None)?; init_gc_metatable::<Callback>(state, &CALLBACK_MT, None)?;
init_gc_metatable_for::<CallbackUpvalue>(state, None)?; init_gc_metatable::<CallbackUpvalue>(state, &CALLBACK_UPVALUE_MT, None)?;
init_gc_metatable_for::<Weak<Mutex<ExtraData>>>(state, None)?; init_gc_metatable::<Weak<Mutex<ExtraData>>>(state, &EXTRA_MT, None)?;
#[cfg(feature = "async")] #[cfg(feature = "async")]
{ {
init_gc_metatable_for::<AsyncCallback>(state, None)?; init_gc_metatable::<AsyncCallback>(state, &ASYNC_CALLBACK_MT, None)?;
init_gc_metatable_for::<AsyncCallbackUpvalue>(state, None)?; #[rustfmt::skip]
init_gc_metatable_for::<AsyncPollUpvalue>(state, None)?; init_gc_metatable::<AsyncCallbackUpvalue>(state, &ASYNC_CALLBACK_UPVALUE_MT, None)?;
init_gc_metatable_for::<Option<Waker>>(state, None)?; init_gc_metatable::<AsyncPollUpvalue>(state, &ASYNC_POLL_UPVALUE_MT, None)?;
init_gc_metatable::<Option<Waker>>(state, &WAKER_MT, None)?;
// Create empty Waker slot // Create empty Waker slot
push_gc_userdata::<Option<Waker>>(state, None)?; push_gc_userdata::<Option<Waker>>(state, &WAKER_MT, None)?;
protect_lua!(state, 1, 0, state => { protect_lua!(state, 1, 0, state => {
let waker_key = &WAKER_REGISTRY_KEY as *const u8 as *const c_void; let waker_key = &WAKER_REGISTRY_KEY as *const u8 as *const c_void;
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, waker_key); ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, waker_key);
@ -450,7 +464,7 @@ impl Lua {
})); }));
mlua_expect!( mlua_expect!(
push_gc_userdata(main_state, Arc::downgrade(&extra)), push_gc_userdata(main_state, &EXTRA_MT, Arc::downgrade(&extra)),
"Error while storing extra data", "Error while storing extra data",
); );
mlua_expect!( mlua_expect!(
@ -1612,7 +1626,9 @@ impl Lua {
let err = err.clone(); let err = err.clone();
ffi::lua_pop(state, 1); ffi::lua_pop(state, 1);
Value::Error(err) Value::Error(err)
} else if let Some(panic) = get_gc_userdata::<WrappedPanic>(state, -1).as_mut() { } else if let Some(panic) =
get_gc_userdata::<WrappedPanic>(state, -1, &WRAPPED_PANIC_MT).as_mut()
{
if let Some(panic) = (*panic).0.take() { if let Some(panic) = (*panic).0.take() {
ffi::lua_pop(state, 1); ffi::lua_pop(state, 1);
resume_unwind(panic); resume_unwind(panic);
@ -1877,8 +1893,12 @@ impl Lua {
check_stack(self.state, 4)?; check_stack(self.state, 4)?;
let lua = self.clone(); let lua = self.clone();
let func = mem::transmute(func); push_gc_userdata(
push_gc_userdata(self.state, CallbackUpvalue { lua, func })?; self.state,
&CALLBACK_UPVALUE_MT,
CallbackUpvalue { lua, func },
)?;
protect_lua!(self.state, 1, 1, state => { protect_lua!(self.state, 1, 1, state => {
ffi::lua_pushcclosure(state, call_callback, 1); ffi::lua_pushcclosure(state, call_callback, 1);
})?; })?;
@ -1930,7 +1950,7 @@ impl Lua {
let fut = ((*upvalue).func)(lua, args); let fut = ((*upvalue).func)(lua, args);
let lua = lua.clone(); let lua = lua.clone();
push_gc_userdata(state, AsyncPollUpvalue { lua, fut })?; push_gc_userdata(state, &ASYNC_POLL_UPVALUE_MT, AsyncPollUpvalue { lua, fut })?;
protect_lua!(state, 1, 1, state => { protect_lua!(state, 1, 1, state => {
ffi::lua_pushcclosure(state, poll_future, 1); ffi::lua_pushcclosure(state, poll_future, 1);
})?; })?;
@ -1961,7 +1981,7 @@ impl Lua {
// Try to get an outer poll waker // Try to get an outer poll waker
let waker_key = &WAKER_REGISTRY_KEY as *const u8 as *const c_void; let waker_key = &WAKER_REGISTRY_KEY as *const u8 as *const c_void;
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, waker_key); ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, waker_key);
let waker = match get_gc_userdata::<Option<Waker>>(state, -1).as_ref() { let waker = match get_gc_userdata::<Option<Waker>>(state, -1, &WAKER_MT).as_ref() {
Some(Some(waker)) => waker.clone(), Some(Some(waker)) => waker.clone(),
_ => noop_waker(), _ => noop_waker(),
}; };
@ -1995,8 +2015,11 @@ impl Lua {
check_stack(self.state, 4)?; check_stack(self.state, 4)?;
let lua = self.clone(); let lua = self.clone();
let func = mem::transmute(func); push_gc_userdata(
push_gc_userdata(self.state, AsyncCallbackUpvalue { lua, func })?; self.state,
&ASYNC_CALLBACK_UPVALUE_MT,
AsyncCallbackUpvalue { lua, func },
)?;
protect_lua!(self.state, 1, 1, state => { protect_lua!(self.state, 1, 1, state => {
ffi::lua_pushcclosure(state, call_callback, 1); ffi::lua_pushcclosure(state, call_callback, 1);
})?; })?;
@ -2104,7 +2127,7 @@ impl Lua {
return None; return None;
} }
let extra = mlua_expect!( let extra = mlua_expect!(
(*get_gc_userdata::<Weak<Mutex<ExtraData>>>(state, -1)).upgrade(), (*get_gc_userdata::<Weak<Mutex<ExtraData>>>(state, -1, &EXTRA_MT)).upgrade(),
"extra is destroyed" "extra is destroyed"
); );
ffi::lua_pop(state, 1); ffi::lua_pop(state, 1);
@ -2437,7 +2460,7 @@ where
Ok(Err(err)) => { Ok(Err(err)) => {
let wrapped_error = get_prealloc_err() as *mut WrappedError; let wrapped_error = get_prealloc_err() as *mut WrappedError;
ptr::write(wrapped_error, WrappedError(err)); ptr::write(wrapped_error, WrappedError(err));
get_gc_metatable_for::<WrappedError>(state); get_gc_metatable(state, &WRAPPED_ERROR_MT);
ffi::lua_setmetatable(state, -2); ffi::lua_setmetatable(state, -2);
// Convert to CallbackError and attach traceback // Convert to CallbackError and attach traceback
@ -2457,7 +2480,7 @@ where
Err(p) => { Err(p) => {
let wrapped_panic = get_prealloc_err() as *mut WrappedPanic; let wrapped_panic = get_prealloc_err() as *mut WrappedPanic;
ptr::write(wrapped_panic, WrappedPanic(Some(p))); ptr::write(wrapped_panic, WrappedPanic(Some(p)));
get_gc_metatable_for::<WrappedPanic>(state); get_gc_metatable(state, &WRAPPED_PANIC_MT);
ffi::lua_setmetatable(state, -2); ffi::lua_setmetatable(state, -2);
ffi::lua_error(state) ffi::lua_error(state)
} }

View File

@ -13,7 +13,7 @@ use crate::function::Function;
#[cfg(feature = "async")] #[cfg(feature = "async")]
use { use {
crate::{ crate::{
lua::{ASYNC_POLL_PENDING, WAKER_REGISTRY_KEY}, lua::{ASYNC_POLL_PENDING, WAKER_MT, WAKER_REGISTRY_KEY},
util::get_gc_userdata, util::get_gc_userdata,
value::Value, value::Value,
}, },
@ -362,7 +362,7 @@ impl WakerGuard {
let waker_key = &WAKER_REGISTRY_KEY as *const u8 as *const c_void; let waker_key = &WAKER_REGISTRY_KEY as *const u8 as *const c_void;
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, waker_key); ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, waker_key);
let waker_slot = get_gc_userdata::<Option<Waker>>(state, -1).as_mut(); let waker_slot = get_gc_userdata::<Option<Waker>>(state, -1, &WAKER_MT).as_mut();
let old = mlua_expect!(waker_slot, "Waker is destroyed").replace(waker); let old = mlua_expect!(waker_slot, "Waker is destroyed").replace(waker);
Ok(WakerGuard(state, old)) Ok(WakerGuard(state, old))
@ -380,7 +380,7 @@ impl Drop for WakerGuard {
let waker_key = &WAKER_REGISTRY_KEY as *const u8 as *const c_void; let waker_key = &WAKER_REGISTRY_KEY as *const u8 as *const c_void;
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, waker_key); ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, waker_key);
let waker_slot = get_gc_userdata::<Option<Waker>>(state, -1).as_mut(); let waker_slot = get_gc_userdata::<Option<Waker>>(state, -1, &WAKER_MT).as_mut();
mem::swap(mlua_expect!(waker_slot, "Waker is destroyed"), &mut self.1); mem::swap(mlua_expect!(waker_slot, "Waker is destroyed"), &mut self.1);
} }
} }

View File

@ -1,21 +1,18 @@
use std::any::{Any, TypeId}; use std::any::Any;
use std::collections::HashMap;
use std::error::Error as StdError; use std::error::Error as StdError;
use std::fmt::Write; use std::fmt::Write;
use std::os::raw::{c_char, c_int, c_void}; use std::os::raw::{c_char, c_int, c_void};
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe}; use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
use std::sync::{Arc, Mutex}; use std::sync::Arc;
use std::{mem, ptr, slice}; use std::{mem, ptr, slice};
use once_cell::sync::Lazy;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::ffi; use crate::ffi;
static METATABLE_CACHE: Lazy<Mutex<HashMap<TypeId, u8>>> = Lazy::new(|| { pub(crate) static WRAPPED_ERROR_MT: u8 = 0;
// The capacity must(!) be greater than number of stored keys pub(crate) static WRAPPED_PANIC_MT: u8 = 0;
Mutex::new(HashMap::with_capacity(32)) static DESTRUCTED_USERDATA_MT: u8 = 0;
}); static ERROR_PRINT_BUFFER_KEY: u8 = 0;
// Checks that Lua has enough free stack space for future stack operations. On failure, this will // Checks that Lua has enough free stack space for future stack operations. On failure, this will
// panic with an internal error message. // panic with an internal error message.
@ -199,7 +196,9 @@ pub unsafe fn pop_error(state: *mut ffi::lua_State, err_code: c_int) -> Error {
if let Some(err) = get_wrapped_error(state, -1).as_ref() { if let Some(err) = get_wrapped_error(state, -1).as_ref() {
ffi::lua_pop(state, 1); ffi::lua_pop(state, 1);
err.clone() err.clone()
} else if let Some(panic) = get_gc_userdata::<WrappedPanic>(state, -1).as_mut() { } else if let Some(panic) =
get_gc_userdata::<WrappedPanic>(state, -1, &WRAPPED_PANIC_MT).as_mut()
{
if let Some(p) = (*panic).0.take() { if let Some(p) = (*panic).0.take() {
resume_unwind(p); resume_unwind(p);
} else { } else {
@ -298,20 +297,24 @@ pub unsafe fn take_userdata<T>(state: *mut ffi::lua_State) -> T {
// Pushes the userdata and attaches a metatable with __gc method. // Pushes the userdata and attaches a metatable with __gc method.
// Internally uses 3 stack spaces, does not call checkstack. // Internally uses 3 stack spaces, does not call checkstack.
pub unsafe fn push_gc_userdata<T: Any>(state: *mut ffi::lua_State, t: T) -> Result<()> { pub unsafe fn push_gc_userdata<T>(state: *mut ffi::lua_State, key: *const u8, t: T) -> Result<()> {
push_userdata(state, t)?; push_userdata(state, t)?;
get_gc_metatable_for::<T>(state); get_gc_metatable(state, key);
ffi::lua_setmetatable(state, -2); ffi::lua_setmetatable(state, -2);
Ok(()) Ok(())
} }
// 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>(
state: *mut ffi::lua_State,
index: c_int,
key: *const u8,
) -> *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();
} }
get_gc_metatable_for::<T>(state); get_gc_metatable(state, key);
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 {
@ -525,7 +528,7 @@ where
let wrapped_error = ud as *mut WrappedError; let wrapped_error = ud as *mut WrappedError;
ptr::write(wrapped_error, WrappedError(err)); ptr::write(wrapped_error, WrappedError(err));
get_gc_metatable_for::<WrappedError>(state); get_gc_metatable(state, &WRAPPED_ERROR_MT);
ffi::lua_setmetatable(state, -2); ffi::lua_setmetatable(state, -2);
// Convert to CallbackError and attach traceback // Convert to CallbackError and attach traceback
@ -545,7 +548,7 @@ where
Err(p) => { Err(p) => {
ffi::lua_settop(state, 1); ffi::lua_settop(state, 1);
ptr::write(ud as *mut WrappedPanic, WrappedPanic(Some(p))); ptr::write(ud as *mut WrappedPanic, WrappedPanic(Some(p)));
get_gc_metatable_for::<WrappedPanic>(state); get_gc_metatable(state, &WRAPPED_PANIC_MT);
ffi::lua_setmetatable(state, -2); ffi::lua_setmetatable(state, -2);
ffi::lua_error(state) ffi::lua_error(state)
} }
@ -559,8 +562,8 @@ pub unsafe extern "C" fn error_traceback(state: *mut ffi::lua_State) -> c_int {
return 1; return 1;
} }
if get_gc_userdata::<WrappedError>(state, -1).is_null() if get_gc_userdata::<WrappedError>(state, -1, &WRAPPED_ERROR_MT).is_null()
&& get_gc_userdata::<WrappedPanic>(state, -1).is_null() && get_gc_userdata::<WrappedPanic>(state, -1, &WRAPPED_PANIC_MT).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 {
@ -587,7 +590,7 @@ pub unsafe extern "C" fn safe_pcall(state: *mut ffi::lua_State) -> c_int {
ffi::lua_insert(state, 1); ffi::lua_insert(state, 1);
ffi::lua_gettop(state) ffi::lua_gettop(state)
} else { } else {
if !get_gc_userdata::<WrappedPanic>(state, -1).is_null() { if !get_gc_userdata::<WrappedPanic>(state, -1, &WRAPPED_PANIC_MT).is_null() {
ffi::lua_error(state); ffi::lua_error(state);
} }
ffi::lua_pushboolean(state, 0); ffi::lua_pushboolean(state, 0);
@ -601,7 +604,7 @@ pub unsafe extern "C" fn safe_xpcall(state: *mut ffi::lua_State) -> c_int {
unsafe extern "C" fn xpcall_msgh(state: *mut ffi::lua_State) -> c_int { unsafe extern "C" fn xpcall_msgh(state: *mut ffi::lua_State) -> c_int {
ffi::luaL_checkstack(state, 2, ptr::null()); ffi::luaL_checkstack(state, 2, ptr::null());
if !get_gc_userdata::<WrappedPanic>(state, -1).is_null() { if !get_gc_userdata::<WrappedPanic>(state, -1, &WRAPPED_PANIC_MT).is_null() {
1 1
} else { } else {
ffi::lua_pushvalue(state, ffi::lua_upvalueindex(1)); ffi::lua_pushvalue(state, ffi::lua_upvalueindex(1));
@ -629,7 +632,7 @@ pub unsafe extern "C" fn safe_xpcall(state: *mut ffi::lua_State) -> c_int {
ffi::lua_insert(state, 2); ffi::lua_insert(state, 2);
ffi::lua_gettop(state) - 1 ffi::lua_gettop(state) - 1
} else { } else {
if !get_gc_userdata::<WrappedPanic>(state, -1).is_null() { if !get_gc_userdata::<WrappedPanic>(state, -1, &WRAPPED_PANIC_MT).is_null() {
ffi::lua_error(state); ffi::lua_error(state);
} }
ffi::lua_pushboolean(state, 0); ffi::lua_pushboolean(state, 0);
@ -664,14 +667,14 @@ pub unsafe fn get_main_state(state: *mut ffi::lua_State) -> Option<*mut ffi::lua
// Pushes a WrappedError to the top of the stack. // Pushes a WrappedError to the top of the stack.
// Uses 3 stack spaces and does not call checkstack. // Uses 3 stack spaces and does not call checkstack.
pub unsafe fn push_wrapped_error(state: *mut ffi::lua_State, err: Error) -> Result<()> { pub unsafe fn push_wrapped_error(state: *mut ffi::lua_State, err: Error) -> Result<()> {
push_gc_userdata::<WrappedError>(state, WrappedError(err)) push_gc_userdata::<WrappedError>(state, &WRAPPED_ERROR_MT, WrappedError(err))
} }
// Checks if the value at the given index is a WrappedError, and if it is returns a pointer to it, // Checks if the value at the given index is a WrappedError, and if it is returns a pointer to it,
// otherwise returns null. // otherwise returns null.
// Uses 2 stack spaces and does not call checkstack. // Uses 2 stack spaces and does not call checkstack.
pub unsafe fn get_wrapped_error(state: *mut ffi::lua_State, index: c_int) -> *const Error { pub unsafe fn get_wrapped_error(state: *mut ffi::lua_State, index: c_int) -> *const Error {
let ud = get_gc_userdata::<WrappedError>(state, index); let ud = get_gc_userdata::<WrappedError>(state, index, &WRAPPED_ERROR_MT);
if ud.is_null() { if ud.is_null() {
return ptr::null(); return ptr::null();
} }
@ -680,23 +683,13 @@ pub unsafe fn get_wrapped_error(state: *mut ffi::lua_State, index: c_int) -> *co
// Initialize the internal (with __gc method) metatable for a type T. // Initialize the internal (with __gc method) metatable for a type T.
// Uses 6 stack spaces and calls checkstack. // Uses 6 stack spaces and calls checkstack.
pub unsafe fn init_gc_metatable_for<T: Any>( pub unsafe fn init_gc_metatable<T>(
state: *mut ffi::lua_State, state: *mut ffi::lua_State,
key: *const u8,
customize_fn: Option<fn(*mut ffi::lua_State) -> Result<()>>, customize_fn: Option<fn(*mut ffi::lua_State) -> Result<()>>,
) -> Result<()> { ) -> Result<()> {
check_stack(state, 6)?; check_stack(state, 6)?;
let type_id = TypeId::of::<T>();
let ref_addr = {
let mut mt_cache = mlua_expect!(METATABLE_CACHE.lock(), "cannot lock metatable cache");
mlua_assert!(
mt_cache.capacity() - mt_cache.len() > 0,
"out of metatable cache capacity"
);
mt_cache.insert(type_id, 0);
&mt_cache[&type_id] as *const u8
};
push_table(state, 0, 3)?; push_table(state, 0, 3)?;
ffi::lua_pushcfunction(state, userdata_destructor::<T>); ffi::lua_pushcfunction(state, userdata_destructor::<T>);
@ -710,19 +703,14 @@ pub unsafe fn init_gc_metatable_for<T: Any>(
} }
protect_lua!(state, 1, 0, |state| { protect_lua!(state, 1, 0, |state| {
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, ref_addr as *mut c_void) ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, key as *const c_void)
})?; })?;
Ok(()) Ok(())
} }
pub unsafe fn get_gc_metatable_for<T: Any>(state: *mut ffi::lua_State) { pub unsafe fn get_gc_metatable(state: *mut ffi::lua_State, key: *const u8) {
let type_id = TypeId::of::<T>(); ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, key as *const c_void);
let ref_addr = {
let mt_cache = mlua_expect!(METATABLE_CACHE.lock(), "cannot lock metatable cache");
mlua_expect!(mt_cache.get(&type_id), "gc metatable does not exist") as *const u8
};
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, ref_addr as *const c_void);
} }
// Initialize the error, panic, and destructed userdata metatables. // Initialize the error, panic, and destructed userdata metatables.
@ -771,7 +759,9 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
_ => {} _ => {}
} }
Ok(err_buf) Ok(err_buf)
} else if let Some(panic) = get_gc_userdata::<WrappedPanic>(state, -1).as_ref() { } else if let Some(panic) =
get_gc_userdata::<WrappedPanic>(state, -1, &WRAPPED_PANIC_MT).as_ref()
{
if let Some(ref p) = (*panic).0 { if let Some(ref p) = (*panic).0 {
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);
@ -802,16 +792,18 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
}) })
} }
init_gc_metatable_for::<WrappedError>( init_gc_metatable::<WrappedError>(
state, state,
&WRAPPED_ERROR_MT,
Some(|state| { Some(|state| {
ffi::lua_pushcfunction(state, error_tostring); ffi::lua_pushcfunction(state, error_tostring);
rawset_field(state, -2, "__tostring") rawset_field(state, -2, "__tostring")
}), }),
)?; )?;
init_gc_metatable_for::<WrappedPanic>( init_gc_metatable::<WrappedPanic>(
state, state,
&WRAPPED_PANIC_MT,
Some(|state| { Some(|state| {
ffi::lua_pushcfunction(state, error_tostring); ffi::lua_pushcfunction(state, error_tostring);
rawset_field(state, -2, "__tostring") rawset_field(state, -2, "__tostring")
@ -870,16 +862,16 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
ffi::lua_pop(state, 1); ffi::lua_pop(state, 1);
protect_lua!(state, 1, 0, state => { protect_lua!(state, 1, 0, state => {
let destructed_metatable_key = &DESTRUCTED_USERDATA_METATABLE as *const u8 as *const c_void; let key = &DESTRUCTED_USERDATA_MT as *const u8 as *const c_void;
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, destructed_metatable_key) ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, key)
})?; })?;
// Create error print buffer // Create error print buffer
init_gc_metatable_for::<String>(state, None)?; init_gc_metatable::<String>(state, &ERROR_PRINT_BUFFER_KEY, None)?;
push_gc_userdata(state, String::new())?; push_gc_userdata(state, &ERROR_PRINT_BUFFER_KEY, String::new())?;
protect_lua!(state, 1, 0, state => { protect_lua!(state, 1, 0, state => {
let err_buf_key = &ERROR_PRINT_BUFFER_KEY as *const u8 as *const c_void; let key = &ERROR_PRINT_BUFFER_KEY as *const u8 as *const c_void;
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, err_buf_key) ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, key)
})?; })?;
Ok(()) Ok(())
@ -923,9 +915,6 @@ pub(crate) unsafe fn to_string(state: *mut ffi::lua_State, index: c_int) -> Stri
} }
pub(crate) unsafe fn get_destructed_userdata_metatable(state: *mut ffi::lua_State) { pub(crate) unsafe fn get_destructed_userdata_metatable(state: *mut ffi::lua_State) {
let key = &DESTRUCTED_USERDATA_METATABLE as *const u8 as *const c_void; let key = &DESTRUCTED_USERDATA_MT as *const u8 as *const c_void;
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, key); ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, key);
} }
static DESTRUCTED_USERDATA_METATABLE: u8 = 0;
static ERROR_PRINT_BUFFER_KEY: u8 = 0;