1
1
use std:: any:: TypeId ;
2
2
use std:: cell:: { RefCell , UnsafeCell } ;
3
3
use std:: ffi:: { CStr , CString } ;
4
- use std:: fmt;
5
4
use std:: marker:: PhantomData ;
6
5
use std:: mem:: MaybeUninit ;
7
6
use std:: ops:: Deref ;
8
7
use std:: os:: raw:: { c_char, c_int, c_void} ;
9
8
use std:: panic:: { catch_unwind, resume_unwind, AssertUnwindSafe , Location } ;
10
- use std:: ptr:: NonNull ;
11
9
use std:: result:: Result as StdResult ;
12
10
use std:: sync:: atomic:: { AtomicPtr , Ordering } ;
13
11
use std:: sync:: { Arc , Mutex } ;
14
- use std:: { mem, ptr, str} ;
12
+ use std:: { fmt , mem, ptr, str} ;
15
13
16
14
use rustc_hash:: FxHashMap ;
17
15
60
58
crate :: types:: { AsyncCallback , AsyncCallbackUpvalue , AsyncPollUpvalue } ,
61
59
futures_util:: future:: { self , Future } ,
62
60
futures_util:: task:: { noop_waker_ref, Context , Poll , Waker } ,
61
+ std:: ptr:: NonNull ,
63
62
} ;
64
63
65
64
#[ cfg( feature = "serialize" ) ]
@@ -94,7 +93,6 @@ pub(crate) struct ExtraData {
94
93
95
94
safe : bool ,
96
95
libs : StdLib ,
97
- mem_state : Option < NonNull < MemoryState > > ,
98
96
#[ cfg( feature = "module" ) ]
99
97
skip_memory_check : bool ,
100
98
@@ -244,11 +242,14 @@ impl Drop for Lua {
244
242
impl Drop for LuaInner {
245
243
fn drop ( & mut self ) {
246
244
unsafe {
247
- #[ cfg( feature = "luau" ) ]
248
- {
249
- ( * ffi:: lua_callbacks ( self . state ( ) ) ) . userdata = ptr:: null_mut ( ) ;
250
- }
245
+ let mem_state = MemoryState :: get ( self . main_state ) ;
246
+
251
247
ffi:: lua_close ( self . main_state ) ;
248
+
249
+ // Deallocate MemoryState if it was created by us
250
+ if !mem_state. is_null ( ) {
251
+ drop ( Box :: from_raw ( mem_state) ) ;
252
+ }
252
253
}
253
254
}
254
255
}
@@ -261,9 +262,6 @@ impl Drop for ExtraData {
261
262
}
262
263
263
264
* mlua_expect ! ( self . registry_unref_list. lock( ) , "unref list poisoned" ) = None ;
264
- if let Some ( mem_state) = self . mem_state {
265
- drop ( unsafe { Box :: from_raw ( mem_state. as_ptr ( ) ) } ) ;
266
- }
267
265
}
268
266
}
269
267
@@ -359,36 +357,34 @@ impl Lua {
359
357
///
360
358
/// [`StdLib`]: crate::StdLib
361
359
pub unsafe fn unsafe_new_with ( libs : StdLib , options : LuaOptions ) -> Lua {
360
+ // Workaround to avoid stripping a few unused Lua symbols that could be imported
361
+ // by C modules in unsafe mode
362
+ let mut _symbols: Vec < * const extern "C-unwind" fn ( ) > =
363
+ vec ! [ ffi:: lua_isuserdata as _, ffi:: lua_tocfunction as _] ;
364
+
362
365
#[ cfg( not( feature = "luau" ) ) ]
366
+ _symbols. extend_from_slice ( & [
367
+ ffi:: lua_atpanic as _ ,
368
+ ffi:: luaL_loadstring as _ ,
369
+ ffi:: luaL_openlibs as _ ,
370
+ ] ) ;
371
+ #[ cfg( any( feature = "lua54" , feature = "lua53" , feature = "lua52" ) ) ]
363
372
{
364
- // Workaround to avoid stripping a few unused Lua symbols that could be imported
365
- // by C modules in unsafe mode
366
- let mut _symbols: Vec < * const extern "C-unwind" fn ( ) > = vec ! [
367
- ffi:: lua_atpanic as _,
368
- ffi:: lua_isuserdata as _,
369
- ffi:: lua_tocfunction as _,
370
- ffi:: luaL_loadstring as _,
371
- ffi:: luaL_openlibs as _,
372
- ] ;
373
- #[ cfg( any( feature = "lua54" , feature = "lua53" , feature = "lua52" ) ) ]
374
- {
375
- _symbols. push ( ffi:: lua_getglobal as _ ) ;
376
- _symbols. push ( ffi:: lua_setglobal as _ ) ;
377
- _symbols. push ( ffi:: luaL_setfuncs as _ ) ;
378
- }
373
+ _symbols. push ( ffi:: lua_getglobal as _ ) ;
374
+ _symbols. push ( ffi:: lua_setglobal as _ ) ;
375
+ _symbols. push ( ffi:: luaL_setfuncs as _ ) ;
379
376
}
380
377
381
378
Self :: inner_new ( libs, options)
382
379
}
383
380
384
381
/// Creates a new Lua state with required `libs` and `options`
385
382
unsafe fn inner_new ( libs : StdLib , options : LuaOptions ) -> Lua {
386
- let mut mem_state: * mut MemoryState = Box :: into_raw ( Box :: default ( ) ) ;
383
+ let mem_state: * mut MemoryState = Box :: into_raw ( Box :: default ( ) ) ;
387
384
let mut state = ffi:: lua_newstate ( ALLOCATOR , mem_state as * mut c_void ) ;
388
385
// If state is null then switch to Lua internal allocator
389
386
if state. is_null ( ) {
390
387
drop ( Box :: from_raw ( mem_state) ) ;
391
- mem_state = ptr:: null_mut ( ) ;
392
388
state = ffi:: luaL_newstate ( ) ;
393
389
}
394
390
assert ! ( !state. is_null( ) , "Failed to instantiate Lua VM" ) ;
@@ -404,7 +400,6 @@ impl Lua {
404
400
405
401
let lua = Lua :: init_from_ptr ( state) ;
406
402
let extra = lua. extra . get ( ) ;
407
- ( * extra) . mem_state = NonNull :: new ( mem_state) ;
408
403
409
404
mlua_expect ! (
410
405
load_from_std_lib( state, libs) ,
@@ -440,7 +435,7 @@ impl Lua {
440
435
}
441
436
442
437
#[ cfg( feature = "luau" ) ]
443
- mlua_expect ! ( lua. prepare_luau_state( ) , "Error preparing Luau state " ) ;
438
+ mlua_expect ! ( lua. prepare_luau_state( ) , "Error configuring Luau" ) ;
444
439
445
440
lua
446
441
}
@@ -514,7 +509,6 @@ impl Lua {
514
509
app_data : AppData :: default ( ) ,
515
510
safe : false ,
516
511
libs : StdLib :: NONE ,
517
- mem_state : None ,
518
512
#[ cfg( feature = "module" ) ]
519
513
skip_memory_check : false ,
520
514
ref_thread,
@@ -547,14 +541,8 @@ impl Lua {
547
541
548
542
// Store it in the registry
549
543
mlua_expect ! (
550
- ( |state| {
551
- push_gc_userdata( state, Arc :: clone( & extra) , true ) ?;
552
- protect_lua!( state, 1 , 0 , fn ( state) {
553
- let extra_key = & EXTRA_REGISTRY_KEY as * const u8 as * const c_void;
554
- ffi:: lua_rawsetp( state, ffi:: LUA_REGISTRYINDEX , extra_key) ;
555
- } )
556
- } ) ( main_state) ,
557
- "Error while storing extra data" ,
544
+ set_extra_data( main_state, & extra) ,
545
+ "Error while storing extra data"
558
546
) ;
559
547
560
548
// Register `DestructedUserdata` type
@@ -572,13 +560,6 @@ impl Lua {
572
560
) ;
573
561
assert_stack ( main_state, ffi:: LUA_MINSTACK ) ;
574
562
575
- // Set Luau callbacks userdata to extra data
576
- // We can use global callbacks userdata since we don't allow C modules in Luau
577
- #[ cfg( feature = "luau" ) ]
578
- {
579
- ( * ffi:: lua_callbacks ( main_state) ) . userdata = extra. get ( ) as * mut c_void ;
580
- }
581
-
582
563
let inner = Arc :: new ( LuaInner {
583
564
state : AtomicPtr :: new ( state) ,
584
565
main_state,
@@ -1098,9 +1079,9 @@ impl Lua {
1098
1079
/// Returns the amount of memory (in bytes) currently used inside this Lua state.
1099
1080
pub fn used_memory ( & self ) -> usize {
1100
1081
unsafe {
1101
- match ( * self . extra . get ( ) ) . mem_state . map ( |x| x . as_ref ( ) ) {
1102
- Some ( mem_state) => mem_state. used_memory ( ) ,
1103
- None => {
1082
+ match MemoryState :: get ( self . main_state ) {
1083
+ mem_state if !mem_state . is_null ( ) => ( * mem_state) . used_memory ( ) ,
1084
+ _ => {
1104
1085
// Get data from the Lua GC
1105
1086
let used_kbytes = ffi:: lua_gc ( self . main_state , ffi:: LUA_GCCOUNT , 0 ) ;
1106
1087
let used_kbytes_rem = ffi:: lua_gc ( self . main_state , ffi:: LUA_GCCOUNTB , 0 ) ;
@@ -1119,9 +1100,9 @@ impl Lua {
1119
1100
/// Does not work in module mode where Lua state is managed externally.
1120
1101
pub fn set_memory_limit ( & self , limit : usize ) -> Result < usize > {
1121
1102
unsafe {
1122
- match ( * self . extra . get ( ) ) . mem_state . map ( | mut x| x . as_mut ( ) ) {
1123
- Some ( mem_state) => Ok ( mem_state. set_memory_limit ( limit) ) ,
1124
- None => Err ( Error :: MemoryLimitNotAvailable ) ,
1103
+ match MemoryState :: get ( self . main_state ) {
1104
+ mem_state if !mem_state . is_null ( ) => Ok ( ( * mem_state) . set_memory_limit ( limit) ) ,
1105
+ _ => Err ( Error :: MemoryLimitNotAvailable ) ,
1125
1106
}
1126
1107
}
1127
1108
}
@@ -3169,9 +3150,9 @@ impl Lua {
3169
3150
#[ inline]
3170
3151
pub ( crate ) unsafe fn unlikely_memory_error ( & self ) -> bool {
3171
3152
// MemoryInfo is empty in module mode so we cannot predict memory limits
3172
- ( * self . extra . get ( ) )
3173
- . mem_state
3174
- . map ( |x| x. as_ref ( ) . memory_limit ( ) == 0 )
3153
+ MemoryState :: get ( self . main_state )
3154
+ . as_ref ( )
3155
+ . map ( |x| x. memory_limit ( ) == 0 )
3175
3156
. unwrap_or_else ( || {
3176
3157
// Alternatively, check the special flag (only for module mode)
3177
3158
#[ cfg( feature = "module" ) ]
@@ -3223,14 +3204,6 @@ impl LuaInner {
3223
3204
}
3224
3205
}
3225
3206
3226
- impl ExtraData {
3227
- #[ cfg( feature = "luau" ) ]
3228
- #[ inline]
3229
- pub ( crate ) fn mem_state ( & self ) -> NonNull < MemoryState > {
3230
- self . mem_state . unwrap ( )
3231
- }
3232
- }
3233
-
3234
3207
struct StateGuard < ' a > ( & ' a LuaInner , * mut ffi:: lua_State ) ;
3235
3208
3236
3209
impl < ' a > StateGuard < ' a > {
@@ -3246,13 +3219,13 @@ impl<'a> Drop for StateGuard<'a> {
3246
3219
}
3247
3220
}
3248
3221
3249
- #[ cfg( feature = "luau" ) ]
3250
3222
unsafe fn extra_data ( state : * mut ffi:: lua_State ) -> * mut ExtraData {
3251
- ( * ffi:: lua_callbacks ( state) ) . userdata as * mut ExtraData
3252
- }
3223
+ #[ cfg( feature = "luau" ) ]
3224
+ if cfg ! ( not( feature = "module" ) ) {
3225
+ // In the main app we can use `lua_callbacks` to access ExtraData
3226
+ return ( * ffi:: lua_callbacks ( state) ) . userdata as * mut _ ;
3227
+ }
3253
3228
3254
- #[ cfg( not( feature = "luau" ) ) ]
3255
- unsafe fn extra_data ( state : * mut ffi:: lua_State ) -> * mut ExtraData {
3256
3229
let extra_key = & EXTRA_REGISTRY_KEY as * const u8 as * const c_void ;
3257
3230
if ffi:: lua_rawgetp ( state, ffi:: LUA_REGISTRYINDEX , extra_key) != ffi:: LUA_TUSERDATA {
3258
3231
// `ExtraData` can be null only when Lua state is foreign.
@@ -3265,6 +3238,23 @@ unsafe fn extra_data(state: *mut ffi::lua_State) -> *mut ExtraData {
3265
3238
( * extra_ptr) . get ( )
3266
3239
}
3267
3240
3241
+ unsafe fn set_extra_data (
3242
+ state : * mut ffi:: lua_State ,
3243
+ extra : & Arc < UnsafeCell < ExtraData > > ,
3244
+ ) -> Result < ( ) > {
3245
+ #[ cfg( feature = "luau" ) ]
3246
+ if cfg ! ( not( feature = "module" ) ) {
3247
+ ( * ffi:: lua_callbacks ( state) ) . userdata = extra. get ( ) as * mut _ ;
3248
+ return Ok ( ( ) ) ;
3249
+ }
3250
+
3251
+ push_gc_userdata ( state, Arc :: clone ( extra) , true ) ?;
3252
+ protect_lua ! ( state, 1 , 0 , fn ( state) {
3253
+ let extra_key = & EXTRA_REGISTRY_KEY as * const u8 as * const c_void;
3254
+ ffi:: lua_rawsetp( state, ffi:: LUA_REGISTRYINDEX , extra_key) ;
3255
+ } )
3256
+ }
3257
+
3268
3258
// Creates required entries in the metatable cache (see `util::METATABLE_CACHE`)
3269
3259
pub ( crate ) fn init_metatable_cache ( cache : & mut FxHashMap < TypeId , u8 > ) {
3270
3260
cache. insert ( TypeId :: of :: < Arc < UnsafeCell < ExtraData > > > ( ) , 0 ) ;
0 commit comments