From 34781051fcc62d293aa805bbd20f0bfca05b5ef4 Mon Sep 17 00:00:00 2001 From: Nerry <108566+neri@users.noreply.github.com> Date: Mon, 23 Sep 2024 04:21:12 +0900 Subject: [PATCH] update --- lib/wami_macro/Cargo.toml | 4 +- lib/wami_macro/src/lib.rs | 30 ++++++++++++- src/cg/intr.rs | 87 ++++++++++++++++++++++++++++++-------- src/stack.rs | 46 +++++++++----------- src/tests.rs | 6 +-- src/wasm.rs | 8 ++-- test/tester.wasm | Bin 6287 -> 4907 bytes 7 files changed, 126 insertions(+), 55 deletions(-) diff --git a/lib/wami_macro/Cargo.toml b/lib/wami_macro/Cargo.toml index a571d6f..3363fe5 100644 --- a/lib/wami_macro/Cargo.toml +++ b/lib/wami_macro/Cargo.toml @@ -8,5 +8,5 @@ version = "0.1.0" proc-macro = true [dependencies] -syn = {version = "2.0.72", features = ["full", "extra-traits","printing"]} -quote = {version = "1.0.36"} +syn = {version = "2.0.77", features = ["full", "extra-traits","printing"]} +quote = {version = "1.0.37"} diff --git a/lib/wami_macro/src/lib.rs b/lib/wami_macro/src/lib.rs index 8739a8b..3a96d92 100644 --- a/lib/wami_macro/src/lib.rs +++ b/lib/wami_macro/src/lib.rs @@ -254,9 +254,9 @@ pub fn wasm_exports(_attr: TokenStream, input: TokenStream) -> TokenStream { output_impl.push(format!("let args = [{}];", push_args.join(","))); output_impl.push(format!( "self.instance().exports().get({:?}) - .ok_or(WasmRuntimeErrorKind::NoMethod.into()) + .ok_or(WasmRuntimeErrorKind::NoMethod({:?}.to_owned()).into()) .and_then(|v| v.invoke(&args))", - func_name + func_name, func_name, )); match result_type { Some(ref result_type) => output_impl.push(format!( @@ -360,6 +360,13 @@ impl ParsedType { Some(path) } syn::Type::Reference(reference) => { + if options.allow_intrinsics { + if let Some(intrinsics) = + IntrinsicType::from_ref(reference.elem.as_ref(), options) + { + return Some(ParsedType::IntrinsicType(intrinsics)); + } + } if options.allow_reference { Self::new( reference.elem.as_ref(), @@ -625,6 +632,25 @@ impl IntrinsicType { } } + pub fn from_ref(ty: &syn::Type, options: ParseOption) -> Option { + // For some reason it is not always possible to get the content of the `span` in the usual way + let _ = options; + match ty { + syn::Type::Path(type_path) => { + let mut segments = type_path.path.segments.iter(); + let Some(first_elem) = segments.next() else { + return None; + }; + match first_elem.ident.to_string().as_str() { + "WasmInstance" => Some(Self::WasmInstance), + "str" => Some(Self::Str), + _ => None, + } + } + _ => None, + } + } + pub fn to_string(&self) -> Cow<'static, str> { match self { Self::WasmInstance => Cow::Borrowed("&WasmInstance"), diff --git a/src/cg/intr.rs b/src/cg/intr.rs index d254b50..a70adeb 100644 --- a/src/cg/intr.rs +++ b/src/cg/intr.rs @@ -6,6 +6,7 @@ use crate::memory::WasmMemory; use crate::stack::*; use crate::wasm::*; use crate::*; +use alloc::format; use core::error::Error; use core::iter; use core::mem::{size_of, transmute}; @@ -19,6 +20,14 @@ const INITIAL_VALUE_STACK_SIZE: usize = 512; pub struct WasmInterpreter<'a> { instance: &'a WasmInstance, func_index: usize, + stack_trace: Vec, +} + +#[derive(Debug, Clone)] +pub struct StackTraceEntry { + pub func: u32, + pub position: u32, + pub name: Option, } impl<'a> WasmInterpreter<'a> { @@ -27,6 +36,7 @@ impl<'a> WasmInterpreter<'a> { Self { instance, func_index: 0, + stack_trace: Vec::new(), } } } @@ -52,6 +62,16 @@ impl WasmInterpreter<'_> { .unwrap_or(0) + ex_position.position(); + let mut stack_trace = self.stack_trace.clone(); + for item in stack_trace.iter_mut() { + item.name = self + .instance + .module() + .names() + .and_then(|v| v.func_by_index(item.func as usize)) + .map(|v| v.to_owned()); + } + Box::new(WasmRuntimeError { kind, file_position, @@ -59,6 +79,7 @@ impl WasmInterpreter<'_> { function_name, position: ex_position.position(), mnemonic, + stack_trace, }) } @@ -269,7 +290,7 @@ impl WasmInterpreter<'_> { let index = unsafe { value_stack.get(code.base_stack_level()).get_i32() as usize }; let func = self.instance.module().elem_get(index).ok_or(self.error( - WasmRuntimeErrorKind::NoMethod, + WasmRuntimeErrorKind::NoMethod(format!("$elem({index})")), opcode, ex_position, ))?; @@ -1572,6 +1593,11 @@ impl WasmInterpreter<'_> { locals }; + self.stack_trace.push(StackTraceEntry { + func: self.func_index as u32, + position: ex_position.position() as u32, + name: None, + }); self._interpret( target.index(), code_block, @@ -1584,6 +1610,7 @@ impl WasmInterpreter<'_> { let var = value_stack.get_mut(stack_under); *var = WasmUnionValue::from(result); } + self.stack_trace.pop(); self.func_index = current_function; Ok(()) }) @@ -1612,9 +1639,11 @@ impl WasmInterpreter<'_> { } }) } - WasmFunctionContent::Unresolved => { - Err(self.error(WasmRuntimeErrorKind::NoMethod, opcode, ex_position)) - } + WasmFunctionContent::Unresolved => Err(self.error( + WasmRuntimeErrorKind::NoMethod(format!("$func({})", target.index())), + opcode, + ex_position, + )), } } } @@ -1662,7 +1691,10 @@ impl WasmInvocation for WasmRunnable<'_> { let code_block = match function.content() { WasmFunctionContent::CodeBlock(v) => Ok(v), WasmFunctionContent::Dynamic(_) => Err(WasmRuntimeErrorKind::InvalidParameter), - WasmFunctionContent::Unresolved => Err(WasmRuntimeErrorKind::NoMethod), + WasmFunctionContent::Unresolved => Err(WasmRuntimeErrorKind::NoMethod(format!( + "$func({})", + function.index() + ))), }?; let mut locals = @@ -1699,6 +1731,7 @@ pub struct WasmRuntimeError { function_name: Option, position: usize, mnemonic: WasmMnemonic, + stack_trace: Vec, } impl WasmRuntimeError { @@ -1762,6 +1795,7 @@ impl From for Box { function_name: None, position: 0, mnemonic: WasmMnemonic::Unreachable, + stack_trace: Vec::new(), }) } } @@ -1770,20 +1804,39 @@ impl fmt::Display for WasmRuntimeError { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mnemonic = self.mnemonic(); - write!(f, "{:?} at", self.kind())?; - if let Some(function_name) = self.function_name() { - write!( - f, - " {}(${}):{}", - function_name, - self.function(), - self.position(), - )?; - } else { - write!(f, " ${}:{}", self.function(), self.position(),)?; + write!(f, "{:?}", self.kind())?; + + // In wasm, positon is never zero. + if self.position() > 0 { + write!(f, "\n at")?; + if let Some(function_name) = self.function_name() { + write!( + f, + " {}(${}):{}", + function_name, + self.function(), + self.position(), + )?; + } else { + write!(f, " ${}:{}", self.function(), self.position(),)?; + } + } + if self.file_position() > 0 { + write!(f, ", 0x{:x}: {:?}", self.file_position(), mnemonic)?; + } + + if self.stack_trace.len() > 0 { + writeln!(f, "")?; + for item in self.stack_trace.iter().rev() { + if let Some(name) = item.name.as_ref() { + writeln!(f, " at {}(${}):{}", name, item.func, item.position)?; + } else { + writeln!(f, " at {}:{}", item.func, item.position)?; + } + } } - write!(f, ", 0x{:x}: {:?}", self.file_position(), mnemonic) + Ok(()) } } diff --git a/src/stack.rs b/src/stack.rs index 2621153..8aff6ac 100644 --- a/src/stack.rs +++ b/src/stack.rs @@ -1,8 +1,7 @@ //! Stack structure for the Webassembly Runtime use crate::*; use core::cell::UnsafeCell; -use core::mem::align_of; -use core::mem::size_of; +use core::mem::{self, align_of, size_of}; use core::slice; /// Fixed size stack @@ -38,12 +37,7 @@ impl FixedStack<'_, T> { } } -impl FixedStack<'_, T> { - #[inline] - pub fn remove_all(&mut self) { - while self.pop().is_some() {} - } - +impl FixedStack<'_, T> { #[inline] pub fn last(&self) -> Option<&T> { if self.stack_pointer > 0 { @@ -89,20 +83,20 @@ impl FixedStack<'_, T> { } } -impl FixedStack<'_, T> { - #[track_caller] - pub fn resize(&mut self, new_size: usize, new_value: T) { - if new_size < self.slice.len() { - if self.stack_pointer < new_size { - let _ = new_value; - todo!(); - } - self.stack_pointer = new_size; - } else { - todo!() - } - } -} +// impl FixedStack<'_, T> { +// #[track_caller] +// pub fn resize(&mut self, new_size: usize, new_value: T) { +// if new_size < self.slice.len() { +// if self.stack_pointer < new_size { +// let _ = new_value; +// todo!(); +// } +// self.stack_pointer = new_size; +// } else { +// todo!() +// } +// } +// } /// Shared Stack pub struct StackHeap { @@ -134,17 +128,15 @@ impl StackHeap { { let Self { vec, stack_pointer } = self; - let vec = unsafe { vec.get().replace(Vec::new()) }; + let vec = UnsafeCell::new(unsafe { vec.get().read() }); let mut child = Self { - vec: UnsafeCell::new(vec), + vec, stack_pointer: *stack_pointer, }; let r = f(&mut child); - unsafe { - self.vec.get().replace(child.vec.into_inner()); - } + mem::forget(child.vec); r } diff --git a/src/tests.rs b/src/tests.rs index 07ea4d7..e7fc0d7 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,8 +1,8 @@ -use crate::cg::intr::WasmInterpreter; use crate::cg::WasmCodeBlock; +use crate::cg::intr::WasmInterpreter; use crate::opcode::WasmMnemonic; use crate::prelude::*; -use crate::{leb128::*, WasmSectionId}; +use crate::{WasmSectionId, leb128::*}; use core::f64::consts::PI; use num_traits::Zero; use std::assert_matches::assert_matches; @@ -1297,7 +1297,7 @@ fn call_indirect_test() { .unwrap_err() .downcast() .unwrap(); - assert_matches!(err.kind(), WasmRuntimeErrorKind::NoMethod); + assert_matches!(err.kind(), WasmRuntimeErrorKind::NoMethod(_)); } } diff --git a/src/wasm.rs b/src/wasm.rs index 78a4de1..c1e800b 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -541,7 +541,7 @@ impl WasmModule { } #[inline] - pub fn custom_sections<'a>(&'a self, section_name: &str) -> Option<&Box<[u8]>> { + pub fn custom_sections(&self, section_name: &str) -> Option<&Box<[u8]>> { self.custom_sections.get(section_name) } @@ -602,7 +602,7 @@ impl WasmModule { } } } - Err(WasmRuntimeErrorKind::NoMethod) + Err(WasmRuntimeErrorKind::NoMethod(name.to_owned())) } #[inline] @@ -1733,7 +1733,7 @@ pub enum WasmLinkError { impl fmt::Display for WasmLinkError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) + write!(f, "LinkError: {:?}", self) } } @@ -1756,7 +1756,7 @@ pub enum WasmRuntimeErrorKind { /// (unrecoverable) Memory Boundary Errors OutOfBounds, /// (unrecoverable) The specified function cannot be found. - NoMethod, + NoMethod(String), /// (unrecoverable) Devide by zero DivideByZero, /// (unrecoverable) The type of call instructions do not match. diff --git a/test/tester.wasm b/test/tester.wasm index 1f68b5da0895aa96cdb2b2cd4cd4cfc4c90ac981..c7e907142a5809e6d5b5e1e0c1126e3817aac8e8 100644 GIT binary patch literal 4907 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 H%X9xf{-E^$