Skip to content

Commit c5f36c9

Browse files
committed
Add package module to Luau
Introduce module loaders Support loading binary modules
1 parent f5021da commit c5f36c9

File tree

12 files changed

+359
-175
lines changed

12 files changed

+359
-175
lines changed

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ lua52 = ["ffi/lua52"]
3232
lua51 = ["ffi/lua51"]
3333
luajit = ["ffi/luajit"]
3434
luajit52 = ["luajit", "ffi/luajit52"]
35-
luau = ["ffi/luau"]
35+
luau = ["ffi/luau", "libloading"]
3636
luau-jit = ["luau", "ffi/luau-codegen"]
3737
luau-vector4 = ["luau", "ffi/luau-vector4"]
3838
vendored = ["ffi/vendored"]
@@ -57,6 +57,9 @@ parking_lot = { version = "0.12", optional = true }
5757

5858
ffi = { package = "mlua-sys", version = "0.3.2", path = "mlua-sys" }
5959

60+
[target.'cfg(unix)'.dependencies]
61+
libloading = { version = "0.8", optional = true }
62+
6063
[dev-dependencies]
6164
rustyline = "12.0"
6265
criterion = { version = "0.5", features = ["async_tokio"] }

mlua-sys/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,4 @@ cfg-if = "1.0"
4040
pkg-config = "0.3.17"
4141
lua-src = { version = ">= 546.0.0, < 546.1.0", optional = true }
4242
luajit-src = { version = ">= 210.5.0, < 210.6.0", optional = true }
43-
luau0-src = { version = "0.7.0", optional = true }
43+
luau0-src = { version = "0.7.7", optional = true }

mlua-sys/build/main_inner.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ cfg_if::cfg_if! {
99
}
1010

1111
fn main() {
12-
#[cfg(all(feature = "luau", feature = "module"))]
13-
compile_error!("Luau does not support `module` mode");
12+
#[cfg(all(feature = "luau", feature = "module", windows))]
13+
compile_error!("Luau does not support `module` mode on Windows");
1414

1515
#[cfg(all(feature = "module", feature = "vendored"))]
1616
compile_error!("`vendored` and `module` features are mutually exclusive");

mlua-sys/src/luau/lua.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use std::marker::{PhantomData, PhantomPinned};
44
use std::os::raw::{c_char, c_double, c_float, c_int, c_uint, c_void};
5-
use std::ptr;
5+
use std::{mem, ptr};
66

77
// Option for multiple returns in 'lua_pcall' and 'lua_call'
88
pub const LUA_MULTRET: c_int = -1;
@@ -278,6 +278,7 @@ extern "C-unwind" {
278278
pub fn lua_getuserdatadtor(L: *mut lua_State, tag: c_int) -> Option<lua_Destructor>;
279279
pub fn lua_clonefunction(L: *mut lua_State, idx: c_int);
280280
pub fn lua_cleartable(L: *mut lua_State, idx: c_int);
281+
pub fn lua_getallocf(L: *mut lua_State, ud: *mut *mut c_void) -> lua_Alloc;
281282
}
282283

283284
//
@@ -325,6 +326,15 @@ pub unsafe fn lua_newuserdata(L: *mut lua_State, sz: usize) -> *mut c_void {
325326
lua_newuserdatatagged(L, sz, 0)
326327
}
327328

329+
#[inline(always)]
330+
pub unsafe fn lua_newuserdata_t<T>(L: *mut lua_State) -> *mut T {
331+
unsafe extern "C-unwind" fn destructor<T>(ud: *mut c_void) {
332+
ptr::drop_in_place(ud as *mut T);
333+
}
334+
335+
lua_newuserdatadtor(L, mem::size_of::<T>(), destructor::<T>) as *mut T
336+
}
337+
328338
// TODO: lua_strlen
329339

330340
#[inline(always)]

src/lua.rs

Lines changed: 58 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
use std::any::TypeId;
22
use std::cell::{RefCell, UnsafeCell};
33
use std::ffi::{CStr, CString};
4-
use std::fmt;
54
use std::marker::PhantomData;
65
use std::mem::MaybeUninit;
76
use std::ops::Deref;
87
use std::os::raw::{c_char, c_int, c_void};
98
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe, Location};
10-
use std::ptr::NonNull;
119
use std::result::Result as StdResult;
1210
use std::sync::atomic::{AtomicPtr, Ordering};
1311
use std::sync::{Arc, Mutex};
14-
use std::{mem, ptr, str};
12+
use std::{fmt, mem, ptr, str};
1513

1614
use rustc_hash::FxHashMap;
1715

@@ -60,6 +58,7 @@ use {
6058
crate::types::{AsyncCallback, AsyncCallbackUpvalue, AsyncPollUpvalue},
6159
futures_util::future::{self, Future},
6260
futures_util::task::{noop_waker_ref, Context, Poll, Waker},
61+
std::ptr::NonNull,
6362
};
6463

6564
#[cfg(feature = "serialize")]
@@ -94,7 +93,6 @@ pub(crate) struct ExtraData {
9493

9594
safe: bool,
9695
libs: StdLib,
97-
mem_state: Option<NonNull<MemoryState>>,
9896
#[cfg(feature = "module")]
9997
skip_memory_check: bool,
10098

@@ -244,11 +242,14 @@ impl Drop for Lua {
244242
impl Drop for LuaInner {
245243
fn drop(&mut self) {
246244
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+
251247
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+
}
252253
}
253254
}
254255
}
@@ -261,9 +262,6 @@ impl Drop for ExtraData {
261262
}
262263

263264
*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-
}
267265
}
268266
}
269267

@@ -359,36 +357,34 @@ impl Lua {
359357
///
360358
/// [`StdLib`]: crate::StdLib
361359
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+
362365
#[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"))]
363372
{
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 _);
379376
}
380377

381378
Self::inner_new(libs, options)
382379
}
383380

384381
/// Creates a new Lua state with required `libs` and `options`
385382
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());
387384
let mut state = ffi::lua_newstate(ALLOCATOR, mem_state as *mut c_void);
388385
// If state is null then switch to Lua internal allocator
389386
if state.is_null() {
390387
drop(Box::from_raw(mem_state));
391-
mem_state = ptr::null_mut();
392388
state = ffi::luaL_newstate();
393389
}
394390
assert!(!state.is_null(), "Failed to instantiate Lua VM");
@@ -404,7 +400,6 @@ impl Lua {
404400

405401
let lua = Lua::init_from_ptr(state);
406402
let extra = lua.extra.get();
407-
(*extra).mem_state = NonNull::new(mem_state);
408403

409404
mlua_expect!(
410405
load_from_std_lib(state, libs),
@@ -440,7 +435,7 @@ impl Lua {
440435
}
441436

442437
#[cfg(feature = "luau")]
443-
mlua_expect!(lua.prepare_luau_state(), "Error preparing Luau state");
438+
mlua_expect!(lua.prepare_luau_state(), "Error configuring Luau");
444439

445440
lua
446441
}
@@ -514,7 +509,6 @@ impl Lua {
514509
app_data: AppData::default(),
515510
safe: false,
516511
libs: StdLib::NONE,
517-
mem_state: None,
518512
#[cfg(feature = "module")]
519513
skip_memory_check: false,
520514
ref_thread,
@@ -547,14 +541,8 @@ impl Lua {
547541

548542
// Store it in the registry
549543
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"
558546
);
559547

560548
// Register `DestructedUserdata` type
@@ -572,13 +560,6 @@ impl Lua {
572560
);
573561
assert_stack(main_state, ffi::LUA_MINSTACK);
574562

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-
582563
let inner = Arc::new(LuaInner {
583564
state: AtomicPtr::new(state),
584565
main_state,
@@ -1098,9 +1079,9 @@ impl Lua {
10981079
/// Returns the amount of memory (in bytes) currently used inside this Lua state.
10991080
pub fn used_memory(&self) -> usize {
11001081
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+
_ => {
11041085
// Get data from the Lua GC
11051086
let used_kbytes = ffi::lua_gc(self.main_state, ffi::LUA_GCCOUNT, 0);
11061087
let used_kbytes_rem = ffi::lua_gc(self.main_state, ffi::LUA_GCCOUNTB, 0);
@@ -1119,9 +1100,9 @@ impl Lua {
11191100
/// Does not work in module mode where Lua state is managed externally.
11201101
pub fn set_memory_limit(&self, limit: usize) -> Result<usize> {
11211102
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),
11251106
}
11261107
}
11271108
}
@@ -3169,9 +3150,9 @@ impl Lua {
31693150
#[inline]
31703151
pub(crate) unsafe fn unlikely_memory_error(&self) -> bool {
31713152
// 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)
31753156
.unwrap_or_else(|| {
31763157
// Alternatively, check the special flag (only for module mode)
31773158
#[cfg(feature = "module")]
@@ -3223,14 +3204,6 @@ impl LuaInner {
32233204
}
32243205
}
32253206

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-
32343207
struct StateGuard<'a>(&'a LuaInner, *mut ffi::lua_State);
32353208

32363209
impl<'a> StateGuard<'a> {
@@ -3246,13 +3219,13 @@ impl<'a> Drop for StateGuard<'a> {
32463219
}
32473220
}
32483221

3249-
#[cfg(feature = "luau")]
32503222
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+
}
32533228

3254-
#[cfg(not(feature = "luau"))]
3255-
unsafe fn extra_data(state: *mut ffi::lua_State) -> *mut ExtraData {
32563229
let extra_key = &EXTRA_REGISTRY_KEY as *const u8 as *const c_void;
32573230
if ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, extra_key) != ffi::LUA_TUSERDATA {
32583231
// `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 {
32653238
(*extra_ptr).get()
32663239
}
32673240

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+
32683258
// Creates required entries in the metatable cache (see `util::METATABLE_CACHE`)
32693259
pub(crate) fn init_metatable_cache(cache: &mut FxHashMap<TypeId, u8>) {
32703260
cache.insert(TypeId::of::<Arc<UnsafeCell<ExtraData>>>(), 0);

0 commit comments

Comments
 (0)