From c687e2aba30ca231b03288108b632f1bad464028 Mon Sep 17 00:00:00 2001 From: Mica White Date: Wed, 29 Jul 2026 21:19:57 -0400 Subject: Script optimization --- src/script.rs | 249 ++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 171 insertions(+), 78 deletions(-) (limited to 'src/script.rs') diff --git a/src/script.rs b/src/script.rs index 8539c92..a2cb76d 100644 --- a/src/script.rs +++ b/src/script.rs @@ -1,4 +1,4 @@ -use std::path::Path; +use std::{path::Path, sync::Arc}; use rustc_hash::FxHashMap; @@ -7,11 +7,13 @@ use crate::{ file::{FileManager, GameManifest}, input::InputManager, scene::{preload_scene, switch_scenes}, + script::wasm::WasmModule, storage::StorageManager, time::TimeContext, }; -mod wasm; +pub mod lua; +pub mod wasm; pub struct ScriptManager<'a> { scripts: &'a [ScriptDeclaration], @@ -20,9 +22,11 @@ pub struct ScriptManager<'a> { script_states: FxHashMap>, } +#[derive(Clone)] pub struct WasmRunner { - pub engine: wasmi::Engine, - pub linker: wasmi::Linker>, + pub engine: tinywasm::Engine, + pub store: Arc>, + pub linker: tinywasm::Imports, } pub struct ScriptContext<'a> { @@ -41,7 +45,7 @@ pub struct FullScriptContext<'a> { pub input: &'a InputManager, pub time: &'a TimeContext, pub scripts: &'a ScriptManager<'a>, - pub files: &'a FileManager, + pub files: Box<[Box]>, pub storage: &'a StorageManager, pub wasm_runner: &'a WasmRunner, pub operation_queue: &'a mut Vec, @@ -79,6 +83,10 @@ pub enum ScriptDeclaration { update: StaticScriptFunction, end: StaticScriptFunction, }, + Lua { + name: Box, + path: Box, + }, Wasm { name: Box, path: Box, @@ -104,66 +112,62 @@ impl Default for WasmRunner { impl WasmRunner { pub fn new() -> Self { - let engine = wasmi::Engine::default(); - let linker = unsafe { - std::mem::transmute::< - wasmi::Linker>, - wasmi::Linker>, - >(wasm::linker(&engine).unwrap()) - }; - Self { engine, linker } + let engine = tinywasm::Engine::default(); + let mut store = tinywasm::Store::new(engine.clone()); + let linker = wasm::linker(&mut store).unwrap(); + let store = Arc::new(spin::Mutex::new(store)); + Self { + engine, + store, + linker, + } } - pub fn compile(&self, data: &[u8]) -> Result { - wasmi::Module::new(&self.engine, data) + pub fn compile(&self, data: &[u8]) -> Result { + let module = tinywasm::parse_bytes(data)?; + let instance = tinywasm::ModuleInstance::instantiate( + &mut self.store.lock(), + &module, + Some(self.linker.clone()), + )?; + Ok(WasmModule { instance }) } - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] pub fn run_function( &self, script_id: usize, - module: &wasmi::Module, + module: &mut WasmModule, scripts: &ScriptManager, - files: &FileManager, + files: Box<[Box]>, wasm_runner: &WasmRunner, context: &mut ScriptContext<'_>, function_name: &str, - ) -> Result<(), wasmi::Error> { - // safety: the store won't be kept around after this function ends. Only the - // lifetimes are being transmuted - let mut store = { - puffin::profile_scope!("create store"); - wasmi::Store::new(&self.engine, unsafe { - std::mem::transmute::, FullScriptContext<'_>>( - FullScriptContext { - script_id, - manifest: context.manifest, - buffer: context.buffer, - input: context.input, - time: context.time, - storage: context.storage, - scripts, - files, - wasm_runner, - operation_queue: &mut context.operation_queue, - }, - ) - }) - }; - let instance = { - puffin::profile_scope!("instantiate"); - self.linker.instantiate_and_start(&mut store, module)? - }; - let function = { - puffin::profile_scope!("get function"); - instance.get_func(&store, function_name).ok_or_else(|| { - wasmi::Error::new(format!("No function named {function_name} was exported")) - })? - }; - { - puffin::profile_scope!("call function"); - function.call(&mut store, &[], &mut []) - } + ) -> Result<(), tinywasm::Error> { + puffin::profile_function!(); + + let context = std::ptr::from_mut(Box::leak(Box::new(FullScriptContext { + script_id, + manifest: context.manifest, + buffer: context.buffer, + input: context.input, + time: context.time, + storage: context.storage, + scripts, + files, + wasm_runner, + operation_queue: &mut context.operation_queue, + }))); + + let function = module + .instance + .func::(&wasm_runner.store.lock(), function_name)?; + let r = function.call( + &mut wasm_runner.store.lock(), + context.expose_provenance() as u64, + ); + drop(unsafe { Box::from_raw(context) }); + r } } @@ -185,6 +189,11 @@ impl<'a> ScriptManager<'a> { return Some(i); } } + ScriptDeclaration::Lua { name, .. } => { + if &**name == needle { + return Some(i); + } + } ScriptDeclaration::Wasm { name, .. } => { if &**name == needle { return Some(i); @@ -205,17 +214,17 @@ impl<'a> ScriptManager<'a> { let script = &self.scripts[script_id]; match script { ScriptDeclaration::Static { .. } => (), - ScriptDeclaration::Wasm { path, .. } => { - files.start_loading_file(path, &wasm_runner.engine) - } + ScriptDeclaration::Lua { path, .. } => files.start_loading_file(path, wasm_runner), + ScriptDeclaration::Wasm { path, .. } => files.start_loading_file(path, wasm_runner), } } - pub fn is_script_loaded(&self, script_id: usize, files: &FileManager) -> bool { + pub fn is_script_loaded(&self, script_id: usize, loaded_files: &[Box]) -> bool { let script = &self.scripts[script_id]; match script { ScriptDeclaration::Static { .. } => true, - ScriptDeclaration::Wasm { path, .. } => files.is_file_loaded(path), + ScriptDeclaration::Lua { path, .. } => loaded_files.contains(path), + ScriptDeclaration::Wasm { path, .. } => loaded_files.contains(path), } } @@ -223,6 +232,7 @@ impl<'a> ScriptManager<'a> { let script = &self.scripts[script_id]; match script { ScriptDeclaration::Static { .. } => (), + ScriptDeclaration::Lua { path, .. } => files.unload_file(path), ScriptDeclaration::Wasm { path, .. } => files.unload_file(path), } } @@ -284,7 +294,9 @@ impl<'a> ScriptManager<'a> { Operation::UpdateState { script_id, new_state, - } => *get_script_state(&mut self.script_states, *script_id) = new_state.clone(), + } => { + self.script_states.insert(*script_id, new_state.clone()); + } Operation::UpdateEntity { name, new_state } => { self.entities.insert(name.clone(), new_state.clone()); } @@ -316,18 +328,46 @@ impl<'a> ScriptManager<'a> { ) }); } + ScriptDeclaration::Lua { path, .. } => { + files.load_file(path.clone(), wasm_runner).unwrap(); + let loaded_files = files.loaded_files(); + let module = files.get_cached_file_mut(path).unwrap().unwrap_lua_module(); + if let Err(e) = module.run_function( + "start", + FullScriptContext { + script_id, + manifest: context.manifest, + buffer: context.buffer, + input: context.input, + time: context.time, + scripts: self, + files: loaded_files, + storage: context.storage, + wasm_runner, + operation_queue: &mut context.operation_queue, + }, + ) { + log::error!("{e}"); + } + } ScriptDeclaration::Wasm { path, .. } => { - files.load_file(path.clone(), &wasm_runner.engine).unwrap(); - let module = files.get_cached_file(path).unwrap().unwrap_wasm_module(); - wasm_runner.run_function( + files.load_file(path.clone(), wasm_runner).unwrap(); + let loaded_files = files.loaded_files(); + let module = files + .get_cached_file_mut(path) + .unwrap() + .unwrap_wasm_module_mut(); + if let Err(e) = wasm_runner.run_function( script_id, module, self, - files, + loaded_files, wasm_runner, context, "start", - ); + ) { + log::error!("{e}"); + } } } self.active_scripts.push(script_id); @@ -360,18 +400,46 @@ impl<'a> ScriptManager<'a> { ); }); } + ScriptDeclaration::Lua { path, .. } => { + files.load_file(path.clone(), wasm_runner).unwrap(); + let loaded_files = files.loaded_files(); + let module = files.get_cached_file_mut(path).unwrap().unwrap_lua_module(); + if let Err(e) = module.run_function( + "end", + FullScriptContext { + script_id, + manifest: context.manifest, + buffer: context.buffer, + input: context.input, + time: context.time, + scripts: self, + files: loaded_files, + storage: context.storage, + wasm_runner, + operation_queue: &mut context.operation_queue, + }, + ) { + log::error!("{e}"); + } + } ScriptDeclaration::Wasm { path, .. } => { - files.load_file(path.clone(), &wasm_runner.engine).unwrap(); - let module = files.get_cached_file(path).unwrap().unwrap_wasm_module(); - wasm_runner.run_function( + files.load_file(path.clone(), wasm_runner).unwrap(); + let loaded_files = files.loaded_files(); + let module = files + .get_cached_file_mut(path) + .unwrap() + .unwrap_wasm_module_mut(); + if let Err(e) = wasm_runner.run_function( script_id, module, self, - files, + loaded_files, wasm_runner, context, "end", - ); + ) { + log::error!("{e}"); + } } }; } @@ -399,21 +467,46 @@ impl<'a> ScriptManager<'a> { ) } } + ScriptDeclaration::Lua { path, .. } => { + files.load_file(path.clone(), wasm_runner).unwrap(); + let loaded_files = files.loaded_files(); + let module = files.get_cached_file_mut(path).unwrap().unwrap_lua_module(); + if let Err(e) = module.run_function( + "update", + FullScriptContext { + script_id: *script_id, + manifest: context.manifest, + buffer: context.buffer, + input: context.input, + time: context.time, + scripts: self, + files: loaded_files, + storage: context.storage, + wasm_runner, + operation_queue: &mut context.operation_queue, + }, + ) { + log::error!("{e}"); + } + } ScriptDeclaration::Wasm { path, .. } => { - let module = { - puffin::profile_scope!("load module"); - files.load_file(path.clone(), &wasm_runner.engine).unwrap(); - files.get_cached_file(path).unwrap().unwrap_wasm_module() - }; - wasm_runner.run_function( + files.load_file(path.clone(), wasm_runner).unwrap(); + let loaded_files = files.loaded_files(); + let module = files + .get_cached_file_mut(path) + .unwrap() + .unwrap_wasm_module_mut(); + if let Err(e) = wasm_runner.run_function( *script_id, module, self, - files, + loaded_files, wasm_runner, context, "update", - ); + ) { + log::error!("Error while running scripts: {e}"); + } } } } -- cgit v1.3.1