diff options
| author | Mica White <botahamec@outlook.com> | 2024-08-15 20:23:26 -0400 |
|---|---|---|
| committer | Mica White <botahamec@outlook.com> | 2024-08-25 19:24:37 -0400 |
| commit | 509e5ce1e17417a70b9bcce8bc6e33c05106811d (patch) | |
| tree | 5b1fe60a65b5f42a90023ead03c32336033afa1f /scripts/src/wasm.rs | |
| parent | db9aa9f1bf49e8bede384b9ceb1e1fb82b522799 (diff) | |
Start profiling
Diffstat (limited to 'scripts/src/wasm.rs')
| -rw-r--r-- | scripts/src/wasm.rs | 340 |
1 files changed, 170 insertions, 170 deletions
diff --git a/scripts/src/wasm.rs b/scripts/src/wasm.rs index 7ac9dae..06d840f 100644 --- a/scripts/src/wasm.rs +++ b/scripts/src/wasm.rs @@ -1,170 +1,170 @@ -use std::path::Path; - -use thiserror::Error; -use wasmtime::{Engine, Instance, Linker, Module, Mutability, Store, ValType}; - -// It's a bad idea to have the memory allocator return a number that could also -// indicate an error, so this is set to be at least eight. -const MIN_BUMP_POINTER: u32 = 8; - -/// Information about the script which can be used by functions it calls -pub struct WasmScriptState { - pub bump_pointer: u32, - pub trusted: bool, -} - -impl WasmScriptState { - pub const fn new(trusted: bool) -> Self { - Self { - bump_pointer: MIN_BUMP_POINTER, - trusted, - } - } -} - -/// A script, its path in the filesystem, and some metadata -pub struct WasmScript { - path: Box<Path>, - module: Module, - store: Store<WasmScriptState>, - instance: Instance, - trusted: bool, - //state: Value, -} - -#[derive(Debug, Error)] -pub enum InvalidWasmScript { - #[error("There is no exported memory called 'memory', which is required")] - NoExportedMemory, - #[error("The exported symbol, 'memory' must be a memory")] - MemoryIsNotAMemory, - #[error("The memory must be 32-bit, not 64-bit")] - MemoryTooLarge, - #[error("There is no exported global called '__heap_base', which is required")] - NoHeapBase, - #[error("The exported symbol, '__heap_base' must be a constant global")] - HeapBaseIsNotGlobal, - #[error("The exported global, '__heap_base' must be an i32")] - HeapBaseMustBeI32, - #[error("The exported global, '__heap_base' must be a constant")] - HeapBaseMustBeConstant, - #[error("{}", .0)] - CompilerError(#[from] wasmtime::Error), -} - -/// Confirms that the module can be used as a script -fn validate_module(module: &Module) -> Result<(), InvalidWasmScript> { - // verify that memory is exported from this module and is valid - let Some(export) = module.get_export("memory") else { - return Err(InvalidWasmScript::NoExportedMemory); - }; - let Some(memory) = export.memory() else { - return Err(InvalidWasmScript::MemoryIsNotAMemory); - }; - if memory.is_64() { - return Err(InvalidWasmScript::MemoryTooLarge); - } - - // verify __heap_base global - let Some(export) = module.get_export("__heap_base") else { - return Err(InvalidWasmScript::NoHeapBase); - }; - let Some(heap_base) = export.global() else { - return Err(InvalidWasmScript::HeapBaseIsNotGlobal); - }; - if *heap_base.content() != ValType::I32 { - return Err(InvalidWasmScript::HeapBaseMustBeI32); - } - if heap_base.mutability() != Mutability::Const { - return Err(InvalidWasmScript::HeapBaseMustBeConstant); - } - - Ok(()) -} - -impl WasmScript { - pub fn new( - path: &Path, - engine: &Engine, - linker: &Linker<WasmScriptState>, - trusted: bool, - ) -> Result<Self, InvalidWasmScript> { - let module = Module::from_file(engine, path)?; - validate_module(&module)?; - let mut store = Store::new(engine, WasmScriptState::new(trusted)); - let instance = linker.instantiate(&mut store, &module)?; - - Ok(Self { - path: path.into(), - module, - store, - instance, - trusted, - }) - } - - /// Reload from the filesystem - pub fn reload( - &mut self, - engine: &Engine, - linker: &Linker<WasmScriptState>, - ) -> Result<(), InvalidWasmScript> { - let module = Module::from_file(engine, &self.path)?; - validate_module(&module)?; - self.store = Store::new(engine, WasmScriptState::new(self.trusted)); - self.instance = linker.instantiate(&mut self.store, &module)?; - - Ok(()) - } - - /// Re-links the module. This doesn't load the module from the filesystem. - pub fn relink( - &mut self, - engine: &Engine, - linker: &Linker<WasmScriptState>, - ) -> Result<(), InvalidWasmScript> { - self.store = Store::new(engine, WasmScriptState::new(self.trusted)); - self.instance = linker.instantiate(&mut self.store, &self.module)?; - Ok(()) - } - - pub fn is_trusted(&self) -> bool { - self.trusted - } - - pub fn trust(&mut self) { - self.trusted = true; - } - - pub fn untrust(&mut self) { - self.trusted = false; - } - - fn run_function_if_exists(&mut self, name: &str) -> wasmtime::Result<()> { - // set bump pointer to the start of the heap - let heap_base = self - .instance - .get_global(&mut self.store, "__heap_base") - .unwrap() - .get(&mut self.store) - .unwrap_i32(); - let bump_ptr = &mut self.store.data_mut().bump_pointer; - *bump_ptr = (heap_base as u32).max(MIN_BUMP_POINTER); - - // call the given function - let func = self.instance.get_func(&mut self.store, name); - if let Some(func) = func { - func.call(&mut self.store, &[], &mut [])?; - } - - Ok(()) - } - - pub fn begin(&mut self) -> wasmtime::Result<()> { - self.run_function_if_exists("begin") - } - - pub fn update(&mut self) -> wasmtime::Result<()> { - self.run_function_if_exists("update") - } -} +use std::path::Path;
+
+use thiserror::Error;
+use wasmtime::{Engine, Instance, Linker, Module, Mutability, Store, ValType};
+
+// It's a bad idea to have the memory allocator return a number that could also
+// indicate an error, so this is set to be at least eight.
+const MIN_BUMP_POINTER: u32 = 8;
+
+/// Information about the script which can be used by functions it calls
+pub struct WasmScriptState {
+ pub bump_pointer: u32,
+ pub trusted: bool,
+}
+
+impl WasmScriptState {
+ pub const fn new(trusted: bool) -> Self {
+ Self {
+ bump_pointer: MIN_BUMP_POINTER,
+ trusted,
+ }
+ }
+}
+
+/// A script, its path in the filesystem, and some metadata
+pub struct WasmScript {
+ path: Box<Path>,
+ module: Module,
+ store: Store<WasmScriptState>,
+ instance: Instance,
+ trusted: bool,
+ //state: Value,
+}
+
+#[derive(Debug, Error)]
+pub enum InvalidWasmScript {
+ #[error("There is no exported memory called 'memory', which is required")]
+ NoExportedMemory,
+ #[error("The exported symbol, 'memory' must be a memory")]
+ MemoryIsNotAMemory,
+ #[error("The memory must be 32-bit, not 64-bit")]
+ MemoryTooLarge,
+ #[error("There is no exported global called '__heap_base', which is required")]
+ NoHeapBase,
+ #[error("The exported symbol, '__heap_base' must be a constant global")]
+ HeapBaseIsNotGlobal,
+ #[error("The exported global, '__heap_base' must be an i32")]
+ HeapBaseMustBeI32,
+ #[error("The exported global, '__heap_base' must be a constant")]
+ HeapBaseMustBeConstant,
+ #[error("{}", .0)]
+ CompilerError(#[from] wasmtime::Error),
+}
+
+/// Confirms that the module can be used as a script
+fn validate_module(module: &Module) -> Result<(), InvalidWasmScript> {
+ // verify that memory is exported from this module and is valid
+ let Some(export) = module.get_export("memory") else {
+ return Err(InvalidWasmScript::NoExportedMemory);
+ };
+ let Some(memory) = export.memory() else {
+ return Err(InvalidWasmScript::MemoryIsNotAMemory);
+ };
+ if memory.is_64() {
+ return Err(InvalidWasmScript::MemoryTooLarge);
+ }
+
+ // verify __heap_base global
+ let Some(export) = module.get_export("__heap_base") else {
+ return Err(InvalidWasmScript::NoHeapBase);
+ };
+ let Some(heap_base) = export.global() else {
+ return Err(InvalidWasmScript::HeapBaseIsNotGlobal);
+ };
+ if *heap_base.content() != ValType::I32 {
+ return Err(InvalidWasmScript::HeapBaseMustBeI32);
+ }
+ if heap_base.mutability() != Mutability::Const {
+ return Err(InvalidWasmScript::HeapBaseMustBeConstant);
+ }
+
+ Ok(())
+}
+
+impl WasmScript {
+ pub fn new(
+ path: &Path,
+ engine: &Engine,
+ linker: &Linker<WasmScriptState>,
+ trusted: bool,
+ ) -> Result<Self, InvalidWasmScript> {
+ let module = Module::from_file(engine, path)?;
+ validate_module(&module)?;
+ let mut store = Store::new(engine, WasmScriptState::new(trusted));
+ let instance = linker.instantiate(&mut store, &module)?;
+
+ Ok(Self {
+ path: path.into(),
+ module,
+ store,
+ instance,
+ trusted,
+ })
+ }
+
+ /// Reload from the filesystem
+ pub fn reload(
+ &mut self,
+ engine: &Engine,
+ linker: &Linker<WasmScriptState>,
+ ) -> Result<(), InvalidWasmScript> {
+ let module = Module::from_file(engine, &self.path)?;
+ validate_module(&module)?;
+ self.store = Store::new(engine, WasmScriptState::new(self.trusted));
+ self.instance = linker.instantiate(&mut self.store, &module)?;
+
+ Ok(())
+ }
+
+ /// Re-links the module. This doesn't load the module from the filesystem.
+ pub fn relink(
+ &mut self,
+ engine: &Engine,
+ linker: &Linker<WasmScriptState>,
+ ) -> Result<(), InvalidWasmScript> {
+ self.store = Store::new(engine, WasmScriptState::new(self.trusted));
+ self.instance = linker.instantiate(&mut self.store, &self.module)?;
+ Ok(())
+ }
+
+ pub fn is_trusted(&self) -> bool {
+ self.trusted
+ }
+
+ pub fn trust(&mut self) {
+ self.trusted = true;
+ }
+
+ pub fn untrust(&mut self) {
+ self.trusted = false;
+ }
+
+ fn run_function_if_exists(&mut self, name: &str) -> wasmtime::Result<()> {
+ // set bump pointer to the start of the heap
+ let heap_base = self
+ .instance
+ .get_global(&mut self.store, "__heap_base")
+ .unwrap()
+ .get(&mut self.store)
+ .unwrap_i32();
+ let bump_ptr = &mut self.store.data_mut().bump_pointer;
+ *bump_ptr = (heap_base as u32).max(MIN_BUMP_POINTER);
+
+ // call the given function
+ let func = self.instance.get_func(&mut self.store, name);
+ if let Some(func) = func {
+ func.call(&mut self.store, &[], &mut [])?;
+ }
+
+ Ok(())
+ }
+
+ pub fn begin(&mut self) -> wasmtime::Result<()> {
+ self.run_function_if_exists("begin")
+ }
+
+ pub fn update(&mut self) -> wasmtime::Result<()> {
+ self.run_function_if_exists("update")
+ }
+}
|
