├── md5-bin ├── .gitignore ├── Cargo.toml └── src │ └── main.rs ├── .gitignore ├── cl8w-on-wasm-bin ├── .gitignore ├── Cargo.toml └── src │ └── main.rs ├── cl8w-wasm ├── cl8w-ex.wasm ├── memory.wasm └── cl8w-gcd.wasm ├── src ├── structure │ ├── mod.rs │ ├── values.rs │ ├── types.rs │ ├── instructions.rs │ └── modules.rs ├── validation │ └── mod.rs ├── wasm_error.rs ├── binary │ ├── util.rs │ ├── test_helper.rs │ ├── mod.rs │ ├── decoder.rs │ ├── encoder.rs │ ├── parser.rs │ ├── values.rs │ ├── types.rs │ ├── modules.rs │ └── instructions.rs ├── lib.rs └── exec │ ├── mod.rs │ ├── utils.rs │ ├── global.rs │ ├── table.rs │ ├── numerics.rs │ ├── mem.rs │ ├── val.rs │ ├── func.rs │ ├── instance.rs │ └── stack.rs ├── .gitmodules ├── Cargo.toml ├── README.md ├── examples ├── cl8w-on-wasm-on-wasm.rs ├── md5.rs ├── cl8w-ex.rs └── cl8w-gcd.rs ├── LICENSE ├── .github └── workflows │ └── main.yml └── tests └── spec.rs /md5-bin/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | /wast-dist/ 5 | -------------------------------------------------------------------------------- /cl8w-on-wasm-bin/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /cl8w-wasm/cl8w-ex.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kgtkr/wasm-rs/HEAD/cl8w-wasm/cl8w-ex.wasm -------------------------------------------------------------------------------- /cl8w-wasm/memory.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kgtkr/wasm-rs/HEAD/cl8w-wasm/memory.wasm -------------------------------------------------------------------------------- /src/structure/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod instructions; 2 | pub mod modules; 3 | pub mod types; 4 | pub mod values; 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "WebAssembly/spec"] 2 | path = WebAssembly/spec 3 | url = https://github.com/WebAssembly/spec.git 4 | -------------------------------------------------------------------------------- /src/validation/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::structure::modules::Module; 2 | 3 | pub fn validation(_module: &Module) -> bool { 4 | true 5 | } 6 | -------------------------------------------------------------------------------- /src/wasm_error.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, PartialEq)] 2 | pub enum WasmError { 3 | RuntimeError, 4 | LinkError, 5 | CompileError, 6 | } 7 | -------------------------------------------------------------------------------- /src/binary/util.rs: -------------------------------------------------------------------------------- 1 | use super::Encoder; 2 | 3 | pub fn loop_encode(xs: &Vec, bytes: &mut Vec) { 4 | for x in xs { 5 | x.encode(bytes); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![recursion_limit = "1024"] 2 | #![type_length_limit = "2097152"] 3 | 4 | pub mod binary; 5 | pub mod exec; 6 | pub mod structure; 7 | pub mod validation; 8 | mod wasm_error; 9 | pub use wasm_error::WasmError; 10 | -------------------------------------------------------------------------------- /cl8w-wasm/cl8w-gcd.wasm: -------------------------------------------------------------------------------- 1 | asm````/resourcememory 2 | memorymallocioprintpmaingcd 3 | A  4 | V 5 | A A IA!  6A!  6 ( (oAF ( ( ( (o -------------------------------------------------------------------------------- /md5-bin/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "md5-bin" 3 | version = "0.1.0" 4 | authors = ["kgtkr "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | md5 = "*" 11 | -------------------------------------------------------------------------------- /src/binary/test_helper.rs: -------------------------------------------------------------------------------- 1 | use super::{Decoder, Encoder}; 2 | use proptest::prelude::*; 3 | 4 | pub fn identity_encode_decode() { 5 | proptest!(|(x: T)| { 6 | assert_eq!(Decoder::decode_to_end(&x.encode_to_vec()), Ok(x)); 7 | }); 8 | } 9 | -------------------------------------------------------------------------------- /src/structure/values.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | use proptest_derive::Arbitrary; 3 | 4 | #[derive(Debug, Clone, PartialEq, Copy)] 5 | #[cfg_attr(test, derive(Arbitrary))] 6 | pub struct Byte(pub u8); 7 | 8 | #[derive(Debug, Clone, PartialEq)] 9 | #[cfg_attr(test, derive(Arbitrary))] 10 | pub struct Name(pub String); 11 | -------------------------------------------------------------------------------- /cl8w-on-wasm-bin/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cl8w-on-wasm-bin" 3 | version = "0.1.0" 4 | authors = ["kgtkr "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | wasm-rs = { path = "../" } 11 | maplit = "1.0.2" -------------------------------------------------------------------------------- /src/exec/mod.rs: -------------------------------------------------------------------------------- 1 | mod func; 2 | mod instance; 3 | mod mem; 4 | mod numerics; 5 | mod stack; 6 | mod utils; 7 | pub use func::FuncAddr; 8 | pub use mem::MemAddr; 9 | mod table; 10 | pub use table::TableAddr; 11 | mod global; 12 | pub use global::GlobalAddr; 13 | mod val; 14 | pub use instance::{ExternalVal, ImportObjects, ModuleInst}; 15 | pub use val::Val; 16 | -------------------------------------------------------------------------------- /src/binary/mod.rs: -------------------------------------------------------------------------------- 1 | mod decoder; 2 | mod encoder; 3 | mod instructions; 4 | mod modules; 5 | mod parser; 6 | mod types; 7 | mod util; 8 | mod values; 9 | 10 | use decoder::Decoder; 11 | use encoder::Encoder; 12 | #[cfg(test)] 13 | mod test_helper; 14 | 15 | use super::structure::modules::Module; 16 | 17 | pub fn encode_module(module: &Module) -> Vec { 18 | module.encode_to_vec() 19 | } 20 | 21 | pub fn decode_module(bytes: &[u8]) -> Result> { 22 | Module::decode_to_end(bytes) 23 | } 24 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasm-rs" 3 | version = "0.1.0" 4 | authors = ["kgtkr "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | byteorder = "1" 9 | leb128 = "0.2" 10 | nom = "5.0.1" 11 | num = "0.2.0" 12 | frunk = "0.3.0" 13 | generic-array = "0.13.2" 14 | typenum = "1.11.2" 15 | 16 | 17 | [dev-dependencies] 18 | proptest-derive = { git = "https://github.com/alessandrod/proptest.git", rev = "983253ec281c5e71ca16e726eabe6a8dbf5be675" } 19 | proptest = "0.9.4" 20 | lazy_static = "*" 21 | maplit = "1.0.2" 22 | serde_json = "1.0.44" -------------------------------------------------------------------------------- /md5-bin/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::{c_void, CString}; 2 | use std::mem::forget; 3 | 4 | #[no_mangle] 5 | pub extern "C" fn md5(input: *mut i8) -> *const i8 { 6 | let s = CString::new(format!( 7 | "{:x}", 8 | md5::compute(unsafe { CString::from_raw(input) }.into_bytes()) 9 | )) 10 | .unwrap(); 11 | let p = s.as_ptr(); 12 | forget(s); 13 | p 14 | } 15 | 16 | #[no_mangle] 17 | pub fn alloc(size: usize) -> *mut c_void { 18 | let mut buf = Vec::with_capacity(size); 19 | let p = buf.as_mut_ptr(); 20 | forget(buf); 21 | p 22 | } 23 | 24 | fn main() {} 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wasm-rs 2 | 3 | ## Run Examples 4 | 5 | ``` 6 | $ cargo build --all-targets --release 7 | 8 | $ cargo run --example cl8w-ex --release 9 | 10 | $ cargo run --example cl8w-gcd --release 11 | 12 | $ (cd md5-bin && cargo build --target wasm32-unknown-unknown --release) 13 | $ cargo run --example md5 --release 14 | 15 | $ (cd cl8w-on-wasm-bin && cargo build --target wasm32-unknown-unknown --release) 16 | $ cargo run --example cl8w-on-wasm-on-wasm --release 17 | ``` 18 | 19 | ## Test 20 | 21 | ``` 22 | $ git submodule init 23 | $ git submodule update 24 | $ ./build-spec.sh 25 | $ cargo test 26 | ``` -------------------------------------------------------------------------------- /src/binary/decoder.rs: -------------------------------------------------------------------------------- 1 | use super::parser::eof; 2 | use nom::{sequence::tuple, IResult}; 3 | 4 | pub trait Decoder 5 | where 6 | Self: std::marker::Sized, 7 | { 8 | fn decode(input: &[u8]) -> IResult<&[u8], Self>; 9 | 10 | fn decode_to_end(input: &[u8]) -> Result> { 11 | let (_, (x, _)) = tuple((Self::decode, eof()))(input)?; 12 | Ok(x) 13 | } 14 | } 15 | 16 | impl Decoder for (A, B) 17 | where 18 | A: Decoder, 19 | B: Decoder, 20 | { 21 | fn decode(input: &[u8]) -> IResult<&[u8], Self> { 22 | tuple((A::decode, B::decode))(input) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/binary/encoder.rs: -------------------------------------------------------------------------------- 1 | pub trait Encoder { 2 | fn encode(&self, bytes: &mut Vec); 3 | 4 | fn encode_to_vec(&self) -> Vec { 5 | let mut bytes = Vec::new(); 6 | self.encode(&mut bytes); 7 | bytes 8 | } 9 | } 10 | 11 | impl Encoder for &T 12 | where 13 | T: Encoder, 14 | { 15 | fn encode(&self, bytes: &mut Vec) { 16 | (*self).encode(bytes); 17 | } 18 | } 19 | 20 | impl Encoder for (A, B) 21 | where 22 | A: Encoder, 23 | B: Encoder, 24 | { 25 | fn encode(&self, bytes: &mut Vec) { 26 | self.0.encode(bytes); 27 | self.1.encode(bytes); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/cl8w-on-wasm-on-wasm.rs: -------------------------------------------------------------------------------- 1 | use maplit::hashmap; 2 | use wasm_rs::binary::decode_module; 3 | use wasm_rs::exec::{ExternalVal, FuncAddr, ModuleInst}; 4 | fn main() { 5 | let print = ExternalVal::Func(FuncAddr::alloc_host(|(x,): (i32,)| { 6 | println!("{}", x); 7 | Ok(()) 8 | })); 9 | 10 | let module = decode_module( 11 | &std::fs::read( 12 | "cl8w-on-wasm-bin/target/wasm32-unknown-unknown/release/cl8w-on-wasm-bin.wasm", 13 | ) 14 | .unwrap(), 15 | ) 16 | .unwrap(); 17 | let instance = ModuleInst::new( 18 | &module, 19 | hashmap! { 20 | "env".to_string() => hashmap!{ 21 | "print".to_string() => print 22 | } 23 | }, 24 | ) 25 | .unwrap(); 26 | 27 | instance.export("run").unwrap_func().call(vec![]).unwrap(); 28 | } 29 | -------------------------------------------------------------------------------- /src/exec/utils.rs: -------------------------------------------------------------------------------- 1 | pub fn pop_n(vec: &mut Vec, n: usize) -> Vec { 2 | vec.split_off(vec.len() - n) 3 | } 4 | 5 | #[test] 6 | fn test_pop_n() { 7 | assert_eq!(pop_n::(&mut vec![], 0), vec![] as Vec); 8 | assert_eq!(pop_n::(&mut vec![1, 2, 3, 4, 5], 2), vec![4, 5]); 9 | } 10 | 11 | pub enum Sign { 12 | Positive, 13 | Negative, 14 | } 15 | 16 | pub fn sign_f32(x: f32) -> Option { 17 | if x.is_sign_positive() { 18 | Some(Sign::Positive) 19 | } else if x.is_sign_negative() { 20 | Some(Sign::Negative) 21 | } else { 22 | None 23 | } 24 | } 25 | 26 | pub fn sign_f64(x: f64) -> Option { 27 | if x.is_sign_positive() { 28 | Some(Sign::Positive) 29 | } else if x.is_sign_negative() { 30 | Some(Sign::Negative) 31 | } else { 32 | None 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 tkr 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/exec/global.rs: -------------------------------------------------------------------------------- 1 | use crate::structure::types::{GlobalType, Mut}; 2 | 3 | use super::val::Val; 4 | use std::cell::RefCell; 5 | use std::cell::{Ref, RefMut}; 6 | use std::rc::Rc; 7 | 8 | #[derive(Debug, Clone, PartialEq)] 9 | struct GlobalInst { 10 | value: Val, 11 | mut_: Mut, 12 | } 13 | 14 | #[derive(Clone, Debug, PartialEq)] 15 | pub struct GlobalAddr(Rc>); 16 | 17 | impl GlobalAddr { 18 | fn mut_inst(&self) -> RefMut { 19 | self.0.borrow_mut() 20 | } 21 | 22 | fn inst(&self) -> Ref { 23 | self.0.borrow() 24 | } 25 | 26 | pub fn type_(&self) -> GlobalType { 27 | let inst = self.inst(); 28 | GlobalType(inst.mut_.clone(), inst.value.val_type()) 29 | } 30 | 31 | pub fn new(mut_: Mut, val: Val) -> GlobalAddr { 32 | GlobalAddr(Rc::new(RefCell::new(GlobalInst { value: val, mut_ }))) 33 | } 34 | 35 | pub(super) fn alloc(type_: GlobalType, val: Val) -> GlobalAddr { 36 | GlobalAddr::new(type_.0, val) 37 | } 38 | 39 | pub fn get(&self) -> Val { 40 | self.inst().value 41 | } 42 | 43 | pub fn set(&self, val: Val) -> Option<()> { 44 | let mut inst = self.mut_inst(); 45 | if inst.mut_ == Mut::Var && inst.value.val_type() == val.val_type() { 46 | inst.value = val; 47 | Some(()) 48 | } else { 49 | None 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /examples/md5.rs: -------------------------------------------------------------------------------- 1 | use maplit::hashmap; 2 | use std::ffi::CString; 3 | use wasm_rs::binary::decode_module; 4 | use wasm_rs::exec::{ModuleInst, Val}; 5 | 6 | fn main() { 7 | let module = decode_module( 8 | &std::fs::read("md5-bin/target/wasm32-unknown-unknown/release/md5-bin.wasm").unwrap(), 9 | ) 10 | .unwrap(); 11 | let instance = ModuleInst::new(&module, hashmap! {}).unwrap(); 12 | 13 | let input_bytes = CString::new("abc").unwrap().into_bytes(); 14 | let input_ptr = instance 15 | .export("alloc") 16 | .unwrap_func() 17 | .call(vec![Val::I32(input_bytes.len() as i32)]) 18 | .unwrap() 19 | .unwrap() 20 | .unwrap_i32(); 21 | 22 | instance 23 | .export("memory") 24 | .unwrap_mem() 25 | .write_buffer(input_ptr, &input_bytes[..]); 26 | 27 | let output_ptr = instance 28 | .export("md5") 29 | .unwrap_func() 30 | .call(vec![Val::I32(input_ptr as i32)]) 31 | .unwrap() 32 | .unwrap() 33 | .unwrap_i32() as usize; 34 | 35 | let mem = instance.export("memory").unwrap_mem(); 36 | println!( 37 | "{}", 38 | CString::new( 39 | mem.into_iter() 40 | .skip(output_ptr) 41 | .take_while(|x| *x != 0) 42 | .collect::>(), 43 | ) 44 | .unwrap() 45 | .into_string() 46 | .unwrap() 47 | ); 48 | } 49 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: main 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build_and_test: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v1 10 | - run: | 11 | git submodule init 12 | git submodule update 13 | - run: | 14 | git clone --recursive https://github.com/WebAssembly/wabt 15 | cd wabt 16 | git checkout 1.0.12 17 | make 18 | echo ::add-path::$PWD/bin 19 | - uses: actions-rs/toolchain@v1 20 | with: 21 | toolchain: nightly 22 | target: wasm32-unknown-unknown 23 | override: true 24 | default: true 25 | - run: | 26 | ./build-spec.sh 27 | cargo test 28 | - run: | 29 | cargo build --all-targets --release 30 | 31 | test "$(cargo run --example cl8w-ex --release -q)" = "$(echo -n -e "1\n3\n5\n7\n9\n11\n13\n15\n17\n19\n")" 32 | 33 | test "$(cargo run --example cl8w-gcd --release -q)" = "$(echo -n -e "4\n")" 34 | 35 | (cd md5-bin && cargo build --target wasm32-unknown-unknown --release) 36 | test "$(cargo run --example md5 --release -q)" = "$(echo -n -e "900150983cd24fb0d6963f7d28e17f72\n")" 37 | 38 | (cd cl8w-on-wasm-bin && cargo build --target wasm32-unknown-unknown --release) 39 | test "$(cargo run --example cl8w-on-wasm-on-wasm --release -q)" = "$(echo -n -e "1\n3\n5\n7\n9\n11\n13\n15\n17\n19\n")" 40 | -------------------------------------------------------------------------------- /examples/cl8w-ex.rs: -------------------------------------------------------------------------------- 1 | use wasm_rs::binary::decode_module; 2 | use wasm_rs::exec::{ModuleInst, ExternalVal, FuncAddr, MemAddr}; 3 | use maplit::hashmap; 4 | 5 | fn main(){ 6 | let memory = ExternalVal::Mem(MemAddr::new(10, None)); 7 | let print = ExternalVal::Func(FuncAddr::alloc_host(|(x,): (i32,)| { 8 | println!("{}", x); 9 | Ok(()) 10 | })); 11 | 12 | let memory_module = 13 | decode_module(&std::fs::read("cl8w-wasm/memory.wasm").unwrap()).unwrap(); 14 | let memory_instance = ModuleInst::new( 15 | &memory_module, 16 | hashmap! { 17 | "resource".to_string() => hashmap!{ 18 | "memory".to_string() => memory.clone() 19 | } 20 | }, 21 | ) 22 | .unwrap(); 23 | 24 | let main_module = 25 | decode_module(&std::fs::read("cl8w-wasm/cl8w-ex.wasm").unwrap()).unwrap(); 26 | let main_instance = ModuleInst::new( 27 | &main_module, 28 | hashmap! { 29 | "resource".to_string() => hashmap!{ 30 | "memory".to_string() => memory.clone() 31 | }, 32 | "memory".to_string() => memory_instance.exports(), 33 | "io".to_string() => hashmap!{ 34 | "print".to_string() => print.clone() 35 | } 36 | }, 37 | ) 38 | .unwrap(); 39 | 40 | main_instance 41 | .export("main") 42 | .unwrap_func() 43 | .call(vec![]) 44 | .unwrap(); 45 | } -------------------------------------------------------------------------------- /examples/cl8w-gcd.rs: -------------------------------------------------------------------------------- 1 | use wasm_rs::binary::decode_module; 2 | use wasm_rs::exec::{ModuleInst, ExternalVal, FuncAddr, MemAddr}; 3 | use maplit::hashmap; 4 | 5 | fn main(){ 6 | let memory = ExternalVal::Mem(MemAddr::new(10, None)); 7 | let print = ExternalVal::Func(FuncAddr::alloc_host(|(x,): (i32,)| { 8 | println!("{}", x); 9 | Ok(()) 10 | })); 11 | 12 | let memory_module = 13 | decode_module(&std::fs::read("cl8w-wasm/memory.wasm").unwrap()).unwrap(); 14 | let memory_instance = ModuleInst::new( 15 | &memory_module, 16 | hashmap! { 17 | "resource".to_string() => hashmap!{ 18 | "memory".to_string() => memory.clone() 19 | } 20 | }, 21 | ) 22 | .unwrap(); 23 | 24 | let main_module = 25 | decode_module(&std::fs::read("cl8w-wasm/cl8w-gcd.wasm").unwrap()).unwrap(); 26 | let main_instance = ModuleInst::new( 27 | &main_module, 28 | hashmap! { 29 | "resource".to_string() => hashmap!{ 30 | "memory".to_string() => memory.clone() 31 | }, 32 | "memory".to_string() => memory_instance.exports(), 33 | "io".to_string() => hashmap!{ 34 | "print".to_string() => print.clone() 35 | } 36 | }, 37 | ) 38 | .unwrap(); 39 | 40 | main_instance 41 | .export("main") 42 | .unwrap_func() 43 | .call(vec![]) 44 | .unwrap(); 45 | } -------------------------------------------------------------------------------- /cl8w-on-wasm-bin/src/main.rs: -------------------------------------------------------------------------------- 1 | use maplit::hashmap; 2 | use wasm_rs::binary::decode_module; 3 | use wasm_rs::exec::{ExternalVal, FuncAddr, MemAddr, ModuleInst}; 4 | 5 | fn main() {} 6 | 7 | extern "C" { 8 | fn print(x: i32) -> (); 9 | } 10 | 11 | #[no_mangle] 12 | pub extern "C" fn run() { 13 | let memory = ExternalVal::Mem(MemAddr::new(10, None)); 14 | let print = ExternalVal::Func(FuncAddr::alloc_host(|(x,): (i32,)| { 15 | unsafe { 16 | print(x); 17 | } 18 | Ok(()) 19 | })); 20 | 21 | let memory_module = decode_module(include_bytes!("../../cl8w-wasm/memory.wasm")).unwrap(); 22 | let memory_instance = ModuleInst::new( 23 | &memory_module, 24 | hashmap!( 25 | "resource".to_string() => hashmap!( 26 | "memory".to_string() => memory.clone() 27 | ) 28 | ), 29 | ) 30 | .unwrap(); 31 | 32 | let main_module = decode_module(include_bytes!("../../cl8w-wasm/cl8w-ex.wasm")).unwrap(); 33 | let main_instance = ModuleInst::new( 34 | &main_module, 35 | hashmap!( 36 | "resource".to_string() => hashmap!( 37 | "memory".to_string() => memory.clone() 38 | ), 39 | "memory".to_string() => memory_instance.exports(), 40 | "io".to_string() => hashmap!( 41 | "print".to_string() => print.clone() 42 | ) 43 | ), 44 | ) 45 | .unwrap(); 46 | 47 | main_instance 48 | .export("main") 49 | .unwrap_func() 50 | .call(vec![]) 51 | .unwrap(); 52 | } 53 | -------------------------------------------------------------------------------- /src/binary/parser.rs: -------------------------------------------------------------------------------- 1 | use nom::{ 2 | bytes::complete::{take}, 3 | combinator::map, 4 | error::ParseError, 5 | IResult, InputIter, InputTake, 6 | }; 7 | 8 | pub fn any>() -> impl Fn(Input) -> IResult 9 | where 10 | Input: InputIter + InputTake + Clone, 11 | { 12 | map(take(1usize), |x: Input| x.iter_indices().next().unwrap().1) 13 | } 14 | 15 | pub fn token<'a, Error: ParseError<&'a [u8]>>( 16 | x: u8, 17 | ) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], u8, Error> { 18 | move |input| { 19 | let (input, token) = any()(input)?; 20 | if token == x { 21 | Ok((input, token)) 22 | } else { 23 | Err(nom::Err::Error(Error::from_char(input, '?'))) 24 | } 25 | } 26 | } 27 | 28 | pub fn eof<'a, Error: ParseError<&'a [u8]>>() -> impl Fn(&'a [u8]) -> IResult<&'a [u8], (), Error> { 29 | |input| { 30 | if input.len() == 0 { 31 | Ok((input, ())) 32 | } else { 33 | Err(nom::Err::Error(Error::from_char(input, '?'))) 34 | } 35 | } 36 | } 37 | 38 | pub struct ReadBytes<'a> { 39 | bytes: &'a [u8], 40 | pos: usize, 41 | } 42 | 43 | impl<'a> std::io::Read for ReadBytes<'a> { 44 | fn read(&mut self, buf: &mut [u8]) -> std::io::Result { 45 | let old_pos = self.pos; 46 | for buf_x in buf { 47 | if let Some(x) = self.bytes.get(self.pos) { 48 | (*buf_x) = *x; 49 | self.pos += 1; 50 | } else { 51 | break; 52 | } 53 | } 54 | Ok(self.pos - old_pos) 55 | } 56 | } 57 | 58 | pub fn io_read<'a, O, Error: ParseError<&'a [u8]>>( 59 | f: impl Fn(&mut ReadBytes) -> Option, 60 | ) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], O, Error> { 61 | move |input| { 62 | let mut rb = ReadBytes { 63 | bytes: input, 64 | pos: 0, 65 | }; 66 | match f(&mut rb) { 67 | Some(x) => Ok((&input[rb.pos..], x)), 68 | None => Err(nom::Err::Error(Error::from_char(input, '?'))), 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/structure/types.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | use proptest_derive::Arbitrary; 3 | 4 | #[derive(Debug, Clone, PartialEq)] 5 | #[cfg_attr(test, derive(Arbitrary))] 6 | pub struct FuncType(pub Vec, pub Vec); 7 | 8 | impl FuncType { 9 | pub fn params(&self) -> &Vec { 10 | &self.0 11 | } 12 | 13 | pub fn ret(&self) -> Option<&ValType> { 14 | self.1.first() 15 | } 16 | 17 | pub fn is_match(&self, other: &FuncType) -> bool { 18 | self == other 19 | } 20 | } 21 | 22 | #[derive(Debug, Clone, PartialEq)] 23 | #[cfg_attr(test, derive(Arbitrary))] 24 | pub enum ValType { 25 | I32, 26 | I64, 27 | F32, 28 | F64, 29 | } 30 | 31 | #[derive(Debug, Clone, PartialEq)] 32 | #[cfg_attr(test, derive(Arbitrary))] 33 | pub struct Limits { 34 | pub min: u32, 35 | pub max: Option, 36 | } 37 | 38 | impl Limits { 39 | pub fn is_match(&self, other: &Limits) -> bool { 40 | (self.min >= other.min) 41 | && other 42 | .max 43 | .map(|other_max| { 44 | self.max 45 | .map(|self_max| self_max <= other_max) 46 | .unwrap_or(false) 47 | }) 48 | .unwrap_or(true) 49 | } 50 | } 51 | 52 | #[derive(Debug, Clone, PartialEq)] 53 | #[cfg_attr(test, derive(Arbitrary))] 54 | pub struct MemType(pub Limits); 55 | 56 | impl MemType { 57 | pub fn is_match(&self, other: &MemType) -> bool { 58 | self.0.is_match(&other.0) 59 | } 60 | } 61 | 62 | #[derive(Debug, Clone, PartialEq)] 63 | #[cfg_attr(test, derive(Arbitrary))] 64 | pub struct TableType(pub Limits, pub ElemType); 65 | 66 | impl TableType { 67 | pub fn is_match(&self, other: &TableType) -> bool { 68 | self.0.is_match(&other.0) && self.1 == other.1 69 | } 70 | } 71 | 72 | #[derive(Debug, Clone, PartialEq)] 73 | #[cfg_attr(test, derive(Arbitrary))] 74 | pub enum ElemType { 75 | FuncRef, 76 | } 77 | 78 | #[derive(Debug, Clone, PartialEq)] 79 | #[cfg_attr(test, derive(Arbitrary))] 80 | pub struct GlobalType(pub Mut, pub ValType); 81 | 82 | impl GlobalType { 83 | pub fn is_match(&self, other: &GlobalType) -> bool { 84 | self == other 85 | } 86 | } 87 | 88 | #[derive(Debug, Clone, PartialEq, Copy)] 89 | #[cfg_attr(test, derive(Arbitrary))] 90 | pub enum Mut { 91 | Const, 92 | Var, 93 | } 94 | 95 | #[derive(Debug, Clone, PartialEq)] 96 | #[cfg_attr(test, derive(Arbitrary))] 97 | pub struct ResultType(pub Option); 98 | -------------------------------------------------------------------------------- /src/exec/table.rs: -------------------------------------------------------------------------------- 1 | use super::FuncAddr; 2 | use crate::exec::instance::TypedIdxAccess; 3 | use crate::structure::modules::FuncIdx; 4 | use crate::structure::types::{ElemType, Limits, TableType}; 5 | use crate::WasmError; 6 | use std::cell::RefCell; 7 | use std::cell::{Ref, RefMut}; 8 | use std::rc::Rc; 9 | 10 | #[derive(Debug, Clone)] 11 | struct TableInst { 12 | max: Option, 13 | elem: Vec>, 14 | } 15 | 16 | #[derive(Clone, Debug)] 17 | pub struct TableAddr(Rc>); 18 | 19 | impl TableAddr { 20 | fn mut_inst(&self) -> RefMut { 21 | self.0.borrow_mut() 22 | } 23 | 24 | fn inst(&self) -> Ref { 25 | self.0.borrow() 26 | } 27 | 28 | pub fn new(min: u32, max: Option) -> TableAddr { 29 | TableAddr(Rc::new(RefCell::new(TableInst { 30 | max: max.map(|x| x as usize), 31 | elem: { 32 | let min = min as usize; 33 | let mut vec = Vec::with_capacity(min); 34 | vec.resize(min, None); 35 | vec 36 | }, 37 | }))) 38 | } 39 | 40 | pub(super) fn alloc(table: &TableType) -> TableAddr { 41 | TableAddr::new(table.0.min, table.0.max) 42 | } 43 | 44 | pub fn type_(&self) -> TableType { 45 | let inst = self.inst(); 46 | TableType( 47 | Limits { 48 | min: inst.elem.len() as u32, 49 | max: inst.max.map(|x| x as u32), 50 | }, 51 | ElemType::FuncRef, 52 | ) 53 | } 54 | 55 | pub(super) fn instantiation_valid( 56 | &self, 57 | offset: usize, 58 | init: &Vec, 59 | ) -> Result<(), WasmError> { 60 | let inst = self.inst(); 61 | if offset 62 | .checked_add(init.len()) 63 | .map(|x| x > inst.elem.len()) 64 | .unwrap_or(true) 65 | { 66 | Err(WasmError::LinkError) 67 | } else { 68 | Ok(()) 69 | } 70 | } 71 | 72 | pub(super) fn init_elem(&self, funcs: &Vec, offset: usize, init: &Vec) { 73 | let mut inst = self.mut_inst(); 74 | for (i, x) in init.iter().enumerate() { 75 | inst.elem[offset + i] = Some(funcs.get_idx(*x).clone()); 76 | } 77 | } 78 | 79 | pub fn len(&self) -> i32 { 80 | self.inst().elem.len() as i32 81 | } 82 | 83 | pub fn get(&self, i: i32) -> Option> { 84 | let i = i as usize; 85 | if i < self.len() as usize { 86 | Some(self.inst().elem[i].clone()) 87 | } else { 88 | None 89 | } 90 | } 91 | 92 | pub fn set(&self, i: i32, x: Option) -> Option<()> { 93 | let i = i as usize; 94 | if i < self.len() as usize { 95 | self.mut_inst().elem[i] = x; 96 | Some(()) 97 | } else { 98 | None 99 | } 100 | } 101 | 102 | pub fn grow(&self, add_size: i32) -> Option { 103 | let cur_len = self.len(); 104 | if self 105 | .inst() 106 | .max 107 | .map(|max| max as i32) 108 | .map(|max| max >= cur_len + add_size) 109 | .unwrap_or(true) 110 | { 111 | self.mut_inst() 112 | .elem 113 | .resize((cur_len + add_size) as usize, None); 114 | Some(cur_len) 115 | } else { 116 | None 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/structure/instructions.rs: -------------------------------------------------------------------------------- 1 | use super::modules::{FuncIdx, GlobalIdx, LabelIdx, LocalIdx, TypeIdx}; 2 | use super::types::ResultType; 3 | #[cfg(test)] 4 | use proptest_derive::Arbitrary; 5 | 6 | #[derive(Debug, Clone, PartialEq)] 7 | pub struct Expr(pub Vec); 8 | 9 | #[derive(Debug, Clone, PartialEq)] 10 | pub enum Instr { 11 | I32Const(i32), 12 | I64Const(i64), 13 | F32Const(f32), 14 | F64Const(f64), 15 | I32Clz, 16 | I32Ctz, 17 | I32Popcnt, 18 | I64Clz, 19 | I64Ctz, 20 | I64Popcnt, 21 | F32Abs, 22 | F32Neg, 23 | F32Sqrt, 24 | F32Ceil, 25 | F32Floor, 26 | F32Trunc, 27 | F32Nearest, 28 | F64Abs, 29 | F64Neg, 30 | F64Sqrt, 31 | F64Ceil, 32 | F64Floor, 33 | F64Trunc, 34 | F64Nearest, 35 | I32Add, 36 | I32Sub, 37 | I32Mul, 38 | I32DivS, 39 | I32DivU, 40 | I32RemS, 41 | I32RemU, 42 | I32And, 43 | I32Or, 44 | I32Xor, 45 | I32ShL, 46 | I32ShrS, 47 | I32ShrU, 48 | I32Rotl, 49 | I32Rotr, 50 | I64Add, 51 | I64Sub, 52 | I64Mul, 53 | I64DivS, 54 | I64DivU, 55 | I64RemS, 56 | I64RemU, 57 | I64And, 58 | I64Or, 59 | I64Xor, 60 | I64ShL, 61 | I64ShrS, 62 | I64ShrU, 63 | I64Rotl, 64 | I64Rotr, 65 | F32Add, 66 | F32Sub, 67 | F32Mul, 68 | F32Div, 69 | F32Min, 70 | F32Max, 71 | F32CopySign, 72 | F64Add, 73 | F64Sub, 74 | F64Mul, 75 | F64Div, 76 | F64Min, 77 | F64Max, 78 | F64CopySign, 79 | I32Eqz, 80 | I64Eqz, 81 | I32Eq, 82 | I32Ne, 83 | I32LtS, 84 | I32LtU, 85 | I32GtS, 86 | I32GtU, 87 | I32LeS, 88 | I32LeU, 89 | I32GeS, 90 | I32GeU, 91 | I64Eq, 92 | I64Ne, 93 | I64LtS, 94 | I64LtU, 95 | I64GtS, 96 | I64GtU, 97 | I64LeS, 98 | I64LeU, 99 | I64GeS, 100 | I64GeU, 101 | F32Eq, 102 | F32Ne, 103 | F32Lt, 104 | F32Gt, 105 | F32Le, 106 | F32Ge, 107 | F64Eq, 108 | F64Ne, 109 | F64Lt, 110 | F64Gt, 111 | F64Le, 112 | F64Ge, 113 | I32WrapI64, 114 | I64ExtendI32S, 115 | I64ExtendI32U, 116 | I32TruncF32S, 117 | I32TruncF32U, 118 | I32TruncF64S, 119 | I32TruncF64U, 120 | I64TruncF32S, 121 | I64TruncF32U, 122 | I64TruncF64S, 123 | I64TruncF64U, 124 | F32DemoteF64, 125 | F64PromoteF32, 126 | F32ConvertI32S, 127 | F32ConvertI32U, 128 | F32ConvertI64S, 129 | F32ConvertI64U, 130 | F64ConvertI32S, 131 | F64ConvertI32U, 132 | F64ConvertI64S, 133 | F64ConvertI64U, 134 | I32ReinterpretF32, 135 | I64ReinterpretF64, 136 | F32ReinterpretI32, 137 | F64ReinterpretI64, 138 | Drop, 139 | Select, 140 | LocalGet(LocalIdx), 141 | LocalSet(LocalIdx), 142 | LocalTee(LocalIdx), 143 | GlobalGet(GlobalIdx), 144 | GlobalSet(GlobalIdx), 145 | I32Load(Memarg), 146 | I64Load(Memarg), 147 | F32Load(Memarg), 148 | F64Load(Memarg), 149 | I32Store(Memarg), 150 | I64Store(Memarg), 151 | F32Store(Memarg), 152 | F64Store(Memarg), 153 | I32Load8S(Memarg), 154 | I32Load8U(Memarg), 155 | I64Load8S(Memarg), 156 | I64Load8U(Memarg), 157 | I32Load16S(Memarg), 158 | I32Load16U(Memarg), 159 | I64Load16S(Memarg), 160 | I64Load16U(Memarg), 161 | I64Load32S(Memarg), 162 | I64Load32U(Memarg), 163 | I32Store8(Memarg), 164 | I64Store8(Memarg), 165 | I32Store16(Memarg), 166 | I64Store16(Memarg), 167 | I64Store32(Memarg), 168 | MemorySize, 169 | MemoryGrow, 170 | Nop, 171 | Unreachable, 172 | Block(ResultType, Vec), 173 | Loop(ResultType, Vec), 174 | If(ResultType, Vec, Vec), 175 | Br(LabelIdx), 176 | BrIf(LabelIdx), 177 | BrTable(Vec, LabelIdx), 178 | Return, 179 | Call(FuncIdx), 180 | CallIndirect(TypeIdx), 181 | } 182 | 183 | #[derive(Debug, Clone, PartialEq)] 184 | #[cfg_attr(test, derive(Arbitrary))] 185 | pub struct Memarg { 186 | pub offset: u32, 187 | pub align: u32, 188 | } 189 | -------------------------------------------------------------------------------- /src/binary/values.rs: -------------------------------------------------------------------------------- 1 | use super::parser; 2 | use super::util::loop_encode; 3 | use super::{Decoder, Encoder}; 4 | use crate::structure::values::{Byte, Name}; 5 | use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; 6 | use leb128; 7 | use nom::{combinator::map, multi::many_m_n, IResult}; 8 | use std::convert::TryFrom; 9 | 10 | impl Encoder for Byte { 11 | fn encode(&self, bytes: &mut Vec) { 12 | bytes.push(self.0); 13 | } 14 | } 15 | 16 | impl Decoder for Byte { 17 | fn decode(input: &[u8]) -> IResult<&[u8], Byte> { 18 | map(parser::any(), Byte)(input) 19 | } 20 | } 21 | 22 | impl Encoder for i32 { 23 | fn encode(&self, bytes: &mut Vec) { 24 | leb128::write::signed(bytes, *self as i64).unwrap(); 25 | } 26 | } 27 | 28 | impl Decoder for i32 { 29 | fn decode(input: &[u8]) -> IResult<&[u8], i32> { 30 | parser::io_read(|rb| { 31 | leb128::read::signed(rb) 32 | .ok() 33 | .and_then(|x| i32::try_from(x).ok()) 34 | })(input) 35 | } 36 | } 37 | 38 | impl Encoder for i64 { 39 | fn encode(&self, bytes: &mut Vec) { 40 | leb128::write::signed(bytes, *self).unwrap(); 41 | } 42 | } 43 | 44 | impl Decoder for i64 { 45 | fn decode(input: &[u8]) -> IResult<&[u8], i64> { 46 | parser::io_read(|rb| leb128::read::signed(rb).ok())(input) 47 | } 48 | } 49 | 50 | impl Encoder for u32 { 51 | fn encode(&self, bytes: &mut Vec) { 52 | leb128::write::unsigned(bytes, *self as u64).unwrap(); 53 | } 54 | } 55 | 56 | impl Decoder for u32 { 57 | fn decode(input: &[u8]) -> IResult<&[u8], u32> { 58 | parser::io_read(|rb| { 59 | leb128::read::unsigned(rb) 60 | .ok() 61 | .and_then(|x| u32::try_from(x).ok()) 62 | })(input) 63 | } 64 | } 65 | 66 | impl Encoder for u64 { 67 | fn encode(&self, bytes: &mut Vec) { 68 | leb128::write::unsigned(bytes, *self).unwrap(); 69 | } 70 | } 71 | 72 | impl Decoder for u64 { 73 | fn decode(input: &[u8]) -> IResult<&[u8], u64> { 74 | parser::io_read(|rb| leb128::read::unsigned(rb).ok())(input) 75 | } 76 | } 77 | 78 | impl Encoder for f32 { 79 | fn encode(&self, bytes: &mut Vec) { 80 | bytes.write_f32::(*self).unwrap(); 81 | } 82 | } 83 | 84 | impl Decoder for f32 { 85 | fn decode(input: &[u8]) -> IResult<&[u8], f32> { 86 | parser::io_read(|rb| rb.read_f32::().ok())(input) 87 | } 88 | } 89 | 90 | impl Encoder for f64 { 91 | fn encode(&self, bytes: &mut Vec) { 92 | bytes.write_f64::(*self).unwrap(); 93 | } 94 | } 95 | 96 | impl Decoder for f64 { 97 | fn decode(input: &[u8]) -> IResult<&[u8], f64> { 98 | parser::io_read(|rb| rb.read_f64::().ok())(input) 99 | } 100 | } 101 | 102 | impl Encoder for Name { 103 | fn encode(&self, bytes: &mut Vec) { 104 | self.0.bytes().map(Byte).collect::>().encode(bytes); 105 | } 106 | } 107 | 108 | impl Decoder for Name { 109 | fn decode(input: &[u8]) -> IResult<&[u8], Name> { 110 | let (input, bytes) = Vec::::decode(input)?; 111 | let bytes = bytes.into_iter().map(|x| x.0).collect::>(); 112 | let s = String::from_utf8(bytes).map(Name); 113 | match s { 114 | Ok(x) => Ok((input, x)), 115 | Err(_) => Err(nom::Err::Error((input, nom::error::ErrorKind::Char))), 116 | } 117 | } 118 | } 119 | 120 | impl Encoder for Vec 121 | where 122 | T: Encoder, 123 | { 124 | fn encode(&self, bytes: &mut Vec) { 125 | (self.len() as u32).encode(bytes); 126 | loop_encode(self, bytes); 127 | } 128 | } 129 | 130 | impl Decoder for Vec { 131 | fn decode(input: &[u8]) -> IResult<&[u8], Vec> { 132 | p_vec(T::decode)(input) 133 | } 134 | } 135 | 136 | pub fn p_vec<'a, T, P: Fn(&'a [u8]) -> IResult<&'a [u8], T>>( 137 | p: P, 138 | ) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Vec> { 139 | move |input| { 140 | let (input, size) = u32::decode(input)?; 141 | let size = size as usize; 142 | many_m_n(size, size, &p)(input) 143 | } 144 | } 145 | 146 | #[test] 147 | fn tests() { 148 | use super::test_helper; 149 | 150 | test_helper::identity_encode_decode::(); 151 | test_helper::identity_encode_decode::(); 152 | test_helper::identity_encode_decode::(); 153 | test_helper::identity_encode_decode::(); 154 | test_helper::identity_encode_decode::(); 155 | test_helper::identity_encode_decode::(); 156 | test_helper::identity_encode_decode::(); 157 | test_helper::identity_encode_decode::(); 158 | test_helper::identity_encode_decode::>(); 159 | } 160 | -------------------------------------------------------------------------------- /src/exec/numerics.rs: -------------------------------------------------------------------------------- 1 | use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; 2 | use generic_array::{ArrayLength, GenericArray}; 3 | use std::io::Cursor; 4 | use typenum::{consts, Unsigned}; 5 | 6 | pub trait Byteable: Sized { 7 | type N: ArrayLength; 8 | 9 | fn to_bytes(self) -> GenericArray; 10 | fn from_bytes(bytes: &GenericArray) -> Self; 11 | } 12 | 13 | impl Byteable for i8 { 14 | type N = consts::U1; 15 | 16 | fn to_bytes(self) -> GenericArray { 17 | let mut buf = Vec::with_capacity(Self::N::to_usize()); 18 | buf.write_i8(self).unwrap(); 19 | GenericArray::clone_from_slice(&buf[..]) 20 | } 21 | fn from_bytes(bytes: &GenericArray) -> Self { 22 | let mut rdr = Cursor::new(bytes.as_slice()); 23 | rdr.read_i8().unwrap() 24 | } 25 | } 26 | 27 | impl Byteable for u8 { 28 | type N = consts::U1; 29 | 30 | fn to_bytes(self) -> GenericArray { 31 | let mut buf = Vec::with_capacity(Self::N::to_usize()); 32 | buf.write_u8(self).unwrap(); 33 | GenericArray::clone_from_slice(&buf[..]) 34 | } 35 | fn from_bytes(bytes: &GenericArray) -> Self { 36 | let mut rdr = Cursor::new(bytes.as_slice()); 37 | rdr.read_u8().unwrap() 38 | } 39 | } 40 | 41 | impl Byteable for i16 { 42 | type N = consts::U2; 43 | 44 | fn to_bytes(self) -> GenericArray { 45 | let mut buf = Vec::with_capacity(Self::N::to_usize()); 46 | buf.write_i16::(self).unwrap(); 47 | GenericArray::clone_from_slice(&buf[..]) 48 | } 49 | fn from_bytes(bytes: &GenericArray) -> Self { 50 | let mut rdr = Cursor::new(bytes.as_slice()); 51 | rdr.read_i16::().unwrap() 52 | } 53 | } 54 | 55 | impl Byteable for u16 { 56 | type N = consts::U2; 57 | 58 | fn to_bytes(self) -> GenericArray { 59 | let mut buf = Vec::with_capacity(Self::N::to_usize()); 60 | buf.write_u16::(self).unwrap(); 61 | GenericArray::clone_from_slice(&buf[..]) 62 | } 63 | fn from_bytes(bytes: &GenericArray) -> Self { 64 | let mut rdr = Cursor::new(bytes.as_slice()); 65 | rdr.read_u16::().unwrap() 66 | } 67 | } 68 | 69 | impl Byteable for i32 { 70 | type N = consts::U4; 71 | 72 | fn to_bytes(self) -> GenericArray { 73 | let mut buf = Vec::with_capacity(Self::N::to_usize()); 74 | buf.write_i32::(self).unwrap(); 75 | GenericArray::clone_from_slice(&buf[..]) 76 | } 77 | fn from_bytes(bytes: &GenericArray) -> Self { 78 | let mut rdr = Cursor::new(bytes.as_slice()); 79 | rdr.read_i32::().unwrap() 80 | } 81 | } 82 | 83 | impl Byteable for u32 { 84 | type N = consts::U4; 85 | 86 | fn to_bytes(self) -> GenericArray { 87 | let mut buf = Vec::with_capacity(Self::N::to_usize()); 88 | buf.write_u32::(self).unwrap(); 89 | GenericArray::clone_from_slice(&buf[..]) 90 | } 91 | fn from_bytes(bytes: &GenericArray) -> Self { 92 | let mut rdr = Cursor::new(bytes.as_slice()); 93 | rdr.read_u32::().unwrap() 94 | } 95 | } 96 | 97 | impl Byteable for i64 { 98 | type N = consts::U8; 99 | 100 | fn to_bytes(self) -> GenericArray { 101 | let mut buf = Vec::with_capacity(Self::N::to_usize()); 102 | buf.write_i64::(self).unwrap(); 103 | GenericArray::clone_from_slice(&buf[..]) 104 | } 105 | fn from_bytes(bytes: &GenericArray) -> Self { 106 | let mut rdr = Cursor::new(bytes.as_slice()); 107 | rdr.read_i64::().unwrap() 108 | } 109 | } 110 | 111 | impl Byteable for u64 { 112 | type N = consts::U8; 113 | 114 | fn to_bytes(self) -> GenericArray { 115 | let mut buf = Vec::with_capacity(Self::N::to_usize()); 116 | buf.write_u64::(self).unwrap(); 117 | GenericArray::clone_from_slice(&buf[..]) 118 | } 119 | fn from_bytes(bytes: &GenericArray) -> Self { 120 | let mut rdr = Cursor::new(bytes.as_slice()); 121 | rdr.read_u64::().unwrap() 122 | } 123 | } 124 | 125 | impl Byteable for f32 { 126 | type N = consts::U4; 127 | 128 | fn to_bytes(self) -> GenericArray { 129 | let mut buf = Vec::with_capacity(Self::N::to_usize()); 130 | buf.write_f32::(self).unwrap(); 131 | GenericArray::clone_from_slice(&buf[..]) 132 | } 133 | fn from_bytes(bytes: &GenericArray) -> Self { 134 | let mut rdr = Cursor::new(bytes.as_slice()); 135 | rdr.read_f32::().unwrap() 136 | } 137 | } 138 | 139 | impl Byteable for f64 { 140 | type N = consts::U8; 141 | 142 | fn to_bytes(self) -> GenericArray { 143 | let mut buf = Vec::with_capacity(Self::N::to_usize()); 144 | buf.write_f64::(self).unwrap(); 145 | GenericArray::clone_from_slice(&buf[..]) 146 | } 147 | fn from_bytes(bytes: &GenericArray) -> Self { 148 | let mut rdr = Cursor::new(bytes.as_slice()); 149 | rdr.read_f64::().unwrap() 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/structure/modules.rs: -------------------------------------------------------------------------------- 1 | use super::instructions::Expr; 2 | use super::types::{FuncType, GlobalType, MemType, TableType, ValType}; 3 | use super::values::{Byte, Name}; 4 | #[cfg(test)] 5 | use proptest_derive::Arbitrary; 6 | 7 | #[derive(Debug, Clone, PartialEq)] 8 | pub struct Module { 9 | pub types: Vec, 10 | pub funcs: Vec, 11 | pub tables: Vec, 12 | pub mems: Vec, 13 | pub globals: Vec, 14 | pub elem: Vec, 15 | pub data: Vec, 16 | pub start: Option, 17 | pub imports: Vec, 18 | pub exports: Vec, 19 | } 20 | 21 | pub trait TypedIdx 22 | where 23 | Self: Into, 24 | { 25 | fn to_idx(self) -> usize { 26 | self.into() as usize 27 | } 28 | } 29 | 30 | #[derive(Debug, Clone, PartialEq, Copy)] 31 | #[cfg_attr(test, derive(Arbitrary))] 32 | pub struct TypeIdx(pub u32); 33 | 34 | impl Into for TypeIdx { 35 | fn into(self) -> u32 { 36 | self.0 37 | } 38 | } 39 | 40 | impl TypedIdx for TypeIdx {} 41 | 42 | #[derive(Debug, Clone, PartialEq, Copy)] 43 | #[cfg_attr(test, derive(Arbitrary))] 44 | pub struct FuncIdx(pub u32); 45 | 46 | impl Into for FuncIdx { 47 | fn into(self) -> u32 { 48 | self.0 49 | } 50 | } 51 | 52 | impl TypedIdx for FuncIdx {} 53 | 54 | #[derive(Debug, Clone, PartialEq, Copy)] 55 | #[cfg_attr(test, derive(Arbitrary))] 56 | pub struct TableIdx(pub u32); 57 | 58 | impl Into for TableIdx { 59 | fn into(self) -> u32 { 60 | self.0 61 | } 62 | } 63 | 64 | impl TypedIdx for TableIdx {} 65 | 66 | #[derive(Debug, Clone, PartialEq, Copy)] 67 | #[cfg_attr(test, derive(Arbitrary))] 68 | pub struct MemIdx(pub u32); 69 | 70 | impl Into for MemIdx { 71 | fn into(self) -> u32 { 72 | self.0 73 | } 74 | } 75 | 76 | impl TypedIdx for MemIdx {} 77 | 78 | #[derive(Debug, Clone, PartialEq, Copy)] 79 | #[cfg_attr(test, derive(Arbitrary))] 80 | pub struct GlobalIdx(pub u32); 81 | 82 | impl Into for GlobalIdx { 83 | fn into(self) -> u32 { 84 | self.0 85 | } 86 | } 87 | 88 | impl TypedIdx for GlobalIdx {} 89 | 90 | #[derive(Debug, Clone, PartialEq, Copy)] 91 | #[cfg_attr(test, derive(Arbitrary))] 92 | pub struct LocalIdx(pub u32); 93 | 94 | impl Into for LocalIdx { 95 | fn into(self) -> u32 { 96 | self.0 97 | } 98 | } 99 | 100 | impl TypedIdx for LocalIdx {} 101 | 102 | #[derive(Debug, Clone, PartialEq, Copy)] 103 | #[cfg_attr(test, derive(Arbitrary))] 104 | pub struct LabelIdx(pub u32); 105 | 106 | impl Into for LabelIdx { 107 | fn into(self) -> u32 { 108 | self.0 109 | } 110 | } 111 | 112 | impl TypedIdx for LabelIdx {} 113 | 114 | #[derive(Debug, Clone, PartialEq)] 115 | pub struct Func { 116 | pub type_: TypeIdx, 117 | pub locals: Vec, 118 | pub body: Expr, 119 | } 120 | 121 | #[derive(Debug, Clone, PartialEq)] 122 | #[cfg_attr(test, derive(Arbitrary))] 123 | pub struct Table { 124 | pub type_: TableType, 125 | } 126 | 127 | #[derive(Debug, Clone, PartialEq)] 128 | #[cfg_attr(test, derive(Arbitrary))] 129 | pub struct Mem { 130 | pub type_: MemType, 131 | } 132 | 133 | #[derive(Debug, Clone, PartialEq)] 134 | pub struct Global { 135 | pub type_: GlobalType, 136 | // constant expression 137 | pub init: Expr, 138 | } 139 | 140 | #[derive(Debug, Clone, PartialEq)] 141 | pub struct Elem { 142 | pub table: TableIdx, 143 | // constant expression 144 | pub offset: Expr, 145 | pub init: Vec, 146 | } 147 | 148 | #[derive(Debug, Clone, PartialEq)] 149 | pub struct Data { 150 | pub data: MemIdx, 151 | // constant expression 152 | pub offset: Expr, 153 | pub init: Vec, 154 | } 155 | 156 | #[derive(Debug, Clone, PartialEq)] 157 | #[cfg_attr(test, derive(Arbitrary))] 158 | pub struct Start { 159 | pub func: FuncIdx, 160 | } 161 | 162 | #[derive(Debug, Clone, PartialEq)] 163 | #[cfg_attr(test, derive(Arbitrary))] 164 | pub struct Export { 165 | pub name: Name, 166 | pub desc: ExportDesc, 167 | } 168 | 169 | #[derive(Debug, Clone, PartialEq)] 170 | #[cfg_attr(test, derive(Arbitrary))] 171 | pub enum ExportDesc { 172 | Func(FuncIdx), 173 | Table(TableIdx), 174 | Mem(MemIdx), 175 | Global(GlobalIdx), 176 | } 177 | 178 | impl ExportDesc { 179 | pub fn unwrap_func(&self) -> FuncIdx { 180 | if let ExportDesc::Func(x) = self { 181 | *x 182 | } else { 183 | panic!(); 184 | } 185 | } 186 | 187 | pub fn unwrap_table(&self) -> TableIdx { 188 | if let ExportDesc::Table(x) = self { 189 | *x 190 | } else { 191 | panic!(); 192 | } 193 | } 194 | 195 | pub fn unwrap_mem(&self) -> MemIdx { 196 | if let ExportDesc::Mem(x) = self { 197 | *x 198 | } else { 199 | panic!(); 200 | } 201 | } 202 | 203 | pub fn unwrap_global(&self) -> GlobalIdx { 204 | if let ExportDesc::Global(x) = self { 205 | *x 206 | } else { 207 | panic!(); 208 | } 209 | } 210 | } 211 | 212 | #[derive(Debug, Clone, PartialEq)] 213 | #[cfg_attr(test, derive(Arbitrary))] 214 | pub struct Import { 215 | pub module: Name, 216 | pub name: Name, 217 | pub desc: ImportDesc, 218 | } 219 | 220 | #[derive(Debug, Clone, PartialEq)] 221 | #[cfg_attr(test, derive(Arbitrary))] 222 | pub enum ImportDesc { 223 | Func(TypeIdx), 224 | Table(TableType), 225 | Mem(MemType), 226 | Global(GlobalType), 227 | } 228 | -------------------------------------------------------------------------------- /src/exec/mem.rs: -------------------------------------------------------------------------------- 1 | use crate::structure::instructions::Memarg; 2 | use crate::structure::types::{Limits, MemType}; 3 | use crate::WasmError; 4 | use typenum::Unsigned; 5 | 6 | use super::numerics::Byteable; 7 | use generic_array::GenericArray; 8 | use std::cell::RefCell; 9 | use std::cell::{Ref, RefMut}; 10 | use std::convert::TryFrom; 11 | use std::rc::Rc; 12 | 13 | #[derive(Debug, Clone, PartialEq)] 14 | struct MemInst { 15 | max: Option, 16 | data: Vec, 17 | } 18 | 19 | impl MemInst { 20 | const PAGE_SIZE: usize = 65536; 21 | const MAX_PAGE_SIZE: i32 = 65536; 22 | } 23 | 24 | #[derive(Clone, Debug, PartialEq)] 25 | pub struct MemAddr(Rc>); 26 | 27 | impl MemAddr { 28 | fn mut_inst(&self) -> RefMut { 29 | self.0.borrow_mut() 30 | } 31 | 32 | fn inst(&self) -> Ref { 33 | self.0.borrow() 34 | } 35 | 36 | fn to_pos(memarg: &Memarg, ptr: i32) -> Option { 37 | ptr.checked_add(i32::try_from(memarg.offset).ok()?) 38 | } 39 | 40 | pub fn read_buffer(&self, pos: i32, len: i32) -> Option> { 41 | let pos = pos as usize; 42 | let len = len as usize; 43 | let raw = &self.inst().data; 44 | if pos.checked_add(len).map(|x| raw.len() < x).unwrap_or(true) { 45 | return None; 46 | } 47 | Some(Vec::from(&raw[pos..pos + len])) 48 | } 49 | 50 | pub fn get(&self, i: i32) -> Option { 51 | Some(self.read_buffer(i, 1)?[0]) 52 | } 53 | 54 | pub fn write_buffer(&self, pos: i32, buf: &[u8]) -> Option<()> { 55 | let pos = pos as usize; 56 | let raw = &mut self.mut_inst().data; 57 | if pos 58 | .checked_add(buf.len()) 59 | .map(|x| raw.len() < x) 60 | .unwrap_or(true) 61 | { 62 | return None; 63 | } 64 | for (i, x) in buf.into_iter().enumerate() { 65 | raw[pos + i] = *x; 66 | } 67 | Some(()) 68 | } 69 | 70 | pub fn set(&self, i: i32, x: u8) -> Option<()> { 71 | self.write_buffer(i, &[x]) 72 | } 73 | 74 | pub fn read(&self, memarg: &Memarg, ptr: i32) -> Result { 75 | let pos = MemAddr::to_pos(memarg, ptr).ok_or_else(|| WasmError::RuntimeError)?; 76 | Ok(T::from_bytes(GenericArray::from_slice( 77 | &self 78 | .read_buffer(pos, T::N::to_usize() as i32) 79 | .ok_or_else(|| WasmError::RuntimeError)?[..], 80 | ))) 81 | } 82 | 83 | pub fn write(&self, memarg: &Memarg, ptr: i32, x: T) -> Result<(), WasmError> { 84 | let pos = MemAddr::to_pos(memarg, ptr).ok_or_else(|| WasmError::RuntimeError)?; 85 | let buf = x.to_bytes(); 86 | self.write_buffer(pos, &buf[..]) 87 | .ok_or_else(|| WasmError::RuntimeError) 88 | } 89 | 90 | pub fn type_(&self) -> MemType { 91 | MemType(Limits { 92 | min: self.page_size() as u32, 93 | max: self.inst().max.map(|x| x as u32), 94 | }) 95 | } 96 | 97 | pub(super) fn alloc(type_: &MemType) -> MemAddr { 98 | let min = type_.0.min; 99 | let max = type_.0.max; 100 | MemAddr::new(min, max) 101 | } 102 | 103 | pub fn new(min: u32, max: Option) -> MemAddr { 104 | let min = min as usize * MemInst::PAGE_SIZE; 105 | let max = max.map(|max| max as usize); 106 | MemAddr(Rc::new(RefCell::new(MemInst { 107 | max, 108 | data: { 109 | let mut vec = Vec::with_capacity(min); 110 | vec.resize(min, 0); 111 | vec 112 | }, 113 | }))) 114 | } 115 | 116 | pub fn instantiation_valid(&self, offset: usize, init: &Vec) -> Result<(), WasmError> { 117 | if offset 118 | .checked_add(init.len()) 119 | .map(|x| x > self.inst().data.len()) 120 | .unwrap_or(true) 121 | { 122 | Err(WasmError::LinkError) 123 | } else { 124 | Ok(()) 125 | } 126 | } 127 | 128 | pub fn init_data(&self, offset: usize, init: &Vec) { 129 | let inst = &mut *self.mut_inst(); 130 | for (i, x) in init.iter().enumerate() { 131 | inst.data[offset + i] = *x; 132 | } 133 | } 134 | 135 | pub fn page_size(&self) -> i32 { 136 | (self.inst().data.len() / MemInst::PAGE_SIZE) as i32 137 | } 138 | 139 | pub fn grow(&self, add_size: i32) -> i32 { 140 | let prev = self.page_size(); 141 | let new_size = prev + add_size; 142 | if self 143 | .inst() 144 | .max 145 | .map(|max| new_size as usize > max) 146 | .unwrap_or(false) 147 | || new_size > MemInst::MAX_PAGE_SIZE 148 | { 149 | -1 150 | } else { 151 | self.mut_inst() 152 | .data 153 | .resize(new_size as usize * MemInst::PAGE_SIZE, 0); 154 | prev 155 | } 156 | } 157 | } 158 | 159 | pub struct MemAddrIterator(MemAddr, i32); 160 | 161 | impl Iterator for MemAddrIterator { 162 | type Item = u8; 163 | 164 | fn next(&mut self) -> Option { 165 | let res = self.0.get(self.1)?; 166 | self.1 += 1; 167 | Some(res) 168 | } 169 | } 170 | 171 | impl IntoIterator for MemAddr { 172 | type Item = u8; 173 | type IntoIter = MemAddrIterator; 174 | 175 | fn into_iter(self) -> Self::IntoIter { 176 | MemAddrIterator(self, 0) 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /src/exec/val.rs: -------------------------------------------------------------------------------- 1 | use crate::structure::types::ValType; 2 | use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; 3 | use std::io::Cursor; 4 | 5 | #[derive(Debug, Clone, PartialEq, Copy)] 6 | pub enum Val { 7 | I32(i32), 8 | I64(i64), 9 | F32(f32), 10 | F64(f64), 11 | } 12 | 13 | impl Val { 14 | pub fn val_type(&self) -> ValType { 15 | match self { 16 | Val::I32(_) => ValType::I32, 17 | Val::I64(_) => ValType::I64, 18 | Val::F32(_) => ValType::F32, 19 | Val::F64(_) => ValType::F64, 20 | } 21 | } 22 | 23 | pub fn unwrap_i32(&self) -> i32 { 24 | if let Val::I32(x) = self { 25 | *x 26 | } else { 27 | panic!(); 28 | } 29 | } 30 | 31 | pub fn unwrap_i64(&self) -> i64 { 32 | if let Val::I64(x) = self { 33 | *x 34 | } else { 35 | panic!(); 36 | } 37 | } 38 | 39 | pub fn unwrap_f32(&self) -> f32 { 40 | if let Val::F32(x) = self { 41 | *x 42 | } else { 43 | panic!(); 44 | } 45 | } 46 | 47 | pub fn unwrap_f64(&self) -> f64 { 48 | if let Val::F64(x) = self { 49 | *x 50 | } else { 51 | panic!(); 52 | } 53 | } 54 | } 55 | 56 | pub trait PrimitiveVal: Sized { 57 | fn try_from_val(val: Val) -> Option; 58 | fn wrap_val(self) -> Val; 59 | fn type_() -> ValType; 60 | } 61 | 62 | impl PrimitiveVal for i32 { 63 | fn try_from_val(value: Val) -> Option { 64 | if let Val::I32(x) = value { 65 | Some(x) 66 | } else { 67 | None 68 | } 69 | } 70 | 71 | fn wrap_val(self) -> Val { 72 | Val::I32(self) 73 | } 74 | 75 | fn type_() -> ValType { 76 | ValType::I32 77 | } 78 | } 79 | 80 | impl PrimitiveVal for i64 { 81 | fn try_from_val(value: Val) -> Option { 82 | if let Val::I64(x) = value { 83 | Some(x) 84 | } else { 85 | None 86 | } 87 | } 88 | 89 | fn wrap_val(self) -> Val { 90 | Val::I64(self) 91 | } 92 | 93 | fn type_() -> ValType { 94 | ValType::I64 95 | } 96 | } 97 | 98 | impl PrimitiveVal for f32 { 99 | fn try_from_val(value: Val) -> Option { 100 | if let Val::F32(x) = value { 101 | Some(x) 102 | } else { 103 | None 104 | } 105 | } 106 | 107 | fn wrap_val(self) -> Val { 108 | Val::F32(self) 109 | } 110 | 111 | fn type_() -> ValType { 112 | ValType::F32 113 | } 114 | } 115 | 116 | impl PrimitiveVal for f64 { 117 | fn try_from_val(value: Val) -> Option { 118 | if let Val::F64(x) = value { 119 | Some(x) 120 | } else { 121 | None 122 | } 123 | } 124 | 125 | fn wrap_val(self) -> Val { 126 | Val::F64(self) 127 | } 128 | 129 | fn type_() -> ValType { 130 | ValType::F64 131 | } 132 | } 133 | 134 | pub trait InterpretPrimitive { 135 | type Primitive: PrimitiveVal; 136 | 137 | fn to_primitive(self) -> Self::Primitive; 138 | fn reinterpret(primitive: Self::Primitive) -> Self; 139 | } 140 | 141 | impl InterpretPrimitive for T { 142 | type Primitive = T; 143 | 144 | fn to_primitive(self) -> T { 145 | self 146 | } 147 | fn reinterpret(primitive: T) -> T { 148 | primitive 149 | } 150 | } 151 | 152 | impl InterpretPrimitive for bool { 153 | type Primitive = i32; 154 | 155 | fn to_primitive(self) -> i32 { 156 | if self { 157 | 1 158 | } else { 159 | 0 160 | } 161 | } 162 | 163 | fn reinterpret(primitive: i32) -> bool { 164 | primitive != 0 165 | } 166 | } 167 | 168 | impl InterpretPrimitive for u32 { 169 | type Primitive = i32; 170 | 171 | fn to_primitive(self) -> i32 { 172 | let mut wtr = vec![]; 173 | wtr.write_u32::(self).unwrap(); 174 | let mut rdr = Cursor::new(wtr); 175 | rdr.read_i32::().unwrap() 176 | } 177 | 178 | fn reinterpret(primitive: i32) -> u32 { 179 | let mut wtr = vec![]; 180 | wtr.write_i32::(primitive).unwrap(); 181 | let mut rdr = Cursor::new(wtr); 182 | rdr.read_u32::().unwrap() 183 | } 184 | } 185 | 186 | impl InterpretPrimitive for u64 { 187 | type Primitive = i64; 188 | 189 | fn to_primitive(self) -> i64 { 190 | let mut wtr = vec![]; 191 | wtr.write_u64::(self).unwrap(); 192 | let mut rdr = Cursor::new(wtr); 193 | rdr.read_i64::().unwrap() 194 | } 195 | 196 | fn reinterpret(primitive: i64) -> u64 { 197 | let mut wtr = vec![]; 198 | wtr.write_i64::(primitive).unwrap(); 199 | let mut rdr = Cursor::new(wtr); 200 | rdr.read_u64::().unwrap() 201 | } 202 | } 203 | 204 | pub trait InterpretVal: Sized { 205 | fn try_interpret_val(val: Val) -> Option; 206 | fn to_val(self) -> Val; 207 | } 208 | 209 | impl InterpretVal for T { 210 | fn try_interpret_val(val: Val) -> Option { 211 | Some(T::reinterpret(T::Primitive::try_from_val(val)?)) 212 | } 213 | fn to_val(self) -> Val { 214 | self.to_primitive().wrap_val() 215 | } 216 | } 217 | 218 | impl InterpretVal for Val { 219 | fn try_interpret_val(val: Val) -> Option { 220 | Some(val) 221 | } 222 | fn to_val(self) -> Val { 223 | self 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /src/binary/types.rs: -------------------------------------------------------------------------------- 1 | use super::parser; 2 | use super::Decoder; 3 | use super::Encoder; 4 | use crate::structure::types::{ 5 | ElemType, FuncType, GlobalType, Limits, MemType, Mut, ResultType, TableType, ValType, 6 | }; 7 | use nom::{branch::alt, combinator::map, sequence::tuple, IResult}; 8 | 9 | impl Encoder for ValType { 10 | fn encode(&self, bytes: &mut Vec) { 11 | bytes.push(match self { 12 | ValType::I32 => 0x7f, 13 | ValType::I64 => 0x7e, 14 | ValType::F32 => 0x7d, 15 | ValType::F64 => 0x7c, 16 | }); 17 | } 18 | } 19 | 20 | impl Decoder for ValType { 21 | fn decode(input: &[u8]) -> IResult<&[u8], ValType> { 22 | alt(( 23 | map(parser::token(0x7f), |_| ValType::I32), 24 | map(parser::token(0x7e), |_| ValType::I64), 25 | map(parser::token(0x7d), |_| ValType::F32), 26 | map(parser::token(0x7c), |_| ValType::F64), 27 | ))(input) 28 | } 29 | } 30 | 31 | impl Encoder for ResultType { 32 | fn encode(&self, bytes: &mut Vec) { 33 | match &self.0 { 34 | Some(x) => { 35 | x.encode(bytes); 36 | } 37 | None => { 38 | bytes.push(0x40); 39 | } 40 | } 41 | } 42 | } 43 | 44 | impl Decoder for ResultType { 45 | fn decode(input: &[u8]) -> IResult<&[u8], ResultType> { 46 | map( 47 | alt(( 48 | map(ValType::decode, |vt| Some(vt)), 49 | map(parser::token(0x40), |_| (None)), 50 | )), 51 | ResultType, 52 | )(input) 53 | } 54 | } 55 | 56 | impl Encoder for FuncType { 57 | fn encode(&self, bytes: &mut Vec) { 58 | bytes.push(0x60); 59 | self.0.encode(bytes); 60 | self.1.encode(bytes); 61 | } 62 | } 63 | 64 | impl Decoder for FuncType { 65 | fn decode(input: &[u8]) -> IResult<&[u8], FuncType> { 66 | map( 67 | tuple(( 68 | parser::token(0x60), 69 | Vec::::decode, 70 | Vec::::decode, 71 | )), 72 | |(_, a, b)| FuncType(a, b), 73 | )(input) 74 | } 75 | } 76 | 77 | impl Encoder for Limits { 78 | fn encode(&self, bytes: &mut Vec) { 79 | match &self.max { 80 | None => { 81 | bytes.push(0x00); 82 | self.min.encode(bytes); 83 | } 84 | Some(max) => { 85 | bytes.push(0x01); 86 | self.min.encode(bytes); 87 | max.encode(bytes); 88 | } 89 | } 90 | } 91 | } 92 | 93 | impl Decoder for Limits { 94 | fn decode(input: &[u8]) -> IResult<&[u8], Limits> { 95 | alt(( 96 | map(tuple((parser::token(0x00), u32::decode)), |(_, min)| { 97 | Limits { min, max: None } 98 | }), 99 | map( 100 | tuple((parser::token(0x01), u32::decode, u32::decode)), 101 | |(_, min, max)| Limits { 102 | min, 103 | max: Some(max), 104 | }, 105 | ), 106 | ))(input) 107 | } 108 | } 109 | 110 | impl Encoder for MemType { 111 | fn encode(&self, bytes: &mut Vec) { 112 | self.0.encode(bytes); 113 | } 114 | } 115 | 116 | impl Decoder for MemType { 117 | fn decode(input: &[u8]) -> IResult<&[u8], MemType> { 118 | map(Limits::decode, MemType)(input) 119 | } 120 | } 121 | 122 | impl Encoder for TableType { 123 | fn encode(&self, bytes: &mut Vec) { 124 | self.1.encode(bytes); 125 | self.0.encode(bytes); 126 | } 127 | } 128 | 129 | impl Decoder for TableType { 130 | fn decode(input: &[u8]) -> IResult<&[u8], TableType> { 131 | map(tuple((ElemType::decode, Limits::decode)), |(et, lt)| { 132 | TableType(lt, et) 133 | })(input) 134 | } 135 | } 136 | 137 | impl Encoder for ElemType { 138 | fn encode(&self, bytes: &mut Vec) { 139 | match self { 140 | ElemType::FuncRef => { 141 | bytes.push(0x70); 142 | } 143 | } 144 | } 145 | } 146 | 147 | impl Decoder for ElemType { 148 | fn decode(input: &[u8]) -> IResult<&[u8], ElemType> { 149 | map(parser::token(0x70), |_| ElemType::FuncRef)(input) 150 | } 151 | } 152 | 153 | impl Encoder for GlobalType { 154 | fn encode(&self, bytes: &mut Vec) { 155 | self.1.encode(bytes); 156 | self.0.encode(bytes); 157 | } 158 | } 159 | 160 | impl Decoder for GlobalType { 161 | fn decode(input: &[u8]) -> IResult<&[u8], GlobalType> { 162 | map(tuple((ValType::decode, Mut::decode)), |(gt, m)| { 163 | GlobalType(m, gt) 164 | })(input) 165 | } 166 | } 167 | 168 | impl Encoder for Mut { 169 | fn encode(&self, bytes: &mut Vec) { 170 | bytes.push(match self { 171 | Mut::Const => 0x00, 172 | Mut::Var => 0x01, 173 | }); 174 | } 175 | } 176 | 177 | impl Decoder for Mut { 178 | fn decode(input: &[u8]) -> IResult<&[u8], Mut> { 179 | alt(( 180 | map(parser::token(0x00), |_| Mut::Const), 181 | map(parser::token(0x01), |_| Mut::Var), 182 | ))(input) 183 | } 184 | } 185 | 186 | #[test] 187 | fn tests() { 188 | use super::test_helper; 189 | 190 | test_helper::identity_encode_decode::(); 191 | test_helper::identity_encode_decode::(); 192 | test_helper::identity_encode_decode::(); 193 | test_helper::identity_encode_decode::(); 194 | test_helper::identity_encode_decode::(); 195 | test_helper::identity_encode_decode::(); 196 | test_helper::identity_encode_decode::(); 197 | test_helper::identity_encode_decode::(); 198 | test_helper::identity_encode_decode::(); 199 | } 200 | -------------------------------------------------------------------------------- /src/exec/func.rs: -------------------------------------------------------------------------------- 1 | use super::instance::{ModuleInst, TypedIdxAccess}; 2 | use super::stack::{AdminInstr, Frame, FrameStack, Label, LabelStack, Stack}; 3 | use super::val::{InterpretPrimitive, PrimitiveVal, Val}; 4 | use crate::structure::instructions::Expr; 5 | use crate::structure::modules::{Func, TypeIdx}; 6 | use crate::structure::types::{FuncType, ValType}; 7 | use crate::WasmError; 8 | use frunk::{from_generic, into_generic, Generic}; 9 | use frunk::{hlist::HList, HCons, HNil}; 10 | use std::cell::Ref; 11 | use std::cell::RefCell; 12 | use std::rc::{Rc, Weak}; 13 | 14 | #[derive(Clone, Debug)] 15 | pub struct FuncAddr(Rc>); 16 | 17 | impl FuncAddr { 18 | pub fn call(&self, params: Vec) -> Result, WasmError> { 19 | let mut stack = Stack { 20 | stack: vec![FrameStack { 21 | frame: Frame { 22 | locals: Vec::new(), 23 | module: Weak::new(), 24 | n: 0, 25 | }, 26 | stack: vec![LabelStack { 27 | label: Label { 28 | instrs: vec![], 29 | n: 0, 30 | }, 31 | instrs: vec![AdminInstr::Invoke(self.clone())], 32 | stack: params, 33 | }], 34 | }], 35 | }; 36 | 37 | loop { 38 | stack.step()?; 39 | if stack.stack.len() == 1 40 | && stack.stack.first().unwrap().stack.len() == 1 41 | && stack 42 | .stack 43 | .first() 44 | .unwrap() 45 | .stack 46 | .first() 47 | .unwrap() 48 | .instrs 49 | .is_empty() 50 | { 51 | break; 52 | } 53 | } 54 | 55 | Ok(stack.stack.pop().unwrap().stack.pop().unwrap().stack.pop()) 56 | } 57 | 58 | pub(super) fn borrow(&self) -> Ref { 59 | self.0.borrow() 60 | } 61 | 62 | pub(super) fn alloc_dummy() -> FuncAddr { 63 | FuncAddr(Rc::new(RefCell::new(FuncInst::RuntimeFunc { 64 | type_: FuncType(Vec::new(), Vec::new()), 65 | code: Func { 66 | type_: TypeIdx(0), 67 | locals: Vec::new(), 68 | body: Expr(Vec::new()), 69 | }, 70 | module: Weak::new(), 71 | }))) 72 | } 73 | 74 | pub(super) fn replace_dummy(&self, func: Func, module: Weak) { 75 | *self.0.borrow_mut() = FuncInst::new(func, module); 76 | } 77 | 78 | pub fn alloc_host( 79 | f: impl Fn(P) -> Result + 'static, 80 | ) -> FuncAddr 81 | where 82 | P::Repr: ValTypeable + FromVecVal, 83 | R::Repr: ValTypeable + ToOptionVal, 84 | { 85 | let type_ = FuncType(P::Repr::to_valtype(), R::Repr::to_valtype()); 86 | FuncAddr(Rc::new(RefCell::new(FuncInst::HostFunc { 87 | type_, 88 | host_code: Rc::new(move |params| { 89 | let p = P::Repr::from_vec_val(params); 90 | let r = into_generic(f(from_generic(p))?); 91 | Ok(r.to_option_val()) 92 | }), 93 | }))) 94 | } 95 | 96 | pub fn type_(&self) -> FuncType { 97 | match &*self.0.borrow() { 98 | FuncInst::RuntimeFunc { type_, .. } => type_.clone(), 99 | FuncInst::HostFunc { type_, .. } => type_.clone(), 100 | } 101 | } 102 | } 103 | 104 | #[derive(Clone)] 105 | pub(super) enum FuncInst { 106 | RuntimeFunc { 107 | type_: FuncType, 108 | code: Func, 109 | module: Weak, 110 | }, 111 | HostFunc { 112 | type_: FuncType, 113 | host_code: Rc) -> Result, WasmError>>, 114 | }, 115 | } 116 | 117 | impl std::fmt::Debug for FuncInst { 118 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 119 | write!(f, "") 120 | } 121 | } 122 | 123 | impl FuncInst { 124 | pub fn new(func: Func, module: Weak) -> FuncInst { 125 | FuncInst::RuntimeFunc { 126 | type_: module.upgrade().unwrap().types.get_idx(func.type_).clone(), 127 | code: func, 128 | module, 129 | } 130 | } 131 | } 132 | 133 | pub trait ValTypeable { 134 | fn write_valtype(types: &mut Vec); 135 | fn to_valtype() -> Vec { 136 | let mut types = Vec::new(); 137 | Self::write_valtype(&mut types); 138 | types 139 | } 140 | } 141 | 142 | impl ValTypeable for T { 143 | fn write_valtype(types: &mut Vec) { 144 | types.push(T::Primitive::type_()); 145 | } 146 | } 147 | 148 | impl ValTypeable for HNil { 149 | fn write_valtype(_: &mut Vec) {} 150 | } 151 | 152 | impl ValTypeable for HCons { 153 | fn write_valtype(types: &mut Vec) { 154 | H::write_valtype(types); 155 | T::write_valtype(types); 156 | } 157 | } 158 | 159 | pub trait ToOptionVal { 160 | fn to_option_val(self) -> Option; 161 | } 162 | 163 | impl ToOptionVal for HNil { 164 | fn to_option_val(self) -> Option { 165 | None 166 | } 167 | } 168 | 169 | impl ToOptionVal for HCons { 170 | fn to_option_val(self) -> Option { 171 | self.head.to_option_val() 172 | } 173 | } 174 | 175 | impl ToOptionVal for T { 176 | fn to_option_val(self) -> Option { 177 | Some(self.to_primitive().wrap_val()) 178 | } 179 | } 180 | 181 | pub trait FromVecVal: Sized { 182 | fn from_vec_val_pop_tail(vals: &mut Vec) -> Self; 183 | 184 | fn from_vec_val(mut vals: Vec) -> Self { 185 | let res = Self::from_vec_val_pop_tail(&mut vals); 186 | assert_eq!(vals.len(), 0); 187 | res 188 | } 189 | } 190 | 191 | impl FromVecVal for HNil { 192 | fn from_vec_val_pop_tail(_: &mut Vec) -> Self { 193 | HNil 194 | } 195 | } 196 | 197 | impl FromVecVal for HCons { 198 | fn from_vec_val_pop_tail(vals: &mut Vec) -> Self { 199 | let t = T::from_vec_val_pop_tail(vals); 200 | let h = H::from_vec_val_pop_tail(vals); 201 | HCons { head: h, tail: t } 202 | } 203 | } 204 | 205 | impl FromVecVal for T { 206 | fn from_vec_val_pop_tail(vals: &mut Vec) -> Self { 207 | T::reinterpret(T::Primitive::try_from_val(vals.pop().unwrap()).unwrap()) 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /src/exec/instance.rs: -------------------------------------------------------------------------------- 1 | use crate::structure::instructions::{Expr, Instr}; 2 | use crate::structure::modules::{ 3 | ExportDesc, FuncIdx, GlobalIdx, ImportDesc, Module, TypeIdx, TypedIdx, 4 | }; 5 | use crate::structure::types::FuncType; 6 | use crate::WasmError; 7 | 8 | use super::global::GlobalAddr; 9 | use super::mem::MemAddr; 10 | use super::table::TableAddr; 11 | use super::val::Val; 12 | use super::FuncAddr; 13 | use std::collections::HashMap; 14 | use std::rc::Rc; 15 | 16 | pub type ExternalModule = HashMap; 17 | pub type ImportObjects = HashMap; 18 | 19 | #[derive(Debug, Clone)] 20 | pub enum ExternalVal { 21 | Func(FuncAddr), 22 | Table(TableAddr), 23 | Mem(MemAddr), 24 | Global(GlobalAddr), 25 | } 26 | 27 | impl ExternalVal { 28 | pub fn as_func(self) -> Option { 29 | if let ExternalVal::Func(x) = self { 30 | Some(x) 31 | } else { 32 | None 33 | } 34 | } 35 | 36 | pub fn unwrap_func(self) -> FuncAddr { 37 | self.as_func().unwrap() 38 | } 39 | 40 | pub fn as_table(self) -> Option { 41 | if let ExternalVal::Table(x) = self { 42 | Some(x) 43 | } else { 44 | None 45 | } 46 | } 47 | 48 | pub fn unwrap_table(self) -> TableAddr { 49 | self.as_table().unwrap() 50 | } 51 | 52 | pub fn as_mem(self) -> Option { 53 | if let ExternalVal::Mem(x) = self { 54 | Some(x) 55 | } else { 56 | None 57 | } 58 | } 59 | 60 | pub fn unwrap_mem(self) -> MemAddr { 61 | self.as_mem().unwrap() 62 | } 63 | 64 | pub fn as_global(self) -> Option { 65 | if let ExternalVal::Global(x) = self { 66 | Some(x) 67 | } else { 68 | None 69 | } 70 | } 71 | 72 | pub fn unwrap_global(self) -> GlobalAddr { 73 | self.as_global().unwrap() 74 | } 75 | } 76 | 77 | #[derive(Debug, Clone)] 78 | pub struct ExportInst { 79 | name: String, 80 | value: ExternalVal, 81 | } 82 | 83 | pub trait TypedIdxAccess 84 | where 85 | Idx: TypedIdx, 86 | Self: std::ops::Index, 87 | { 88 | fn get_idx(&self, idx: Idx) -> &Self::Output { 89 | &self[idx.to_idx()] 90 | } 91 | } 92 | 93 | impl TypedIdxAccess for Vec {} 94 | impl TypedIdxAccess for Vec {} 95 | impl TypedIdxAccess for Vec {} 96 | 97 | #[derive(Debug)] 98 | pub struct ModuleInst { 99 | pub types: Vec, 100 | pub funcs: Vec, 101 | pub table: Option, 102 | pub mem: Option, 103 | pub globals: Vec, 104 | pub exports: Vec, 105 | } 106 | 107 | impl ModuleInst { 108 | pub fn new( 109 | module: &Module, 110 | imports_objects: ImportObjects, 111 | ) -> Result, WasmError> { 112 | let mut result = ModuleInst { 113 | types: module.types.clone(), 114 | funcs: Vec::new(), 115 | table: None, 116 | mem: None, 117 | globals: Vec::new(), 118 | exports: Vec::new(), 119 | }; 120 | 121 | for import in &module.imports { 122 | let val = imports_objects 123 | .get(&import.module.0) 124 | .and_then(|module| module.get(&import.name.0)) 125 | .cloned() 126 | .ok_or_else(|| WasmError::LinkError)?; 127 | match &import.desc { 128 | ImportDesc::Func(idx) => { 129 | result.funcs.push( 130 | val.as_func() 131 | .filter(|func| func.type_().is_match(result.types.get_idx(*idx))) 132 | .ok_or_else(|| WasmError::LinkError)?, 133 | ); 134 | } 135 | ImportDesc::Table(type_) => { 136 | let _ = result.table.replace( 137 | val.as_table() 138 | .filter(|table| table.type_().is_match(type_)) 139 | .ok_or_else(|| WasmError::LinkError)?, 140 | ); 141 | } 142 | ImportDesc::Mem(type_) => { 143 | let _ = result.mem.replace( 144 | val.as_mem() 145 | .filter(|mem| mem.type_().is_match(type_)) 146 | .ok_or_else(|| WasmError::LinkError)?, 147 | ); 148 | } 149 | ImportDesc::Global(type_) => { 150 | result.globals.push( 151 | val.as_global() 152 | .filter(|global| global.type_().is_match(type_)) 153 | .ok_or_else(|| WasmError::LinkError)?, 154 | ); 155 | } 156 | } 157 | } 158 | 159 | for _ in &module.funcs { 160 | result.funcs.push(FuncAddr::alloc_dummy()); 161 | } 162 | 163 | if let Some(table) = module.tables.iter().next() { 164 | let _ = result.table.replace(TableAddr::alloc(&table.type_)); 165 | } 166 | 167 | if let Some(mem) = module.mems.iter().next() { 168 | let _ = result.mem.replace(MemAddr::alloc(&mem.type_)); 169 | } 170 | 171 | for global in &module.globals { 172 | result.globals.push(GlobalAddr::alloc( 173 | global.type_.clone(), 174 | result.eval_const_expr(&global.init), 175 | )); 176 | } 177 | 178 | for elem in &module.elem { 179 | let offset = result.eval_const_expr(&elem.offset).unwrap_i32() as usize; 180 | result 181 | .table 182 | .as_ref() 183 | .unwrap() 184 | .instantiation_valid(offset, &elem.init)?; 185 | } 186 | for data in &module.data { 187 | let offset = result.eval_const_expr(&data.offset).unwrap_i32() as usize; 188 | result 189 | .mem 190 | .as_ref() 191 | .unwrap() 192 | .instantiation_valid(offset, &data.init.iter().map(|x| x.0).collect())?; 193 | } 194 | 195 | for elem in &module.elem { 196 | let offset = result.eval_const_expr(&elem.offset).unwrap_i32() as usize; 197 | result 198 | .table 199 | .as_ref() 200 | .unwrap() 201 | .init_elem(&result.funcs, offset, &elem.init); 202 | } 203 | for data in &module.data { 204 | let offset = result.eval_const_expr(&data.offset).unwrap_i32() as usize; 205 | result 206 | .mem 207 | .as_ref() 208 | .unwrap() 209 | .init_data(offset, &data.init.iter().map(|x| x.0).collect()); 210 | } 211 | 212 | for export in &module.exports { 213 | result.exports.push(ExportInst { 214 | name: export.name.0.clone(), 215 | value: match export.desc { 216 | ExportDesc::Func(idx) => ExternalVal::Func(result.funcs.get_idx(idx).clone()), 217 | ExportDesc::Global(idx) => { 218 | ExternalVal::Global(result.globals.get_idx(idx).clone()) 219 | } 220 | ExportDesc::Mem(_idx) => ExternalVal::Mem(result.mem.as_ref().unwrap().clone()), 221 | ExportDesc::Table(_idx) => { 222 | ExternalVal::Table(result.table.as_ref().unwrap().clone()) 223 | } 224 | }, 225 | }); 226 | } 227 | 228 | let result = Rc::new(result); 229 | 230 | for (i, func) in module.funcs.iter().enumerate() { 231 | let idx = i + module 232 | .imports 233 | .iter() 234 | .map(|x| { 235 | if let ImportDesc::Func(_) = x.desc { 236 | 1 237 | } else { 238 | 0 239 | } 240 | }) 241 | .sum::(); 242 | result.funcs[idx].replace_dummy(func.clone(), Rc::downgrade(&result)); 243 | } 244 | 245 | if let Some(start) = &module.start { 246 | result.funcs.get_idx(start.func).call(vec![])?; 247 | } 248 | 249 | Ok(result) 250 | } 251 | 252 | fn eval_const_expr(&self, expr: &Expr) -> Val { 253 | match &expr.0[..] { 254 | &[Instr::I32Const(x)] => Val::I32(x), 255 | &[Instr::I64Const(x)] => Val::I64(x), 256 | &[Instr::F32Const(x)] => Val::F32(x), 257 | &[Instr::F64Const(x)] => Val::F64(x), 258 | &[Instr::GlobalGet(i)] => self.globals[i.to_idx()].get(), 259 | _ => panic!(), 260 | } 261 | } 262 | 263 | pub fn export(&self, name: &str) -> ExternalVal { 264 | self.exports 265 | .iter() 266 | .find(|e| e.name.as_str() == name) 267 | .map(|x| x.value.clone()) 268 | .unwrap() 269 | } 270 | 271 | pub fn exports(&self) -> ExternalModule { 272 | self.exports 273 | .iter() 274 | .map(|x| (x.name.clone(), x.value.clone())) 275 | .collect() 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /tests/spec.rs: -------------------------------------------------------------------------------- 1 | #![feature(backtrace)] 2 | 3 | use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; 4 | use lazy_static::lazy_static; 5 | use maplit::hashmap; 6 | use serde_json::Value; 7 | use std::collections::HashMap; 8 | use std::io::Cursor; 9 | use std::panic; 10 | use std::panic::{catch_unwind, AssertUnwindSafe}; 11 | use std::path::Path; 12 | use std::rc::Rc; 13 | use wasm_rs::binary::decode_module; 14 | use wasm_rs::exec::FuncAddr; 15 | use wasm_rs::exec::GlobalAddr; 16 | use wasm_rs::exec::MemAddr; 17 | use wasm_rs::exec::TableAddr; 18 | use wasm_rs::exec::Val; 19 | use wasm_rs::exec::{ExternalVal, ImportObjects, ModuleInst}; 20 | use wasm_rs::structure::types::Mut; 21 | use wasm_rs::WasmError; 22 | 23 | #[derive(Debug, Clone, Copy)] 24 | struct SpecVal(Val); 25 | impl PartialEq for SpecVal { 26 | fn eq(&self, other: &SpecVal) -> bool { 27 | match (self.0, other.0) { 28 | (Val::I32(a), Val::I32(b)) => a == b, 29 | (Val::I64(a), Val::I64(b)) => a == b, 30 | (Val::F32(a), Val::F32(b)) => { 31 | let mut a_bytes = Vec::new(); 32 | a_bytes.write_f32::(a).unwrap(); 33 | 34 | let mut b_bytes = Vec::new(); 35 | b_bytes.write_f32::(b).unwrap(); 36 | a_bytes == b_bytes 37 | } 38 | (Val::F64(a), Val::F64(b)) => { 39 | let mut a_bytes = Vec::new(); 40 | a_bytes.write_f64::(a).unwrap(); 41 | 42 | let mut b_bytes = Vec::new(); 43 | b_bytes.write_f64::(b).unwrap(); 44 | a_bytes == b_bytes 45 | } 46 | _ => false, 47 | } 48 | } 49 | } 50 | 51 | impl FromJSON for SpecVal { 52 | fn from_json(json: &Value) -> SpecVal { 53 | SpecVal(Val::from_json(json)) 54 | } 55 | } 56 | 57 | trait FromJSON { 58 | fn from_json(json: &Value) -> Self; 59 | } 60 | 61 | impl FromJSON for Val { 62 | fn from_json(json: &Value) -> Val { 63 | let json_obj = json.as_object().unwrap(); 64 | let mut buf = Vec::new(); 65 | buf.write_u64::( 66 | json_obj 67 | .get("value") 68 | .unwrap() 69 | .as_str() 70 | .unwrap() 71 | .parse::() 72 | .unwrap(), 73 | ) 74 | .unwrap(); 75 | let mut rdr = Cursor::new(buf); 76 | match json_obj.get("type").unwrap().as_str().unwrap() { 77 | "i32" => Val::I32(rdr.read_i32::().unwrap()), 78 | "i64" => Val::I64(rdr.read_i64::().unwrap()), 79 | "f32" => Val::F32(rdr.read_f32::().unwrap()), 80 | "f64" => Val::F64(rdr.read_f64::().unwrap()), 81 | _ => panic!(), 82 | } 83 | } 84 | } 85 | 86 | #[derive(Debug, Clone, PartialEq)] 87 | pub enum ActionKind { 88 | Invoke { field: String, args: Vec }, 89 | Get { field: String }, 90 | } 91 | 92 | impl FromJSON for ActionKind { 93 | fn from_json(json: &Value) -> ActionKind { 94 | let json_obj = json.as_object().unwrap(); 95 | match json_obj.get("type").unwrap().as_str().unwrap() { 96 | "invoke" => ActionKind::Invoke { 97 | field: json_obj.get("field").unwrap().as_str().unwrap().to_string(), 98 | args: json_obj 99 | .get("args") 100 | .unwrap() 101 | .as_array() 102 | .unwrap() 103 | .iter() 104 | .map(Val::from_json) 105 | .collect::>(), 106 | }, 107 | "get" => ActionKind::Get { 108 | field: json_obj.get("field").unwrap().as_str().unwrap().to_string(), 109 | }, 110 | _ => panic!(), 111 | } 112 | } 113 | } 114 | 115 | #[derive(Debug, Clone, PartialEq)] 116 | pub struct Action { 117 | kind: ActionKind, 118 | module: Option, 119 | } 120 | 121 | impl Action { 122 | fn run(&self, state: &mut SpecState) -> Result, WasmError> { 123 | match &self.kind { 124 | ActionKind::Invoke { field, args } => state 125 | .instance(&self.module) 126 | .export(field) 127 | .unwrap_func() 128 | .call(args.clone()) 129 | .map(|x| x.into_iter().map(SpecVal).collect::>()), 130 | ActionKind::Get { field } => Ok(vec![SpecVal( 131 | state 132 | .instance(&self.module) 133 | .export(field) 134 | .unwrap_global() 135 | .get(), 136 | )]), 137 | } 138 | } 139 | } 140 | 141 | impl FromJSON for Action { 142 | fn from_json(json: &Value) -> Action { 143 | Action { 144 | kind: ActionKind::from_json(json), 145 | module: json 146 | .as_object() 147 | .unwrap() 148 | .get("module") 149 | .map(|x| x.as_str().unwrap().to_string()), 150 | } 151 | } 152 | } 153 | 154 | #[derive(Debug)] 155 | struct SpecState { 156 | instances: Vec>, 157 | instance_map: HashMap>, 158 | registers: ImportObjects, 159 | } 160 | 161 | impl SpecState { 162 | fn new() -> SpecState { 163 | SpecState { 164 | instances: Vec::new(), 165 | instance_map: HashMap::new(), 166 | registers: hashmap! { 167 | "spectest".to_string() => hashmap! { 168 | "print".to_string() => ExternalVal::Func(FuncAddr::alloc_host(|(): ()| Ok(()))), 169 | "print_i32".to_string() => ExternalVal::Func(FuncAddr::alloc_host(|(_,): (i32,)| Ok(()))), 170 | "print_i32_f32".to_string() => ExternalVal::Func(FuncAddr::alloc_host(|(_, _): (i32, f32)| Ok(()))), 171 | "print_f64_f64".to_string() => ExternalVal::Func(FuncAddr::alloc_host(|(_, _): (f64, f64)| Ok(()))), 172 | "print_f32".to_string() => ExternalVal::Func(FuncAddr::alloc_host(|(_,): (f32, )| Ok(()))), 173 | "print_f64".to_string() => ExternalVal::Func(FuncAddr::alloc_host(|(_,): (f64,)| Ok(()))), 174 | "global_i32".to_string() => ExternalVal::Global(GlobalAddr::new(Mut::Const, Val::I32(666))), 175 | "global_f32".to_string() => ExternalVal::Global(GlobalAddr::new(Mut::Const, Val::F32(666.0))), 176 | "global_f64".to_string() => ExternalVal::Global(GlobalAddr::new(Mut::Const, Val::F64(666.0))), 177 | "table".to_string() => ExternalVal::Table(TableAddr::new(10, Some(20))), 178 | "memory".to_string() => ExternalVal::Mem(MemAddr::new(1,Some(2))), 179 | } 180 | }, 181 | } 182 | } 183 | 184 | fn instance(&self, name: &Option) -> Rc { 185 | name.as_ref() 186 | .map(|name| self.instance_map.get(name).unwrap().clone()) 187 | .unwrap_or_else(|| self.instances.last().unwrap().clone()) 188 | } 189 | } 190 | 191 | #[derive(Debug, Clone, PartialEq)] 192 | pub struct Spec { 193 | commands: Vec, 194 | source_filename: String, 195 | } 196 | 197 | impl FromJSON for Spec { 198 | fn from_json(json: &Value) -> Spec { 199 | let json_obj = json.as_object().unwrap(); 200 | Spec { 201 | commands: json_obj 202 | .get("commands") 203 | .unwrap() 204 | .as_array() 205 | .unwrap() 206 | .iter() 207 | .map(Command::from_json) 208 | .collect::>(), 209 | source_filename: json_obj 210 | .get("source_filename") 211 | .unwrap() 212 | .as_str() 213 | .unwrap() 214 | .to_string(), 215 | } 216 | } 217 | } 218 | 219 | impl Spec { 220 | fn run(&self, base_dir: &Path, line: &mut i32) { 221 | let mut state = SpecState::new(); 222 | 223 | for command in &self.commands { 224 | *line = command.line; 225 | command.run(base_dir, &mut state); 226 | } 227 | } 228 | } 229 | 230 | #[derive(Debug, Clone, PartialEq)] 231 | pub struct Command { 232 | line: i32, 233 | paylaod: CommandKind, 234 | } 235 | 236 | impl Command { 237 | fn run(&self, base_dir: &Path, state: &mut SpecState) { 238 | match &self.paylaod { 239 | CommandKind::Module { filename, name } => { 240 | let module = ModuleInst::new( 241 | &decode_module(&std::fs::read(base_dir.join(filename)).unwrap()).unwrap(), 242 | state.registers.clone(), 243 | ) 244 | .unwrap(); 245 | state.instances.push(module.clone()); 246 | if let Some(name) = name { 247 | state.instance_map.insert(name.clone(), module.clone()); 248 | } 249 | } 250 | CommandKind::AssertReturn { action, expected } => { 251 | assert_eq!(&action.run(state).unwrap(), expected); 252 | } 253 | CommandKind::AssertTrap { action } => { 254 | assert_eq!(action.run(state), Err(WasmError::RuntimeError)); 255 | } 256 | CommandKind::Register { as_, name } => { 257 | state 258 | .registers 259 | .insert(as_.clone(), state.instance(name).exports()); 260 | } 261 | CommandKind::Action { action, expected } => { 262 | assert_eq!(&action.run(state).unwrap(), expected); 263 | } 264 | CommandKind::AssertUninstantiable { filename } => { 265 | assert_eq!( 266 | ModuleInst::new( 267 | &decode_module(&std::fs::read(base_dir.join(filename)).unwrap()).unwrap(), 268 | state.registers.clone(), 269 | ) 270 | .unwrap_err(), 271 | WasmError::RuntimeError 272 | ); 273 | } 274 | CommandKind::AssertUnlinkable { filename } => { 275 | assert_eq!( 276 | ModuleInst::new( 277 | &decode_module(&std::fs::read(base_dir.join(filename)).unwrap()).unwrap(), 278 | state.registers.clone(), 279 | ) 280 | .unwrap_err(), 281 | WasmError::LinkError 282 | ); 283 | } 284 | CommandKind::Skip { .. } => {} 285 | } 286 | } 287 | } 288 | 289 | impl FromJSON for Command { 290 | fn from_json(json: &Value) -> Command { 291 | Command { 292 | line: json 293 | .as_object() 294 | .unwrap() 295 | .get("line") 296 | .unwrap() 297 | .as_i64() 298 | .unwrap() as i32, 299 | paylaod: CommandKind::from_json(json), 300 | } 301 | } 302 | } 303 | 304 | #[derive(Debug, Clone, PartialEq)] 305 | enum CommandKind { 306 | Module { 307 | filename: String, 308 | name: Option, 309 | }, 310 | AssertReturn { 311 | action: Action, 312 | expected: Vec, 313 | }, 314 | Register { 315 | as_: String, 316 | name: Option, 317 | }, 318 | AssertTrap { 319 | action: Action, 320 | }, 321 | Skip { 322 | type_: String, 323 | }, 324 | AssertUnlinkable { 325 | filename: String, 326 | }, 327 | AssertUninstantiable { 328 | filename: String, 329 | }, 330 | Action { 331 | action: Action, 332 | expected: Vec, 333 | }, 334 | } 335 | 336 | impl FromJSON for CommandKind { 337 | fn from_json(json: &Value) -> CommandKind { 338 | let json_obj = json.as_object().unwrap(); 339 | match json_obj.get("type").unwrap().as_str().unwrap() { 340 | "module" => CommandKind::Module { 341 | filename: json_obj 342 | .get("filename") 343 | .unwrap() 344 | .as_str() 345 | .unwrap() 346 | .to_string(), 347 | name: json 348 | .as_object() 349 | .unwrap() 350 | .get("name") 351 | .map(|x| x.as_str().unwrap().to_string()), 352 | }, 353 | "assert_return" => CommandKind::AssertReturn { 354 | action: Action::from_json(json_obj.get("action").unwrap()), 355 | expected: json_obj 356 | .get("expected") 357 | .unwrap() 358 | .as_array() 359 | .unwrap() 360 | .iter() 361 | .map(SpecVal::from_json) 362 | .collect::>(), 363 | }, 364 | "register" => CommandKind::Register { 365 | as_: json_obj.get("as").unwrap().as_str().unwrap().to_string(), 366 | name: json 367 | .as_object() 368 | .unwrap() 369 | .get("name") 370 | .map(|x| x.as_str().unwrap().to_string()), 371 | }, 372 | "action" => CommandKind::Action { 373 | action: Action::from_json(json_obj.get("action").unwrap()), 374 | expected: json_obj 375 | .get("expected") 376 | .unwrap() 377 | .as_array() 378 | .unwrap() 379 | .iter() 380 | .map(SpecVal::from_json) 381 | .collect::>(), 382 | }, 383 | "assert_trap" => CommandKind::AssertTrap { 384 | action: Action::from_json(json_obj.get("action").unwrap()), 385 | }, 386 | "assert_uninstantiable" => CommandKind::AssertUninstantiable { 387 | filename: json_obj 388 | .get("filename") 389 | .unwrap() 390 | .as_str() 391 | .unwrap() 392 | .to_string(), 393 | }, 394 | "assert_unlinkable" => CommandKind::AssertUnlinkable { 395 | filename: json_obj 396 | .get("filename") 397 | .unwrap() 398 | .as_str() 399 | .unwrap() 400 | .to_string(), 401 | }, 402 | "assert_malformed" => CommandKind::Skip { 403 | type_: "assert_malformed".to_string(), 404 | }, 405 | "assert_invalid" => CommandKind::Skip { 406 | type_: "assert_invalid".to_string(), 407 | }, 408 | "assert_exhaustion" => CommandKind::Skip { 409 | type_: "assert_exhaustion".to_string(), 410 | }, 411 | "assert_return_canonical_nan" => CommandKind::Skip { 412 | type_: "assert_return_canonical_nan".to_string(), 413 | }, 414 | "assert_return_arithmetic_nan" => CommandKind::Skip { 415 | type_: "assert_return_arithmetic_nan".to_string(), 416 | }, 417 | ty => panic!("unknown type: {}", ty), 418 | } 419 | } 420 | } 421 | 422 | use std::sync::RwLock; 423 | 424 | lazy_static! { 425 | pub static ref LAST_PANIC_MSG: RwLock> = { RwLock::new(None) }; 426 | } 427 | 428 | #[test] 429 | fn test_specs() { 430 | let default_hook = panic::take_hook(); 431 | 432 | panic::set_hook(Box::new(move |panic_info| { 433 | *self::LAST_PANIC_MSG.write().unwrap() = Some(format!( 434 | "{}\n{}", 435 | panic_info, 436 | std::backtrace::Backtrace::capture() 437 | )); 438 | default_hook(panic_info); 439 | })); 440 | 441 | let base_dir = Path::new("./wast-dist"); 442 | let mut passed_count = 0; 443 | let mut failed_count = 0; 444 | let mut fail_msgs = Vec::new(); 445 | 446 | for file in std::fs::read_dir(base_dir).unwrap() { 447 | let filename = file.unwrap().file_name().into_string().unwrap(); 448 | if filename.ends_with(".json") { 449 | let json_path = base_dir.join(filename); 450 | let mut line = 0; 451 | let spec = Spec::from_json( 452 | &serde_json::from_slice::(&std::fs::read(&json_path).unwrap()).unwrap(), 453 | ); 454 | 455 | let line_ref = AssertUnwindSafe(&mut line); 456 | let spec_ref = &spec; 457 | match catch_unwind(move || { 458 | spec_ref.run(base_dir, line_ref.0); 459 | }) { 460 | Ok(_) => { 461 | passed_count += 1; 462 | println!("[passed]{}", spec.source_filename); 463 | } 464 | Err(e) => { 465 | failed_count += 1; 466 | fail_msgs.push(format!( 467 | "[{}:{}] {}\n{}", 468 | spec.source_filename, 469 | line, 470 | any_to_string(&*e), 471 | self::LAST_PANIC_MSG.read().unwrap().as_ref().unwrap() 472 | )); 473 | println!("[failed]{}:{}", spec.source_filename, line); 474 | } 475 | } 476 | } 477 | } 478 | 479 | for msg in fail_msgs { 480 | println!("{}", msg); 481 | } 482 | 483 | println!("{} passed; {} failed;", passed_count, failed_count); 484 | if failed_count != 0 { 485 | panic!("test failed"); 486 | } 487 | } 488 | 489 | fn any_to_string(any: &dyn std::any::Any) -> String { 490 | if let Some(s) = any.downcast_ref::() { 491 | s.clone() 492 | } else if let Some(s) = any.downcast_ref::<&str>() { 493 | s.to_string() 494 | } else { 495 | "Any".to_string() 496 | } 497 | } 498 | -------------------------------------------------------------------------------- /src/binary/modules.rs: -------------------------------------------------------------------------------- 1 | use super::parser; 2 | use super::Decoder; 3 | use super::Encoder; 4 | use crate::structure::instructions::Expr; 5 | use crate::structure::modules::{ 6 | Data, Elem, Export, ExportDesc, Func, FuncIdx, Global, GlobalIdx, Import, ImportDesc, LabelIdx, 7 | LocalIdx, Mem, MemIdx, Module, Start, Table, TableIdx, TypeIdx, 8 | }; 9 | use crate::structure::types::{FuncType, GlobalType, MemType, TableType, ValType}; 10 | use crate::structure::values::{Byte, Name}; 11 | 12 | use nom::{ 13 | branch::alt, 14 | combinator::{flat_map, map}, 15 | multi::{many0, many_m_n}, 16 | sequence::tuple, 17 | IResult, 18 | }; 19 | 20 | trait Zero { 21 | type NonZero; 22 | type Zero; 23 | 24 | fn is_zero(&self) -> bool { 25 | self.get_non_zero().is_none() 26 | } 27 | 28 | fn get_non_zero(&self) -> Option<&Self::NonZero>; 29 | 30 | fn zero() -> Self::Zero; 31 | } 32 | 33 | impl Zero for Option { 34 | type NonZero = T; 35 | type Zero = Option; 36 | 37 | fn get_non_zero(&self) -> Option<&Self::NonZero> { 38 | self.as_ref() 39 | } 40 | 41 | fn zero() -> Self::Zero { 42 | None 43 | } 44 | } 45 | 46 | impl Zero for Vec { 47 | type NonZero = Vec; 48 | type Zero = Vec; 49 | 50 | fn get_non_zero(&self) -> Option<&Self::NonZero> { 51 | if self.is_empty() { 52 | None 53 | } else { 54 | Some(self) 55 | } 56 | } 57 | 58 | fn zero() -> Self::Zero { 59 | Vec::new() 60 | } 61 | } 62 | 63 | impl<'a, T> Zero for &'a T 64 | where 65 | T: Zero, 66 | { 67 | type NonZero = T::NonZero; 68 | type Zero = T::Zero; 69 | 70 | fn get_non_zero(&self) -> Option<&Self::NonZero> { 71 | (*self).get_non_zero() 72 | } 73 | 74 | fn zero() -> Self::Zero { 75 | T::zero() 76 | } 77 | } 78 | 79 | impl Encoder for TypeIdx { 80 | fn encode(&self, bytes: &mut Vec) { 81 | self.0.encode(bytes); 82 | } 83 | } 84 | 85 | impl Decoder for TypeIdx { 86 | fn decode(input: &[u8]) -> IResult<&[u8], TypeIdx> { 87 | map(u32::decode, TypeIdx)(input) 88 | } 89 | } 90 | 91 | impl Encoder for FuncIdx { 92 | fn encode(&self, bytes: &mut Vec) { 93 | self.0.encode(bytes); 94 | } 95 | } 96 | 97 | impl Decoder for FuncIdx { 98 | fn decode(input: &[u8]) -> IResult<&[u8], FuncIdx> { 99 | map(u32::decode, FuncIdx)(input) 100 | } 101 | } 102 | 103 | impl Encoder for GlobalIdx { 104 | fn encode(&self, bytes: &mut Vec) { 105 | self.0.encode(bytes); 106 | } 107 | } 108 | 109 | impl Decoder for GlobalIdx { 110 | fn decode(input: &[u8]) -> IResult<&[u8], GlobalIdx> { 111 | map(u32::decode, GlobalIdx)(input) 112 | } 113 | } 114 | 115 | impl Encoder for LocalIdx { 116 | fn encode(&self, bytes: &mut Vec) { 117 | self.0.encode(bytes); 118 | } 119 | } 120 | 121 | impl Decoder for LocalIdx { 122 | fn decode(input: &[u8]) -> IResult<&[u8], LocalIdx> { 123 | map(u32::decode, LocalIdx)(input) 124 | } 125 | } 126 | 127 | impl Encoder for LabelIdx { 128 | fn encode(&self, bytes: &mut Vec) { 129 | self.0.encode(bytes); 130 | } 131 | } 132 | 133 | impl Decoder for LabelIdx { 134 | fn decode(input: &[u8]) -> IResult<&[u8], LabelIdx> { 135 | map(u32::decode, LabelIdx)(input) 136 | } 137 | } 138 | 139 | impl Encoder for MemIdx { 140 | fn encode(&self, bytes: &mut Vec) { 141 | self.0.encode(bytes); 142 | } 143 | } 144 | 145 | impl Decoder for MemIdx { 146 | fn decode(input: &[u8]) -> IResult<&[u8], MemIdx> { 147 | map(u32::decode, MemIdx)(input) 148 | } 149 | } 150 | 151 | impl Encoder for TableIdx { 152 | fn encode(&self, bytes: &mut Vec) { 153 | self.0.encode(bytes); 154 | } 155 | } 156 | 157 | impl Decoder for TableIdx { 158 | fn decode(input: &[u8]) -> IResult<&[u8], TableIdx> { 159 | map(u32::decode, TableIdx)(input) 160 | } 161 | } 162 | 163 | impl Encoder for Import { 164 | fn encode(&self, bytes: &mut Vec) { 165 | self.module.encode(bytes); 166 | self.name.encode(bytes); 167 | self.desc.encode(bytes); 168 | } 169 | } 170 | 171 | impl Decoder for Import { 172 | fn decode(input: &[u8]) -> IResult<&[u8], Import> { 173 | map( 174 | tuple((Name::decode, Name::decode, ImportDesc::decode)), 175 | |(module, name, desc)| Import { module, name, desc }, 176 | )(input) 177 | } 178 | } 179 | 180 | impl Encoder for ImportDesc { 181 | fn encode(&self, bytes: &mut Vec) { 182 | match self { 183 | ImportDesc::Func(x) => { 184 | bytes.push(0x00); 185 | x.encode(bytes); 186 | } 187 | ImportDesc::Table(tt) => { 188 | bytes.push(0x01); 189 | tt.encode(bytes); 190 | } 191 | ImportDesc::Mem(mt) => { 192 | bytes.push(0x02); 193 | mt.encode(bytes); 194 | } 195 | ImportDesc::Global(gt) => { 196 | bytes.push(0x03); 197 | gt.encode(bytes); 198 | } 199 | } 200 | } 201 | } 202 | 203 | impl Decoder for ImportDesc { 204 | fn decode(input: &[u8]) -> IResult<&[u8], ImportDesc> { 205 | alt(( 206 | map(tuple((parser::token(0x00), TypeIdx::decode)), |(_, x)| { 207 | ImportDesc::Func(x) 208 | }), 209 | map(tuple((parser::token(0x01), TableType::decode)), |(_, x)| { 210 | ImportDesc::Table(x) 211 | }), 212 | map(tuple((parser::token(0x02), MemType::decode)), |(_, x)| { 213 | ImportDesc::Mem(x) 214 | }), 215 | map( 216 | tuple((parser::token(0x03), GlobalType::decode)), 217 | |(_, x)| ImportDesc::Global(x), 218 | ), 219 | ))(input) 220 | } 221 | } 222 | impl Encoder for Table { 223 | fn encode(&self, bytes: &mut Vec) { 224 | self.type_.encode(bytes); 225 | } 226 | } 227 | 228 | impl Decoder for Table { 229 | fn decode(input: &[u8]) -> IResult<&[u8], Table> { 230 | map(TableType::decode, |type_| Table { type_ })(input) 231 | } 232 | } 233 | 234 | impl Encoder for Mem { 235 | fn encode(&self, bytes: &mut Vec) { 236 | self.type_.encode(bytes); 237 | } 238 | } 239 | 240 | impl Decoder for Mem { 241 | fn decode(input: &[u8]) -> IResult<&[u8], Mem> { 242 | map(MemType::decode, |type_| Mem { type_ })(input) 243 | } 244 | } 245 | 246 | impl Encoder for Global { 247 | fn encode(&self, bytes: &mut Vec) { 248 | self.type_.encode(bytes); 249 | self.init.encode(bytes); 250 | } 251 | } 252 | 253 | impl Decoder for Global { 254 | fn decode(input: &[u8]) -> IResult<&[u8], Global> { 255 | map( 256 | tuple((GlobalType::decode, Expr::decode)), 257 | |(type_, init)| Global { type_, init }, 258 | )(input) 259 | } 260 | } 261 | 262 | impl Encoder for Export { 263 | fn encode(&self, bytes: &mut Vec) { 264 | self.name.encode(bytes); 265 | self.desc.encode(bytes); 266 | } 267 | } 268 | 269 | impl Decoder for Export { 270 | fn decode(input: &[u8]) -> IResult<&[u8], Export> { 271 | map(tuple((Name::decode, ExportDesc::decode)), |(name, desc)| { 272 | Export { name, desc } 273 | })(input) 274 | } 275 | } 276 | 277 | impl Encoder for ExportDesc { 278 | fn encode(&self, bytes: &mut Vec) { 279 | match self { 280 | ExportDesc::Func(x) => { 281 | bytes.push(0x00); 282 | x.encode(bytes); 283 | } 284 | ExportDesc::Table(tt) => { 285 | bytes.push(0x01); 286 | tt.encode(bytes); 287 | } 288 | ExportDesc::Mem(mt) => { 289 | bytes.push(0x02); 290 | mt.encode(bytes); 291 | } 292 | ExportDesc::Global(gt) => { 293 | bytes.push(0x03); 294 | gt.encode(bytes); 295 | } 296 | } 297 | } 298 | } 299 | 300 | impl Decoder for ExportDesc { 301 | fn decode(input: &[u8]) -> IResult<&[u8], ExportDesc> { 302 | alt(( 303 | map(tuple((parser::token(0x00), FuncIdx::decode)), |(_, x)| { 304 | ExportDesc::Func(x) 305 | }), 306 | map(tuple((parser::token(0x01), TableIdx::decode)), |(_, x)| { 307 | ExportDesc::Table(x) 308 | }), 309 | map(tuple((parser::token(0x02), MemIdx::decode)), |(_, x)| { 310 | ExportDesc::Mem(x) 311 | }), 312 | map(tuple((parser::token(0x03), GlobalIdx::decode)), |(_, x)| { 313 | ExportDesc::Global(x) 314 | }), 315 | ))(input) 316 | } 317 | } 318 | 319 | impl Encoder for Start { 320 | fn encode(&self, bytes: &mut Vec) { 321 | self.func.encode(bytes) 322 | } 323 | } 324 | 325 | impl Decoder for Start { 326 | fn decode(input: &[u8]) -> IResult<&[u8], Start> { 327 | map(FuncIdx::decode, |func| Start { func })(input) 328 | } 329 | } 330 | 331 | impl Encoder for Elem { 332 | fn encode(&self, bytes: &mut Vec) { 333 | self.table.encode(bytes); 334 | self.offset.encode(bytes); 335 | self.init.encode(bytes); 336 | } 337 | } 338 | 339 | impl Decoder for Elem { 340 | fn decode(input: &[u8]) -> IResult<&[u8], Elem> { 341 | map( 342 | tuple((TableIdx::decode, Expr::decode, Vec::::decode)), 343 | |(table, offset, init)| Elem { 344 | table, 345 | offset, 346 | init, 347 | }, 348 | )(input) 349 | } 350 | } 351 | 352 | impl Encoder for Data { 353 | fn encode(&self, bytes: &mut Vec) { 354 | self.data.encode(bytes); 355 | self.offset.encode(bytes); 356 | self.init.encode(bytes); 357 | } 358 | } 359 | 360 | impl Decoder for Data { 361 | fn decode(input: &[u8]) -> IResult<&[u8], Data> { 362 | map( 363 | tuple((MemIdx::decode, Expr::decode, Vec::::decode)), 364 | |(data, offset, init)| Data { data, offset, init }, 365 | )(input) 366 | } 367 | } 368 | 369 | fn group_by_count(xs: &Vec) -> Vec<(u32, &T)> { 370 | xs.iter().fold(Vec::new(), |mut prev, x| { 371 | match prev.last_mut() { 372 | Some((prev_c, prev_x)) if &x == prev_x => { 373 | (*prev_c) += 1; 374 | } 375 | _ => { 376 | prev.push((1, x)); 377 | } 378 | } 379 | prev 380 | }) 381 | } 382 | 383 | #[test] 384 | fn test_group_by_count() { 385 | assert_eq!( 386 | group_by_count(&Vec::::new()), 387 | Vec::<(u32, &i32)>::new() 388 | ); 389 | 390 | assert_eq!(group_by_count(&vec![2]), vec![(1, &2)]); 391 | assert_eq!( 392 | group_by_count(&vec![2, 3, 4, 4, 4, 3, 2, 2]), 393 | vec![(1, &2), (1, &3), (3, &4), (1, &3), (2, &2)] 394 | ); 395 | } 396 | 397 | struct Code<'a>(&'a Func); 398 | 399 | impl<'a> Encoder for Code<'a> { 400 | fn encode(&self, bytes: &mut Vec) { 401 | let body = (group_by_count(&self.0.locals), &self.0.body).encode_to_vec(); 402 | (body.len() as u32).encode(bytes); 403 | bytes.extend_from_slice(&body); 404 | } 405 | } 406 | 407 | pub fn p_code(input: &[u8]) -> IResult<&[u8], (Vec, Expr)> { 408 | let (input, size) = u32::decode(input)?; 409 | let size = size as usize; 410 | let (code_input, input) = input.split_at(size); 411 | let (_, result) = map( 412 | tuple((Vec::<(u32, ValType)>::decode, Expr::decode, parser::eof())), 413 | |(locals, body, _)| { 414 | let locals = locals 415 | .into_iter() 416 | .map(|(l, t)| { 417 | let l = l as usize; 418 | let mut result = Vec::with_capacity(l); 419 | result.resize(l, t); 420 | result 421 | }) 422 | .collect::>() 423 | .concat(); 424 | (locals, body) 425 | }, 426 | )(code_input)?; 427 | Ok((input, result)) 428 | } 429 | 430 | fn encode_section(id: Byte, cont: T, bytes: &mut Vec) 431 | where 432 | T::NonZero: Encoder, 433 | { 434 | if let Some(x) = cont.get_non_zero() { 435 | id.encode(bytes); 436 | let body = x.encode_to_vec(); 437 | (body.len() as u32).encode(bytes); 438 | bytes.extend_from_slice(&body); 439 | } 440 | } 441 | 442 | fn p_section<'a, R>( 443 | id: Byte, 444 | p: impl Fn(&'a [u8]) -> IResult<&'a [u8], R>, 445 | ) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Option> { 446 | move |input| match Byte::decode(input) { 447 | Ok((_, id_)) if id_ != id => Ok((input, None)), 448 | Err(_) => Ok((input, None)), 449 | Ok((input, _id)) => { 450 | let (input, size) = u32::decode(input)?; 451 | let size = size as usize; 452 | let (body_input, input) = input.split_at(size); 453 | let (_, result) = map(tuple((&p, parser::eof())), |(x, _)| x)(body_input)?; 454 | Ok((input, Some(result))) 455 | } 456 | } 457 | } 458 | 459 | impl Encoder for Module { 460 | fn encode(&self, bytes: &mut Vec) { 461 | bytes.push(0x00); 462 | bytes.push(0x61); 463 | bytes.push(0x73); 464 | bytes.push(0x6d); 465 | 466 | bytes.push(0x01); 467 | bytes.push(0x00); 468 | bytes.push(0x00); 469 | bytes.push(0x00); 470 | 471 | encode_section(Byte(1), &self.types, bytes); 472 | encode_section(Byte(2), &self.imports, bytes); 473 | encode_section( 474 | Byte(3), 475 | self.funcs.iter().map(|x| &x.type_).collect::>(), 476 | bytes, 477 | ); 478 | encode_section(Byte(4), &self.tables, bytes); 479 | encode_section(Byte(5), &self.mems, bytes); 480 | encode_section(Byte(6), &self.globals, bytes); 481 | encode_section(Byte(7), &self.exports, bytes); 482 | encode_section(Byte(8), &self.start, bytes); 483 | encode_section(Byte(9), &self.elem, bytes); 484 | encode_section( 485 | Byte(10), 486 | self.funcs.iter().map(|x| Code(x)).collect::>(), 487 | bytes, 488 | ); 489 | encode_section(Byte(11), &self.data, bytes); 490 | } 491 | } 492 | 493 | fn p_costoms(input: &[u8]) -> IResult<&[u8], ()> { 494 | map( 495 | many0(flat_map( 496 | tuple((parser::token(0x00), u32::decode)), 497 | |(_, size)| many_m_n(size as usize, size as usize, Byte::decode), 498 | )), 499 | |_| (), 500 | )(input) 501 | } 502 | 503 | impl Decoder for Module { 504 | fn decode(input: &[u8]) -> IResult<&[u8], Module> { 505 | map( 506 | tuple(( 507 | tuple(( 508 | parser::token(0x00), 509 | parser::token(0x61), 510 | parser::token(0x73), 511 | parser::token(0x6d), 512 | parser::token(0x01), 513 | parser::token(0x00), 514 | parser::token(0x00), 515 | parser::token(0x00), 516 | )), 517 | tuple((p_costoms, p_section(Byte(1), Vec::::decode))), 518 | tuple((p_costoms, p_section(Byte(2), Vec::::decode))), 519 | tuple((p_costoms, p_section(Byte(3), Vec::::decode))), 520 | tuple((p_costoms, p_section(Byte(4), Vec::
::decode))), 521 | tuple((p_costoms, p_section(Byte(5), Vec::::decode))), 522 | tuple((p_costoms, p_section(Byte(6), Vec::::decode))), 523 | tuple((p_costoms, p_section(Byte(7), Vec::::decode))), 524 | tuple((p_costoms, p_section(Byte(8), Start::decode))), 525 | tuple((p_costoms, p_section(Byte(9), Vec::::decode))), 526 | tuple((p_costoms, p_section(Byte(10), super::values::p_vec(p_code)))), 527 | tuple((p_costoms, p_section(Byte(11), Vec::::decode))), 528 | p_costoms, 529 | )), 530 | |( 531 | _, 532 | (_, types), 533 | (_, imports), 534 | (_, funcs), 535 | (_, tables), 536 | (_, mems), 537 | (_, globals), 538 | (_, exports), 539 | (_, start), 540 | (_, elem), 541 | (_, code), 542 | (_, data), 543 | _, 544 | )| Module { 545 | types: types.unwrap_or_else(Vec::new), 546 | funcs: funcs 547 | .unwrap_or_else(Vec::new) 548 | .into_iter() 549 | .zip(code.unwrap_or_else(Vec::new)) 550 | .map(|(type_, (locals, body))| Func { 551 | type_, 552 | locals, 553 | body, 554 | }) 555 | .collect::>(), 556 | imports: imports.unwrap_or_else(Vec::new), 557 | tables: tables.unwrap_or_else(Vec::new), 558 | mems: mems.unwrap_or_else(Vec::new), 559 | globals: globals.unwrap_or_else(Vec::new), 560 | exports: exports.unwrap_or_else(Vec::new), 561 | start, 562 | elem: elem.unwrap_or_else(Vec::new), 563 | data: data.unwrap_or_else(Vec::new), 564 | }, 565 | )(input) 566 | } 567 | } 568 | 569 | #[test] 570 | fn tests() { 571 | use super::test_helper; 572 | 573 | // test_helper::identity_encode_decode::(); 574 | test_helper::identity_encode_decode::(); 575 | test_helper::identity_encode_decode::(); 576 | test_helper::identity_encode_decode::(); 577 | test_helper::identity_encode_decode::(); 578 | test_helper::identity_encode_decode::(); 579 | test_helper::identity_encode_decode::(); 580 | test_helper::identity_encode_decode::(); 581 | // test_helper::identity_encode_decode::(); 582 | test_helper::identity_encode_decode::
(); 583 | test_helper::identity_encode_decode::(); 584 | // test_helper::identity_encode_decode::(); 585 | // test_helper::identity_encode_decode::(); 586 | test_helper::identity_encode_decode::(); 587 | test_helper::identity_encode_decode::(); 588 | test_helper::identity_encode_decode::(); 589 | test_helper::identity_encode_decode::(); 590 | test_helper::identity_encode_decode::(); 591 | } 592 | -------------------------------------------------------------------------------- /src/binary/instructions.rs: -------------------------------------------------------------------------------- 1 | use super::parser; 2 | use super::util::loop_encode; 3 | use super::Encoder; 4 | use crate::structure::instructions::{Expr, Instr, Memarg}; 5 | use crate::structure::modules::{FuncIdx, GlobalIdx, LabelIdx, LocalIdx, TypeIdx}; 6 | use crate::structure::types::ResultType; 7 | use nom::{ 8 | branch::alt, 9 | combinator::{map, opt}, 10 | multi::many0, 11 | sequence::tuple, 12 | IResult, 13 | }; 14 | 15 | use super::Decoder; 16 | 17 | macro_rules! alt_m { 18 | ($x:expr) => { 19 | $x 20 | }; 21 | ($x:expr,) => { 22 | $x 23 | }; 24 | ( 25 | $a: expr, 26 | $b: expr, 27 | $c: expr, 28 | $d: expr, 29 | $e: expr, 30 | $f: expr, 31 | $g: expr, 32 | $h: expr, 33 | $i: expr, 34 | $j: expr, 35 | $k: expr, 36 | $l: expr, 37 | $m: expr, 38 | $n: expr, 39 | $o: expr, 40 | $p: expr, 41 | $q: expr, 42 | $r: expr, 43 | $s: expr, 44 | $t: expr, 45 | $u: expr, 46 | $v: expr, 47 | $w: expr, 48 | $x: expr, 49 | $y: expr, 50 | $($xs:tt)+) => { 51 | alt(( 52 | alt(($a, 53 | $b, 54 | $c, 55 | $d, 56 | $e)), 57 | alt(($f, 58 | $g, 59 | $h, 60 | $i, 61 | $j)), 62 | alt(($k, 63 | $l, 64 | $m, 65 | $n, 66 | $o)), 67 | alt(($p, 68 | $q, 69 | $r, 70 | $s, 71 | $t)), 72 | alt(($u, 73 | $v, 74 | $w, 75 | $x, 76 | $y)), 77 | alt_m!($($xs)+))) 78 | }; 79 | ($x1:expr, $x2:expr, $x3:expr, $x4:expr, $x5:expr, $x6:expr, $x7:expr, $x8:expr, $($xs:tt)+) => { 80 | alt(($x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, alt_m!($($xs)+))) 81 | }; 82 | ($x1:expr, $x2:expr, $x3:expr, $x4:expr, $x5:expr, $x6:expr, $x7:expr, $($xs:tt)+) => { 83 | alt(($x1, $x2, $x3, $x4, $x5, $x6, $x7, alt_m!($($xs)+))) 84 | }; 85 | ($x1:expr, $x2:expr, $x3:expr, $x4:expr, $x5:expr, $x6:expr, $($xs:tt)+) => { 86 | alt(($x1, $x2, $x3, $x4, $x5, $x6, alt_m!($($xs)+))) 87 | }; 88 | ($x1:expr, $x2:expr, $x3:expr, $x4:expr, $x5:expr, $($xs:tt)+) => { 89 | alt(($x1, $x2, $x3, $x4, $x5, alt_m!($($xs)+))) 90 | }; 91 | ($x1:expr, $x2:expr, $x3:expr, $x4:expr, $($xs:tt)+) => { 92 | alt(($x1, $x2, $x3, $x4, alt_m!($($xs)+))) 93 | }; 94 | ($x1:expr, $x2:expr, $x3:expr, $($xs:tt)+) => { 95 | alt(($x1, $x2, $x3 ,alt_m!($($xs)+))) 96 | }; 97 | ($x1:expr, $x2:expr, $($xs:tt)+) => { 98 | alt(($x1, $x2 ,alt_m!($($xs)+))) 99 | }; 100 | ($x:expr, $($xs:tt)+) => { 101 | alt(($x,alt_m!($($xs)+))) 102 | }; 103 | } 104 | 105 | impl Encoder for Expr { 106 | fn encode(&self, bytes: &mut Vec) { 107 | loop_encode(&self.0, bytes); 108 | bytes.push(0x0b); 109 | } 110 | } 111 | 112 | impl Decoder for Expr { 113 | fn decode(input: &[u8]) -> IResult<&[u8], Expr> { 114 | map( 115 | tuple((many0(Instr::decode), parser::token(0x0b))), 116 | |(x, _)| Expr(x), 117 | )(input) 118 | } 119 | } 120 | 121 | impl Encoder for Instr { 122 | fn encode(&self, bytes: &mut Vec) { 123 | match &self { 124 | Instr::Unreachable => bytes.push(0x00), 125 | Instr::Nop => bytes.push(0x01), 126 | Instr::Block(rt, is) => { 127 | bytes.push(0x02); 128 | rt.encode(bytes); 129 | loop_encode(is, bytes); 130 | bytes.push(0x0b); 131 | } 132 | Instr::Loop(rt, is) => { 133 | bytes.push(0x03); 134 | rt.encode(bytes); 135 | loop_encode(is, bytes); 136 | bytes.push(0x0b); 137 | } 138 | Instr::If(rt, is1, is2) => { 139 | bytes.push(0x04); 140 | rt.encode(bytes); 141 | loop_encode(is1, bytes); 142 | if !is2.is_empty() { 143 | bytes.push(0x05); 144 | loop_encode(is2, bytes); 145 | } 146 | bytes.push(0x0b); 147 | } 148 | Instr::Br(l) => { 149 | bytes.push(0x0c); 150 | l.encode(bytes); 151 | } 152 | Instr::BrIf(l) => { 153 | bytes.push(0x0d); 154 | l.encode(bytes); 155 | } 156 | Instr::BrTable(ls, l) => { 157 | bytes.push(0x0e); 158 | ls.encode(bytes); 159 | l.encode(bytes); 160 | } 161 | Instr::Return => bytes.push(0x0f), 162 | Instr::Call(x) => { 163 | bytes.push(0x10); 164 | x.encode(bytes); 165 | } 166 | Instr::CallIndirect(x) => { 167 | bytes.push(0x11); 168 | x.encode(bytes); 169 | bytes.push(0x00); 170 | } 171 | Instr::Drop => bytes.push(0x1a), 172 | Instr::Select => bytes.push(0x1b), 173 | Instr::LocalGet(x) => { 174 | bytes.push(0x20); 175 | x.encode(bytes); 176 | } 177 | Instr::LocalSet(x) => { 178 | bytes.push(0x21); 179 | x.encode(bytes); 180 | } 181 | Instr::LocalTee(x) => { 182 | bytes.push(0x22); 183 | x.encode(bytes); 184 | } 185 | Instr::GlobalGet(x) => { 186 | bytes.push(0x23); 187 | x.encode(bytes); 188 | } 189 | Instr::GlobalSet(x) => { 190 | bytes.push(0x24); 191 | x.encode(bytes); 192 | } 193 | Instr::I32Load(m) => { 194 | bytes.push(0x28); 195 | m.encode(bytes); 196 | } 197 | Instr::I64Load(m) => { 198 | bytes.push(0x29); 199 | m.encode(bytes); 200 | } 201 | Instr::F32Load(m) => { 202 | bytes.push(0x2a); 203 | m.encode(bytes); 204 | } 205 | Instr::F64Load(m) => { 206 | bytes.push(0x2b); 207 | m.encode(bytes); 208 | } 209 | Instr::I32Load8S(m) => { 210 | bytes.push(0x2c); 211 | m.encode(bytes); 212 | } 213 | Instr::I32Load8U(m) => { 214 | bytes.push(0x2d); 215 | m.encode(bytes); 216 | } 217 | Instr::I32Load16S(m) => { 218 | bytes.push(0x2e); 219 | m.encode(bytes); 220 | } 221 | Instr::I32Load16U(m) => { 222 | bytes.push(0x2f); 223 | m.encode(bytes); 224 | } 225 | Instr::I64Load8S(m) => { 226 | bytes.push(0x30); 227 | m.encode(bytes); 228 | } 229 | Instr::I64Load8U(m) => { 230 | bytes.push(0x31); 231 | m.encode(bytes); 232 | } 233 | Instr::I64Load16S(m) => { 234 | bytes.push(0x32); 235 | m.encode(bytes); 236 | } 237 | Instr::I64Load16U(m) => { 238 | bytes.push(0x33); 239 | m.encode(bytes); 240 | } 241 | Instr::I64Load32S(m) => { 242 | bytes.push(0x34); 243 | m.encode(bytes); 244 | } 245 | Instr::I64Load32U(m) => { 246 | bytes.push(0x35); 247 | m.encode(bytes); 248 | } 249 | Instr::I32Store(m) => { 250 | bytes.push(0x36); 251 | m.encode(bytes); 252 | } 253 | Instr::I64Store(m) => { 254 | bytes.push(0x37); 255 | m.encode(bytes); 256 | } 257 | Instr::F32Store(m) => { 258 | bytes.push(0x38); 259 | m.encode(bytes); 260 | } 261 | Instr::F64Store(m) => { 262 | bytes.push(0x39); 263 | m.encode(bytes); 264 | } 265 | Instr::I32Store8(m) => { 266 | bytes.push(0x3a); 267 | m.encode(bytes); 268 | } 269 | Instr::I32Store16(m) => { 270 | bytes.push(0x3b); 271 | m.encode(bytes); 272 | } 273 | Instr::I64Store8(m) => { 274 | bytes.push(0x3c); 275 | m.encode(bytes); 276 | } 277 | Instr::I64Store16(m) => { 278 | bytes.push(0x3d); 279 | m.encode(bytes); 280 | } 281 | Instr::I64Store32(m) => { 282 | bytes.push(0x3e); 283 | m.encode(bytes); 284 | } 285 | Instr::MemorySize => { 286 | bytes.push(0x3f); 287 | bytes.push(0x00); 288 | } 289 | Instr::MemoryGrow => { 290 | bytes.push(0x40); 291 | bytes.push(0x00); 292 | } 293 | Instr::I32Const(n) => { 294 | bytes.push(0x41); 295 | n.encode(bytes); 296 | } 297 | Instr::I64Const(n) => { 298 | bytes.push(0x42); 299 | n.encode(bytes); 300 | } 301 | Instr::F32Const(z) => { 302 | bytes.push(0x43); 303 | z.encode(bytes); 304 | } 305 | Instr::F64Const(z) => { 306 | bytes.push(0x44); 307 | z.encode(bytes); 308 | } 309 | Instr::I32Eqz => bytes.push(0x45), 310 | Instr::I32Eq => bytes.push(0x46), 311 | Instr::I32Ne => bytes.push(0x47), 312 | Instr::I32LtS => bytes.push(0x48), 313 | Instr::I32LtU => bytes.push(0x49), 314 | Instr::I32GtS => bytes.push(0x4a), 315 | Instr::I32GtU => bytes.push(0x4b), 316 | Instr::I32LeS => bytes.push(0x4c), 317 | Instr::I32LeU => bytes.push(0x4d), 318 | Instr::I32GeS => bytes.push(0x4e), 319 | Instr::I32GeU => bytes.push(0x4f), 320 | Instr::I64Eqz => bytes.push(0x50), 321 | Instr::I64Eq => bytes.push(0x51), 322 | Instr::I64Ne => bytes.push(0x52), 323 | Instr::I64LtS => bytes.push(0x53), 324 | Instr::I64LtU => bytes.push(0x54), 325 | Instr::I64GtS => bytes.push(0x55), 326 | Instr::I64GtU => bytes.push(0x56), 327 | Instr::I64LeS => bytes.push(0x57), 328 | Instr::I64LeU => bytes.push(0x58), 329 | Instr::I64GeS => bytes.push(0x59), 330 | Instr::I64GeU => bytes.push(0x5a), 331 | Instr::F32Eq => bytes.push(0x5b), 332 | Instr::F32Ne => bytes.push(0x5c), 333 | Instr::F32Lt => bytes.push(0x5d), 334 | Instr::F32Gt => bytes.push(0x5e), 335 | Instr::F32Le => bytes.push(0x5f), 336 | Instr::F32Ge => bytes.push(0x60), 337 | Instr::F64Eq => bytes.push(0x61), 338 | Instr::F64Ne => bytes.push(0x62), 339 | Instr::F64Lt => bytes.push(0x63), 340 | Instr::F64Gt => bytes.push(0x64), 341 | Instr::F64Le => bytes.push(0x65), 342 | Instr::F64Ge => bytes.push(0x66), 343 | Instr::I32Clz => bytes.push(0x67), 344 | Instr::I32Ctz => bytes.push(0x68), 345 | Instr::I32Popcnt => bytes.push(0x69), 346 | Instr::I32Add => bytes.push(0x6a), 347 | Instr::I32Sub => bytes.push(0x6b), 348 | Instr::I32Mul => bytes.push(0x6c), 349 | Instr::I32DivS => bytes.push(0x6d), 350 | Instr::I32DivU => bytes.push(0x6e), 351 | Instr::I32RemS => bytes.push(0x6f), 352 | Instr::I32RemU => bytes.push(0x70), 353 | Instr::I32And => bytes.push(0x71), 354 | Instr::I32Or => bytes.push(0x72), 355 | Instr::I32Xor => bytes.push(0x73), 356 | Instr::I32ShL => bytes.push(0x74), 357 | Instr::I32ShrS => bytes.push(0x75), 358 | Instr::I32ShrU => bytes.push(0x76), 359 | Instr::I32Rotl => bytes.push(0x77), 360 | Instr::I32Rotr => bytes.push(0x78), 361 | Instr::I64Clz => bytes.push(0x79), 362 | Instr::I64Ctz => bytes.push(0x7a), 363 | Instr::I64Popcnt => bytes.push(0x7b), 364 | Instr::I64Add => bytes.push(0x7c), 365 | Instr::I64Sub => bytes.push(0x7d), 366 | Instr::I64Mul => bytes.push(0x7e), 367 | Instr::I64DivS => bytes.push(0x7f), 368 | Instr::I64DivU => bytes.push(0x80), 369 | Instr::I64RemS => bytes.push(0x81), 370 | Instr::I64RemU => bytes.push(0x82), 371 | Instr::I64And => bytes.push(0x83), 372 | Instr::I64Or => bytes.push(0x84), 373 | Instr::I64Xor => bytes.push(0x85), 374 | Instr::I64ShL => bytes.push(0x86), 375 | Instr::I64ShrS => bytes.push(0x87), 376 | Instr::I64ShrU => bytes.push(0x88), 377 | Instr::I64Rotl => bytes.push(0x89), 378 | Instr::I64Rotr => bytes.push(0x8a), 379 | Instr::F32Abs => bytes.push(0x8b), 380 | Instr::F32Neg => bytes.push(0x8c), 381 | Instr::F32Ceil => bytes.push(0x8d), 382 | Instr::F32Floor => bytes.push(0x8e), 383 | Instr::F32Trunc => bytes.push(0x8f), 384 | Instr::F32Nearest => bytes.push(0x90), 385 | Instr::F32Sqrt => bytes.push(0x91), 386 | Instr::F32Add => bytes.push(0x92), 387 | Instr::F32Sub => bytes.push(0x93), 388 | Instr::F32Mul => bytes.push(0x94), 389 | Instr::F32Div => bytes.push(0x95), 390 | Instr::F32Min => bytes.push(0x96), 391 | Instr::F32Max => bytes.push(0x97), 392 | Instr::F32CopySign => bytes.push(0x98), 393 | Instr::F64Abs => bytes.push(0x99), 394 | Instr::F64Neg => bytes.push(0x9a), 395 | Instr::F64Ceil => bytes.push(0x9b), 396 | Instr::F64Floor => bytes.push(0x9c), 397 | Instr::F64Trunc => bytes.push(0x9d), 398 | Instr::F64Nearest => bytes.push(0x9e), 399 | Instr::F64Sqrt => bytes.push(0x9f), 400 | Instr::F64Add => bytes.push(0xa0), 401 | Instr::F64Sub => bytes.push(0xa1), 402 | Instr::F64Mul => bytes.push(0xa2), 403 | Instr::F64Div => bytes.push(0xa3), 404 | Instr::F64Min => bytes.push(0xa4), 405 | Instr::F64Max => bytes.push(0xa5), 406 | Instr::F64CopySign => bytes.push(0xa6), 407 | Instr::I32WrapI64 => bytes.push(0xa7), 408 | Instr::I32TruncF32S => bytes.push(0xa8), 409 | Instr::I32TruncF32U => bytes.push(0xa9), 410 | Instr::I32TruncF64S => bytes.push(0xaa), 411 | Instr::I32TruncF64U => bytes.push(0xab), 412 | Instr::I64ExtendI32S => bytes.push(0xac), 413 | Instr::I64ExtendI32U => bytes.push(0xad), 414 | Instr::I64TruncF32S => bytes.push(0xae), 415 | Instr::I64TruncF32U => bytes.push(0xaf), 416 | Instr::I64TruncF64S => bytes.push(0xb0), 417 | Instr::I64TruncF64U => bytes.push(0xb1), 418 | Instr::F32ConvertI32S => bytes.push(0xb2), 419 | Instr::F32ConvertI32U => bytes.push(0xb3), 420 | Instr::F32ConvertI64S => bytes.push(0xb4), 421 | Instr::F32ConvertI64U => bytes.push(0xb5), 422 | Instr::F32DemoteF64 => bytes.push(0xb6), 423 | Instr::F64ConvertI32S => bytes.push(0xb7), 424 | Instr::F64ConvertI32U => bytes.push(0xb8), 425 | Instr::F64ConvertI64S => bytes.push(0xb9), 426 | Instr::F64ConvertI64U => bytes.push(0xba), 427 | Instr::F64PromoteF32 => bytes.push(0xbb), 428 | Instr::I32ReinterpretF32 => bytes.push(0xbc), 429 | Instr::I64ReinterpretF64 => bytes.push(0xbd), 430 | Instr::F32ReinterpretI32 => bytes.push(0xbe), 431 | Instr::F64ReinterpretI64 => bytes.push(0xbf), 432 | } 433 | } 434 | } 435 | 436 | impl Decoder for Instr { 437 | fn decode(input: &[u8]) -> IResult<&[u8], Instr> { 438 | alt_m!( 439 | map(parser::token(0x00), |_| Instr::Unreachable), 440 | map(parser::token(0x01), |_| Instr::Nop), 441 | map( 442 | tuple(( 443 | parser::token(0x02), 444 | ResultType::decode, 445 | many0(Instr::decode), 446 | parser::token(0x0b) 447 | )), 448 | |(_, rt, is, _)| Instr::Block(rt, is), 449 | ), 450 | map( 451 | tuple(( 452 | parser::token(0x03), 453 | ResultType::decode, 454 | many0(Instr::decode), 455 | parser::token(0x0b) 456 | )), 457 | |(_, rt, is, _)| Instr::Loop(rt, is), 458 | ), 459 | map( 460 | tuple(( 461 | parser::token(0x04), 462 | ResultType::decode, 463 | many0(Instr::decode), 464 | opt(map( 465 | tuple((parser::token(0x05), many0(Instr::decode))), 466 | |(_, x)| x 467 | )), 468 | parser::token(0x0b) 469 | )), 470 | |(_, rt, is1, is2, _)| Instr::If(rt, is1, is2.unwrap_or_else(Vec::new)), 471 | ), 472 | map(tuple((parser::token(0x0c), LabelIdx::decode)), |(_, l)| { 473 | Instr::Br(l) 474 | }), 475 | map(tuple((parser::token(0x0d), LabelIdx::decode)), |(_, l)| { 476 | Instr::BrIf(l) 477 | }), 478 | map( 479 | tuple(( 480 | parser::token(0x0e), 481 | super::values::p_vec(LabelIdx::decode), 482 | LabelIdx::decode 483 | )), 484 | |(_, ls, l)| Instr::BrTable(ls, l), 485 | ), 486 | map(parser::token(0x0f), |_| Instr::Return), 487 | map(tuple((parser::token(0x10), FuncIdx::decode)), |(_, f)| { 488 | Instr::Call(f) 489 | }), 490 | map( 491 | tuple((parser::token(0x11), TypeIdx::decode, parser::token(0x00))), 492 | |(_, t, _)| Instr::CallIndirect(t), 493 | ), 494 | map(parser::token(0x1a), |_| Instr::Drop), 495 | map(parser::token(0x1b), |_| Instr::Select), 496 | map(tuple((parser::token(0x20), LocalIdx::decode)), |(_, x)| { 497 | Instr::LocalGet(x) 498 | }), 499 | map(tuple((parser::token(0x21), LocalIdx::decode)), |(_, x)| { 500 | Instr::LocalSet(x) 501 | }), 502 | map(tuple((parser::token(0x22), LocalIdx::decode)), |(_, x)| { 503 | Instr::LocalTee(x) 504 | }), 505 | map(tuple((parser::token(0x23), GlobalIdx::decode)), |(_, x)| { 506 | Instr::GlobalGet(x) 507 | }), 508 | map(tuple((parser::token(0x24), GlobalIdx::decode)), |(_, x)| { 509 | Instr::GlobalSet(x) 510 | }), 511 | map(tuple((parser::token(0x28), Memarg::decode)), |(_, m)| { 512 | Instr::I32Load(m) 513 | }), 514 | map(tuple((parser::token(0x29), Memarg::decode)), |(_, m)| { 515 | Instr::I64Load(m) 516 | }), 517 | map(tuple((parser::token(0x2a), Memarg::decode)), |(_, m)| { 518 | Instr::F32Load(m) 519 | }), 520 | map(tuple((parser::token(0x2a), Memarg::decode)), |(_, m)| { 521 | Instr::F32Load(m) 522 | }), 523 | map(tuple((parser::token(0x2b), Memarg::decode)), |(_, m)| { 524 | Instr::F64Load(m) 525 | }), 526 | map(tuple((parser::token(0x2c), Memarg::decode)), |(_, m)| { 527 | Instr::I32Load8S(m) 528 | }), 529 | map(tuple((parser::token(0x2d), Memarg::decode)), |(_, m)| { 530 | Instr::I32Load8U(m) 531 | }), 532 | map(tuple((parser::token(0x2e), Memarg::decode)), |(_, m)| { 533 | Instr::I32Load16S(m) 534 | }), 535 | map(tuple((parser::token(0x2f), Memarg::decode)), |(_, m)| { 536 | Instr::I32Load16U(m) 537 | }), 538 | map(tuple((parser::token(0x30), Memarg::decode)), |(_, m)| { 539 | Instr::I64Load8S(m) 540 | }), 541 | map(tuple((parser::token(0x31), Memarg::decode)), |(_, m)| { 542 | Instr::I64Load8U(m) 543 | }), 544 | map(tuple((parser::token(0x32), Memarg::decode)), |(_, m)| { 545 | Instr::I64Load16S(m) 546 | }), 547 | map(tuple((parser::token(0x33), Memarg::decode)), |(_, m)| { 548 | Instr::I64Load16U(m) 549 | }), 550 | map(tuple((parser::token(0x34), Memarg::decode)), |(_, m)| { 551 | Instr::I64Load32S(m) 552 | }), 553 | map(tuple((parser::token(0x35), Memarg::decode)), |(_, m)| { 554 | Instr::I64Load32U(m) 555 | }), 556 | map(tuple((parser::token(0x36), Memarg::decode)), |(_, m)| { 557 | Instr::I32Store(m) 558 | }), 559 | map(tuple((parser::token(0x37), Memarg::decode)), |(_, m)| { 560 | Instr::I64Store(m) 561 | }), 562 | map(tuple((parser::token(0x38), Memarg::decode)), |(_, m)| { 563 | Instr::F32Store(m) 564 | }), 565 | map(tuple((parser::token(0x39), Memarg::decode)), |(_, m)| { 566 | Instr::F64Store(m) 567 | }), 568 | map(tuple((parser::token(0x3a), Memarg::decode)), |(_, m)| { 569 | Instr::I32Store8(m) 570 | }), 571 | map(tuple((parser::token(0x3b), Memarg::decode)), |(_, m)| { 572 | Instr::I32Store16(m) 573 | }), 574 | map(tuple((parser::token(0x3c), Memarg::decode)), |(_, m)| { 575 | Instr::I64Store8(m) 576 | }), 577 | map(tuple((parser::token(0x3d), Memarg::decode)), |(_, m)| { 578 | Instr::I64Store16(m) 579 | }), 580 | map(tuple((parser::token(0x3e), Memarg::decode)), |(_, m)| { 581 | Instr::I64Store32(m) 582 | }), 583 | map(tuple((parser::token(0x3f), parser::token(0x00))), |_| { 584 | Instr::MemorySize 585 | }), 586 | map(tuple((parser::token(0x40), parser::token(0x00))), |_| { 587 | Instr::MemoryGrow 588 | }), 589 | map(tuple((parser::token(0x41), i32::decode)), |(_, n)| { 590 | Instr::I32Const(n) 591 | }), 592 | map(tuple((parser::token(0x42), i64::decode)), |(_, n)| { 593 | Instr::I64Const(n) 594 | }), 595 | map(tuple((parser::token(0x43), f32::decode)), |(_, z)| { 596 | Instr::F32Const(z) 597 | }), 598 | map(tuple((parser::token(0x44), f64::decode)), |(_, z)| { 599 | Instr::F64Const(z) 600 | }), 601 | map(parser::token(0x45), |_| Instr::I32Eqz), 602 | map(parser::token(0x46), |_| Instr::I32Eq), 603 | map(parser::token(0x47), |_| Instr::I32Ne), 604 | map(parser::token(0x48), |_| Instr::I32LtS), 605 | map(parser::token(0x49), |_| Instr::I32LtU), 606 | map(parser::token(0x4a), |_| Instr::I32GtS), 607 | map(parser::token(0x4b), |_| Instr::I32GtU), 608 | map(parser::token(0x4c), |_| Instr::I32LeS), 609 | map(parser::token(0x4d), |_| Instr::I32LeU), 610 | map(parser::token(0x4e), |_| Instr::I32GeS), 611 | map(parser::token(0x4f), |_| Instr::I32GeU), 612 | map(parser::token(0x50), |_| Instr::I64Eqz), 613 | map(parser::token(0x51), |_| Instr::I64Eq), 614 | map(parser::token(0x52), |_| Instr::I64Ne), 615 | map(parser::token(0x53), |_| Instr::I64LtS), 616 | map(parser::token(0x54), |_| Instr::I64LtU), 617 | map(parser::token(0x55), |_| Instr::I64GtS), 618 | map(parser::token(0x56), |_| Instr::I64GtU), 619 | map(parser::token(0x57), |_| Instr::I64LeS), 620 | map(parser::token(0x58), |_| Instr::I64LeU), 621 | map(parser::token(0x59), |_| Instr::I64GeS), 622 | map(parser::token(0x5a), |_| Instr::I64GeU), 623 | map(parser::token(0x5b), |_| Instr::F32Eq), 624 | map(parser::token(0x5c), |_| Instr::F32Ne), 625 | map(parser::token(0x5d), |_| Instr::F32Lt), 626 | map(parser::token(0x5e), |_| Instr::F32Gt), 627 | map(parser::token(0x5f), |_| Instr::F32Le), 628 | map(parser::token(0x60), |_| Instr::F32Ge), 629 | map(parser::token(0x61), |_| Instr::F64Eq), 630 | map(parser::token(0x62), |_| Instr::F64Ne), 631 | map(parser::token(0x63), |_| Instr::F64Lt), 632 | map(parser::token(0x64), |_| Instr::F64Gt), 633 | map(parser::token(0x65), |_| Instr::F64Le), 634 | map(parser::token(0x66), |_| Instr::F64Ge), 635 | map(parser::token(0x67), |_| Instr::I32Clz), 636 | map(parser::token(0x68), |_| Instr::I32Ctz), 637 | map(parser::token(0x69), |_| Instr::I32Popcnt), 638 | map(parser::token(0x6a), |_| Instr::I32Add), 639 | map(parser::token(0x6b), |_| Instr::I32Sub), 640 | map(parser::token(0x6c), |_| Instr::I32Mul), 641 | map(parser::token(0x6d), |_| Instr::I32DivS), 642 | map(parser::token(0x6e), |_| Instr::I32DivU), 643 | map(parser::token(0x6f), |_| Instr::I32RemS), 644 | map(parser::token(0x70), |_| Instr::I32RemU), 645 | map(parser::token(0x71), |_| Instr::I32And), 646 | map(parser::token(0x72), |_| Instr::I32Or), 647 | map(parser::token(0x73), |_| Instr::I32Xor), 648 | map(parser::token(0x74), |_| Instr::I32ShL), 649 | map(parser::token(0x75), |_| Instr::I32ShrS), 650 | map(parser::token(0x76), |_| Instr::I32ShrU), 651 | map(parser::token(0x77), |_| Instr::I32Rotl), 652 | map(parser::token(0x78), |_| Instr::I32Rotr), 653 | map(parser::token(0x79), |_| Instr::I64Clz), 654 | map(parser::token(0x7a), |_| Instr::I64Ctz), 655 | map(parser::token(0x7b), |_| Instr::I64Popcnt), 656 | map(parser::token(0x7c), |_| Instr::I64Add), 657 | map(parser::token(0x7d), |_| Instr::I64Sub), 658 | map(parser::token(0x7e), |_| Instr::I64Mul), 659 | map(parser::token(0x7f), |_| Instr::I64DivS), 660 | map(parser::token(0x80), |_| Instr::I64DivU), 661 | map(parser::token(0x81), |_| Instr::I64RemS), 662 | map(parser::token(0x82), |_| Instr::I64RemU), 663 | map(parser::token(0x83), |_| Instr::I64And), 664 | map(parser::token(0x84), |_| Instr::I64Or), 665 | map(parser::token(0x85), |_| Instr::I64Xor), 666 | map(parser::token(0x86), |_| Instr::I64ShL), 667 | map(parser::token(0x87), |_| Instr::I64ShrS), 668 | map(parser::token(0x88), |_| Instr::I64ShrU), 669 | map(parser::token(0x89), |_| Instr::I64Rotl), 670 | map(parser::token(0x8a), |_| Instr::I64Rotr), 671 | map(parser::token(0x8b), |_| Instr::F32Abs), 672 | map(parser::token(0x8c), |_| Instr::F32Neg), 673 | map(parser::token(0x8d), |_| Instr::F32Ceil), 674 | map(parser::token(0x8e), |_| Instr::F32Floor), 675 | map(parser::token(0x8f), |_| Instr::F32Trunc), 676 | map(parser::token(0x90), |_| Instr::F32Nearest), 677 | map(parser::token(0x91), |_| Instr::F32Sqrt), 678 | map(parser::token(0x92), |_| Instr::F32Add), 679 | map(parser::token(0x93), |_| Instr::F32Sub), 680 | map(parser::token(0x94), |_| Instr::F32Mul), 681 | map(parser::token(0x95), |_| Instr::F32Div), 682 | map(parser::token(0x96), |_| Instr::F32Min), 683 | map(parser::token(0x97), |_| Instr::F32Max), 684 | map(parser::token(0x98), |_| Instr::F32CopySign), 685 | map(parser::token(0x99), |_| Instr::F64Abs), 686 | map(parser::token(0x9a), |_| Instr::F64Neg), 687 | map(parser::token(0x9b), |_| Instr::F64Ceil), 688 | map(parser::token(0x9c), |_| Instr::F64Floor), 689 | map(parser::token(0x9d), |_| Instr::F64Trunc), 690 | map(parser::token(0x9e), |_| Instr::F64Nearest), 691 | map(parser::token(0x9f), |_| Instr::F64Sqrt), 692 | map(parser::token(0xa0), |_| Instr::F64Add), 693 | map(parser::token(0xa1), |_| Instr::F64Sub), 694 | map(parser::token(0xa2), |_| Instr::F64Mul), 695 | map(parser::token(0xa3), |_| Instr::F64Div), 696 | map(parser::token(0xa4), |_| Instr::F64Min), 697 | map(parser::token(0xa5), |_| Instr::F64Max), 698 | map(parser::token(0xa6), |_| Instr::F64CopySign), 699 | map(parser::token(0xa7), |_| Instr::I32WrapI64), 700 | map(parser::token(0xa8), |_| Instr::I32TruncF32S), 701 | map(parser::token(0xa9), |_| Instr::I32TruncF32U), 702 | map(parser::token(0xaa), |_| Instr::I32TruncF64S), 703 | map(parser::token(0xab), |_| Instr::I32TruncF64U), 704 | map(parser::token(0xac), |_| Instr::I64ExtendI32S), 705 | map(parser::token(0xad), |_| Instr::I64ExtendI32U), 706 | map(parser::token(0xae), |_| Instr::I64TruncF32S), 707 | map(parser::token(0xaf), |_| Instr::I64TruncF32U), 708 | map(parser::token(0xb0), |_| Instr::I64TruncF64S), 709 | map(parser::token(0xb1), |_| Instr::I64TruncF64U), 710 | map(parser::token(0xb2), |_| Instr::F32ConvertI32S), 711 | map(parser::token(0xb3), |_| Instr::F32ConvertI32U), 712 | map(parser::token(0xb4), |_| Instr::F32ConvertI64S), 713 | map(parser::token(0xb5), |_| Instr::F32ConvertI64U), 714 | map(parser::token(0xb6), |_| Instr::F32DemoteF64), 715 | map(parser::token(0xb7), |_| Instr::F64ConvertI32S), 716 | map(parser::token(0xb8), |_| Instr::F64ConvertI32U), 717 | map(parser::token(0xb9), |_| Instr::F64ConvertI64S), 718 | map(parser::token(0xba), |_| Instr::F64ConvertI64U), 719 | map(parser::token(0xbb), |_| Instr::F64PromoteF32), 720 | map(parser::token(0xbc), |_| Instr::I32ReinterpretF32), 721 | map(parser::token(0xbd), |_| Instr::I64ReinterpretF64), 722 | map(parser::token(0xbe), |_| Instr::F32ReinterpretI32), 723 | map(parser::token(0xbf), |_| Instr::F64ReinterpretI64), 724 | )(input) 725 | } 726 | } 727 | 728 | impl Encoder for Memarg { 729 | fn encode(&self, bytes: &mut Vec) { 730 | self.align.encode(bytes); 731 | self.offset.encode(bytes); 732 | } 733 | } 734 | 735 | impl Decoder for Memarg { 736 | fn decode(input: &[u8]) -> IResult<&[u8], Memarg> { 737 | map(tuple((u32::decode, u32::decode)), |(align, offset)| { 738 | Memarg { align, offset } 739 | })(input) 740 | } 741 | } 742 | 743 | #[test] 744 | fn tests() { 745 | use super::test_helper; 746 | 747 | // test_helper::identity_encode_decode::(); 748 | // test_helper::identity_encode_decode::(); 749 | test_helper::identity_encode_decode::(); 750 | } 751 | -------------------------------------------------------------------------------- /src/exec/stack.rs: -------------------------------------------------------------------------------- 1 | use super::func::{FuncAddr, FuncInst}; 2 | use super::instance::{ModuleInst, TypedIdxAccess}; 3 | use super::utils::{pop_n, sign_f32, sign_f64, Sign}; 4 | use super::val::{InterpretVal, Val}; 5 | use crate::structure::instructions::Instr; 6 | use crate::structure::modules::{LabelIdx, TypedIdx}; 7 | use crate::structure::types::ValType; 8 | use crate::WasmError; 9 | use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; 10 | use frunk::{from_generic, hlist::HList, into_generic, Generic, HCons, HNil}; 11 | use num::NumCast; 12 | use std::io::Cursor; 13 | use std::rc::Weak; 14 | 15 | pub trait StackValues: Sized { 16 | fn pop_stack(stack: &mut Vec) -> Option; 17 | fn push_stack(self, stack: &mut Vec); 18 | } 19 | 20 | impl StackValues for T { 21 | fn pop_stack(stack: &mut Vec) -> Option { 22 | let val = stack.pop()?; 23 | T::try_interpret_val(val) 24 | } 25 | fn push_stack(self, stack: &mut Vec) { 26 | stack.push(self.to_val()); 27 | } 28 | } 29 | 30 | impl StackValues for HNil { 31 | fn pop_stack(_: &mut Vec) -> Option { 32 | Some(HNil) 33 | } 34 | fn push_stack(self, _: &mut Vec) {} 35 | } 36 | 37 | impl StackValues for HCons { 38 | fn pop_stack(stack: &mut Vec) -> Option { 39 | let tail = T::pop_stack(stack)?; 40 | let head = H::pop_stack(stack)?; 41 | Some(tail.prepend(head)) 42 | } 43 | fn push_stack(self, stack: &mut Vec) { 44 | self.head.push_stack(stack); 45 | self.tail.push_stack(stack); 46 | } 47 | } 48 | 49 | #[derive(Debug, Clone)] 50 | pub enum FrameLevelInstr { 51 | Label(Label, /* 前から */ Vec), 52 | Br(LabelIdx), 53 | LabelEnd, 54 | Invoke(FuncAddr), 55 | Return, 56 | } 57 | 58 | #[derive(Debug, Clone)] 59 | pub enum ModuleLevelInstr { 60 | Invoke(FuncAddr), 61 | Return, 62 | } 63 | 64 | #[derive(Debug, Clone)] 65 | pub enum AdminInstr { 66 | Instr(Instr), 67 | Invoke(FuncAddr), 68 | Label(Label, Vec), 69 | Br(LabelIdx), 70 | Return, 71 | } 72 | 73 | #[derive(Debug, Clone)] 74 | pub struct Frame { 75 | pub module: Weak, 76 | pub locals: Vec, 77 | pub n: usize, 78 | } 79 | 80 | #[derive(Debug, Clone, PartialEq)] 81 | pub struct Label { 82 | // 前から実行 83 | pub instrs: Vec, 84 | pub n: usize, 85 | } 86 | 87 | #[derive(Debug, Clone)] 88 | pub struct FrameStack { 89 | pub frame: Frame, 90 | // not empty 91 | // stack[0]の継続は空 92 | pub stack: Vec, 93 | } 94 | 95 | impl FrameStack { 96 | pub fn step(&mut self) -> Result, WasmError> { 97 | let cur_lavel = self.stack.last_mut().unwrap(); 98 | Ok(if let Some(instr) = cur_lavel.step(&mut self.frame)? { 99 | match instr { 100 | FrameLevelInstr::Invoke(idx) => Some(ModuleLevelInstr::Invoke(idx)), 101 | FrameLevelInstr::Return => Some(ModuleLevelInstr::Return), 102 | FrameLevelInstr::Br(idx) => { 103 | let mut add_stack = self.stack.last().unwrap().stack.clone(); 104 | let idx = idx.to_idx(); 105 | for _ in 0..idx { 106 | self.stack.pop().unwrap(); 107 | } 108 | 109 | let k_label = self.stack.pop().unwrap().label; 110 | let mut k = k_label 111 | .instrs 112 | .clone() 113 | .into_iter() 114 | .map(AdminInstr::Instr) 115 | .rev() 116 | .collect::>(); 117 | 118 | if let Some(last_label) = self.stack.last_mut() { 119 | last_label.instrs.append(&mut k); 120 | last_label 121 | .stack 122 | .append(&mut pop_n(&mut add_stack, k_label.n)); 123 | None 124 | } else { 125 | self.stack.push(LabelStack { 126 | label: Label { 127 | instrs: vec![], 128 | n: 0, /* dummy */ 129 | }, 130 | instrs: vec![], 131 | stack: add_stack, 132 | }); 133 | Some(ModuleLevelInstr::Return) 134 | } 135 | } 136 | FrameLevelInstr::Label(label, instrs) => { 137 | self.stack.push(LabelStack { 138 | label, 139 | instrs: instrs.into_iter().map(AdminInstr::Instr).rev().collect(), 140 | stack: vec![], 141 | }); 142 | None 143 | } 144 | FrameLevelInstr::LabelEnd => { 145 | let mut cur_lavel = self.stack.pop().unwrap(); 146 | if let Some(last_label) = self.stack.last_mut() { 147 | last_label.stack.append(&mut cur_lavel.stack); 148 | None 149 | } else { 150 | self.stack.push(cur_lavel); 151 | Some(ModuleLevelInstr::Return) 152 | } 153 | } 154 | } 155 | } else { 156 | None 157 | }) 158 | } 159 | } 160 | 161 | #[derive(Debug, Clone)] 162 | pub struct LabelStack { 163 | pub label: Label, 164 | // 後ろから実行 165 | pub instrs: Vec, 166 | pub stack: Vec, 167 | } 168 | 169 | impl LabelStack { 170 | fn run_ok(&mut self, f: impl FnOnce(I) -> O) -> () 171 | where 172 | I: Generic, 173 | I::Repr: StackValues, 174 | O: Generic, 175 | O::Repr: StackValues, 176 | { 177 | self.run(|i| Ok(f(i))).unwrap(); 178 | } 179 | 180 | fn pop_values(&mut self) -> T 181 | where 182 | T: Generic, 183 | T::Repr: StackValues, 184 | { 185 | from_generic(T::Repr::pop_stack(&mut self.stack).unwrap()) 186 | } 187 | 188 | fn push_values(&mut self, x: T) 189 | where 190 | T: Generic, 191 | T::Repr: StackValues, 192 | { 193 | into_generic(x).push_stack(&mut self.stack) 194 | } 195 | 196 | fn run(&mut self, f: impl FnOnce(I) -> Result) -> Result<(), WasmError> 197 | where 198 | I: Generic, 199 | I::Repr: StackValues, 200 | O: Generic, 201 | O::Repr: StackValues, 202 | { 203 | let input = self.pop_values::(); 204 | let output = f(input)?; 205 | self.push_values(output); 206 | Ok(()) 207 | } 208 | 209 | fn run_const(&mut self, f: impl FnOnce() -> T) { 210 | self.run_ok(|(): ()| -> (T,) { (f(),) }) 211 | } 212 | 213 | fn run_unop( 214 | &mut self, 215 | f: impl FnOnce(T) -> Result, 216 | ) -> Result<(), WasmError> { 217 | self.run(|(x,): (T,)| -> Result<(T,), _> { Ok((f(x)?,)) }) 218 | } 219 | 220 | fn run_binop( 221 | &mut self, 222 | f: impl FnOnce(T, T) -> Result, 223 | ) -> Result<(), WasmError> { 224 | self.run(|(a, b): (T, T)| -> Result<(T,), _> { Ok((f(a, b)?,)) }) 225 | } 226 | 227 | fn run_testop(&mut self, f: impl FnOnce(T) -> bool) { 228 | self.run_ok(|(x,): (T,)| -> (bool,) { (f(x),) }) 229 | } 230 | 231 | fn run_reop(&mut self, f: impl FnOnce(T, T) -> bool) { 232 | self.run_ok(|(x, y): (T, T)| -> (bool,) { (f(x, y),) }) 233 | } 234 | 235 | fn run_cvtop( 236 | &mut self, 237 | f: impl FnOnce(T) -> Result, 238 | ) -> Result<(), WasmError> { 239 | self.run(|(x,): (T,)| -> Result<(R,), _> { Ok((f(x)?,)) }) 240 | } 241 | 242 | fn step(&mut self, frame: &mut Frame) -> Result, WasmError> { 243 | Ok(match self.instrs.pop() { 244 | Some(instr) => match instr { 245 | AdminInstr::Instr(instr) => { 246 | match instr { 247 | Instr::I32Const(x) => { 248 | self.run_const(|| -> i32 { x }); 249 | } 250 | Instr::I64Const(x) => { 251 | self.run_const(|| -> i64 { x }); 252 | } 253 | Instr::F32Const(x) => { 254 | self.run_const(|| -> f32 { x }); 255 | } 256 | Instr::F64Const(x) => { 257 | self.run_const(|| -> f64 { x }); 258 | } 259 | Instr::I32Clz => { 260 | self.run_unop(|x: i32| -> Result { 261 | Ok(x.leading_zeros() as i32) 262 | })?; 263 | } 264 | Instr::I32Ctz => { 265 | self.run_unop(|x: i32| -> Result { 266 | Ok(x.trailing_zeros() as i32) 267 | })?; 268 | } 269 | Instr::I32Popcnt => { 270 | self.run_unop(|x: i32| -> Result { 271 | Ok(x.count_ones() as i32) 272 | })?; 273 | } 274 | Instr::I64Clz => { 275 | self.run_unop(|x: i64| -> Result { 276 | Ok(x.leading_zeros() as i64) 277 | })?; 278 | } 279 | Instr::I64Ctz => { 280 | self.run_unop(|x: i64| -> Result { 281 | Ok(x.trailing_zeros() as i64) 282 | })?; 283 | } 284 | Instr::I64Popcnt => { 285 | self.run_unop(|x: i64| -> Result { 286 | Ok(x.count_ones() as i64) 287 | })?; 288 | } 289 | Instr::F32Abs => { 290 | self.run_unop(|x: f32| -> Result { Ok(x.abs()) })?; 291 | } 292 | Instr::F32Neg => { 293 | self.run_unop(|x: f32| -> Result { Ok(-x) })?; 294 | } 295 | Instr::F32Sqrt => { 296 | self.run_unop(|x: f32| -> Result { Ok(x.sqrt()) })?; 297 | } 298 | Instr::F32Ceil => { 299 | self.run_unop(|x: f32| -> Result { Ok(x.ceil()) })?; 300 | } 301 | Instr::F32Floor => { 302 | self.run_unop(|x: f32| -> Result { Ok(x.floor()) })?; 303 | } 304 | Instr::F32Trunc => { 305 | self.run_unop(|x: f32| -> Result { Ok(x.trunc()) })?; 306 | } 307 | Instr::F32Nearest => { 308 | self.run_unop(|x: f32| -> Result { 309 | let x_mod2 = x % 2.0; 310 | Ok(if x_mod2 == 0.5 { 311 | x.floor() 312 | } else if x_mod2 == -0.5 { 313 | x.ceil() 314 | } else { 315 | x.round() 316 | }) 317 | })?; 318 | } 319 | Instr::F64Abs => { 320 | self.run_unop(|x: f64| -> Result { Ok(x.abs()) })?; 321 | } 322 | Instr::F64Neg => { 323 | self.run_unop(|x: f64| -> Result { Ok(-x) })?; 324 | } 325 | Instr::F64Sqrt => { 326 | self.run_unop(|x: f64| -> Result { Ok(x.sqrt()) })?; 327 | } 328 | Instr::F64Ceil => { 329 | self.run_unop(|x: f64| -> Result { Ok(x.ceil()) })?; 330 | } 331 | Instr::F64Floor => { 332 | self.run_unop(|x: f64| -> Result { Ok(x.floor()) })?; 333 | } 334 | Instr::F64Trunc => { 335 | self.run_unop(|x: f64| -> Result { Ok(x.trunc()) })?; 336 | } 337 | Instr::F64Nearest => { 338 | self.run_unop(|x: f64| -> Result { 339 | let x_mod2 = x % 2.0; 340 | Ok(if x_mod2 == 0.5 { 341 | x.floor() 342 | } else if x_mod2 == -0.5 { 343 | x.ceil() 344 | } else { 345 | x.round() 346 | }) 347 | })?; 348 | } 349 | Instr::I32Add => { 350 | self.run_binop(|x: i32, y: i32| -> Result { 351 | Ok(x.overflowing_add(y).0) 352 | })?; 353 | } 354 | Instr::I32Sub => { 355 | self.run_binop(|x: i32, y: i32| -> Result { 356 | Ok(x.overflowing_sub(y).0) 357 | })?; 358 | } 359 | Instr::I32Mul => { 360 | self.run_binop(|x: i32, y: i32| -> Result { 361 | Ok(x.overflowing_mul(y).0) 362 | })?; 363 | } 364 | Instr::I32DivS => { 365 | self.run_binop(|x: i32, y: i32| -> Result { 366 | if y == 0 { 367 | return Err(WasmError::RuntimeError); 368 | } 369 | Ok(x.checked_div(y).ok_or_else(|| WasmError::RuntimeError)?) 370 | })?; 371 | } 372 | Instr::I32DivU => { 373 | self.run_binop(|x: u32, y: u32| -> Result { 374 | if y == 0 { 375 | return Err(WasmError::RuntimeError); 376 | } 377 | Ok(x.checked_div(y).ok_or_else(|| WasmError::RuntimeError)?) 378 | })?; 379 | } 380 | Instr::I32RemS => { 381 | self.run_binop(|x: i32, y: i32| -> Result { 382 | if y == 0 { 383 | return Err(WasmError::RuntimeError); 384 | } 385 | Ok(x.overflowing_rem(y).0) 386 | })?; 387 | } 388 | Instr::I32RemU => { 389 | self.run_binop(|x: u32, y: u32| -> Result { 390 | if y == 0 { 391 | return Err(WasmError::RuntimeError); 392 | } 393 | Ok(x.overflowing_rem(y).0) 394 | })?; 395 | } 396 | Instr::I32And => { 397 | self.run_binop(|x: i32, y: i32| -> Result { Ok(x & y) })?; 398 | } 399 | Instr::I32Or => { 400 | self.run_binop(|x: i32, y: i32| -> Result { Ok(x | y) })?; 401 | } 402 | Instr::I32Xor => { 403 | self.run_binop(|x: i32, y: i32| -> Result { Ok(x ^ y) })?; 404 | } 405 | Instr::I32ShL => { 406 | self.run_binop(|x: i32, y: i32| -> Result { 407 | Ok(x.overflowing_shl(y as u32).0) 408 | })?; 409 | } 410 | Instr::I32ShrS => { 411 | self.run_binop(|x: i32, y: i32| -> Result { 412 | Ok(x.overflowing_shr(y as u32).0) 413 | })?; 414 | } 415 | Instr::I32ShrU => { 416 | self.run_binop(|x: u32, y: u32| -> Result { 417 | Ok(x.overflowing_shr(y).0) 418 | })?; 419 | } 420 | Instr::I32Rotl => { 421 | self.run_binop(|x: i32, y: i32| -> Result { 422 | Ok(x.rotate_left(y as u32)) 423 | })?; 424 | } 425 | Instr::I32Rotr => { 426 | self.run_binop(|x: i32, y: i32| -> Result { 427 | Ok(x.rotate_right(y as u32)) 428 | })?; 429 | } 430 | Instr::I64Add => { 431 | self.run_binop(|x: i64, y: i64| -> Result { 432 | Ok(x.overflowing_add(y).0) 433 | })?; 434 | } 435 | Instr::I64Sub => { 436 | self.run_binop(|x: i64, y: i64| -> Result { 437 | Ok(x.overflowing_sub(y).0) 438 | })?; 439 | } 440 | Instr::I64Mul => { 441 | self.run_binop(|x: i64, y: i64| -> Result { 442 | Ok(x.overflowing_mul(y).0) 443 | })?; 444 | } 445 | Instr::I64DivS => { 446 | self.run_binop(|x: i64, y: i64| -> Result { 447 | if y == 0 { 448 | return Err(WasmError::RuntimeError); 449 | } 450 | Ok(x.checked_div(y).ok_or_else(|| WasmError::RuntimeError)?) 451 | })?; 452 | } 453 | Instr::I64DivU => { 454 | self.run_binop(|x: u64, y: u64| -> Result { 455 | if y == 0 { 456 | return Err(WasmError::RuntimeError); 457 | } 458 | Ok(x.checked_div(y).ok_or_else(|| WasmError::RuntimeError)?) 459 | })?; 460 | } 461 | Instr::I64RemS => { 462 | self.run_binop(|x: i64, y: i64| -> Result { 463 | if y == 0 { 464 | return Err(WasmError::RuntimeError); 465 | } 466 | Ok(x.overflowing_rem(y).0) 467 | })?; 468 | } 469 | Instr::I64RemU => { 470 | self.run_binop(|x: u64, y: u64| -> Result { 471 | if y == 0 { 472 | return Err(WasmError::RuntimeError); 473 | } 474 | Ok(x.overflowing_rem(y).0) 475 | })?; 476 | } 477 | Instr::I64And => { 478 | self.run_binop(|x: i64, y: i64| -> Result { Ok(x & y) })?; 479 | } 480 | Instr::I64Or => { 481 | self.run_binop(|x: i64, y: i64| -> Result { Ok(x | y) })?; 482 | } 483 | Instr::I64Xor => { 484 | self.run_binop(|x: i64, y: i64| -> Result { Ok(x ^ y) })?; 485 | } 486 | Instr::I64ShL => { 487 | self.run_binop(|x: i64, y: i64| -> Result { 488 | Ok(x.overflowing_shl(y as u32).0) 489 | })?; 490 | } 491 | Instr::I64ShrS => { 492 | self.run_binop(|x: i64, y: i64| -> Result { 493 | Ok(x.overflowing_shr(y as u32).0) 494 | })?; 495 | } 496 | Instr::I64ShrU => { 497 | self.run_binop(|x: u64, y: u64| -> Result { 498 | Ok(x.overflowing_shr(y as u32).0) 499 | })?; 500 | } 501 | Instr::I64Rotl => { 502 | self.run_binop(|x: i64, y: i64| -> Result { 503 | Ok(x.rotate_left(y as u32)) 504 | })?; 505 | } 506 | Instr::I64Rotr => { 507 | self.run_binop(|x: i64, y: i64| -> Result { 508 | Ok(x.rotate_right(y as u32)) 509 | })?; 510 | } 511 | Instr::F32Add => { 512 | self.run_binop(|x: f32, y: f32| -> Result { Ok(x + y) })?; 513 | } 514 | Instr::F32Sub => { 515 | self.run_binop(|x: f32, y: f32| -> Result { Ok(x - y) })?; 516 | } 517 | Instr::F32Mul => { 518 | self.run_binop(|x: f32, y: f32| -> Result { Ok(x * y) })?; 519 | } 520 | Instr::F32Div => { 521 | self.run_binop(|x: f32, y: f32| -> Result { Ok(x / y) })?; 522 | } 523 | Instr::F32Min => { 524 | self.run_binop(|x: f32, y: f32| -> Result { 525 | // 0.0, -0.0対策 526 | Ok(match (sign_f32(x), sign_f32(y)) { 527 | (Some(Sign::Positive), Some(Sign::Negative)) => y, 528 | (Some(Sign::Negative), Some(Sign::Positive)) => x, 529 | _ => x.min(y), 530 | }) 531 | })?; 532 | } 533 | Instr::F32Max => { 534 | self.run_binop(|x: f32, y: f32| -> Result { 535 | Ok(match (sign_f32(x), sign_f32(y)) { 536 | (Some(Sign::Positive), Some(Sign::Negative)) => x, 537 | (Some(Sign::Negative), Some(Sign::Positive)) => y, 538 | _ => x.max(y), 539 | }) 540 | })?; 541 | } 542 | Instr::F32CopySign => { 543 | self.run_binop(|x: f32, y: f32| -> Result { 544 | Ok(x.copysign(y)) 545 | })?; 546 | } 547 | Instr::F64Add => { 548 | self.run_binop(|x: f64, y: f64| -> Result { Ok(x + y) })?; 549 | } 550 | Instr::F64Sub => { 551 | self.run_binop(|x: f64, y: f64| -> Result { Ok(x - y) })?; 552 | } 553 | Instr::F64Mul => { 554 | self.run_binop(|x: f64, y: f64| -> Result { Ok(x * y) })?; 555 | } 556 | Instr::F64Div => { 557 | self.run_binop(|x: f64, y: f64| -> Result { Ok(x / y) })?; 558 | } 559 | Instr::F64Min => { 560 | self.run_binop(|x: f64, y: f64| -> Result { 561 | Ok(match (sign_f64(x), sign_f64(y)) { 562 | (Some(Sign::Positive), Some(Sign::Negative)) => y, 563 | (Some(Sign::Negative), Some(Sign::Positive)) => x, 564 | _ => x.min(y), 565 | }) 566 | })?; 567 | } 568 | Instr::F64Max => { 569 | self.run_binop(|x: f64, y: f64| -> Result { 570 | Ok(match (sign_f64(x), sign_f64(y)) { 571 | (Some(Sign::Positive), Some(Sign::Negative)) => x, 572 | (Some(Sign::Negative), Some(Sign::Positive)) => y, 573 | _ => x.max(y), 574 | }) 575 | })?; 576 | } 577 | Instr::F64CopySign => { 578 | self.run_binop(|x: f64, y: f64| -> Result { 579 | Ok(x.copysign(y)) 580 | })?; 581 | } 582 | Instr::I32Eqz => { 583 | self.run_testop(|x: i32| -> bool { x == 0 }); 584 | } 585 | Instr::I64Eqz => { 586 | self.run_testop(|x: i64| -> bool { x == 0 }); 587 | } 588 | Instr::I32Eq => { 589 | self.run_reop(|x: i32, y: i32| -> bool { x == y }); 590 | } 591 | Instr::I32Ne => { 592 | self.run_reop(|x: i32, y: i32| -> bool { x != y }); 593 | } 594 | Instr::I32LtS => { 595 | self.run_reop(|x: i32, y: i32| -> bool { x < y }); 596 | } 597 | Instr::I32LtU => { 598 | self.run_reop(|x: u32, y: u32| -> bool { x < y }); 599 | } 600 | Instr::I32GtS => { 601 | self.run_reop(|x: i32, y: i32| -> bool { x > y }); 602 | } 603 | Instr::I32GtU => { 604 | self.run_reop(|x: u32, y: u32| -> bool { x > y }); 605 | } 606 | Instr::I32LeS => { 607 | self.run_reop(|x: i32, y: i32| -> bool { x <= y }); 608 | } 609 | Instr::I32LeU => { 610 | self.run_reop(|x: u32, y: u32| -> bool { x <= y }); 611 | } 612 | Instr::I32GeS => { 613 | self.run_reop(|x: i32, y: i32| -> bool { x >= y }); 614 | } 615 | Instr::I32GeU => { 616 | self.run_reop(|x: u32, y: u32| -> bool { x >= y }); 617 | } 618 | Instr::I64Eq => { 619 | self.run_reop(|x: i64, y: i64| -> bool { x == y }); 620 | } 621 | Instr::I64Ne => { 622 | self.run_reop(|x: i64, y: i64| -> bool { x != y }); 623 | } 624 | Instr::I64LtS => { 625 | self.run_reop(|x: i64, y: i64| -> bool { x < y }); 626 | } 627 | Instr::I64LtU => { 628 | self.run_reop(|x: u64, y: u64| -> bool { x < y }); 629 | } 630 | Instr::I64GtS => { 631 | self.run_reop(|x: i64, y: i64| -> bool { x > y }); 632 | } 633 | Instr::I64GtU => { 634 | self.run_reop(|x: u64, y: u64| -> bool { x > y }); 635 | } 636 | Instr::I64LeS => { 637 | self.run_reop(|x: i64, y: i64| -> bool { x <= y }); 638 | } 639 | Instr::I64LeU => { 640 | self.run_reop(|x: u64, y: u64| -> bool { x <= y }); 641 | } 642 | Instr::I64GeS => { 643 | self.run_reop(|x: i64, y: i64| -> bool { x >= y }); 644 | } 645 | Instr::I64GeU => { 646 | self.run_reop(|x: u64, y: u64| -> bool { x >= y }); 647 | } 648 | Instr::F32Eq => { 649 | self.run_reop(|x: f32, y: f32| -> bool { x == y }); 650 | } 651 | Instr::F32Ne => { 652 | self.run_reop(|x: f32, y: f32| -> bool { x != y }); 653 | } 654 | Instr::F32Lt => { 655 | self.run_reop(|x: f32, y: f32| -> bool { x < y }); 656 | } 657 | Instr::F32Gt => { 658 | self.run_reop(|x: f32, y: f32| -> bool { x > y }); 659 | } 660 | Instr::F32Le => { 661 | self.run_reop(|x: f32, y: f32| -> bool { x <= y }); 662 | } 663 | Instr::F32Ge => { 664 | self.run_reop(|x: f32, y: f32| -> bool { x >= y }); 665 | } 666 | Instr::F64Eq => { 667 | self.run_reop(|x: f64, y: f64| -> bool { x == y }); 668 | } 669 | Instr::F64Ne => { 670 | self.run_reop(|x: f64, y: f64| -> bool { x != y }); 671 | } 672 | Instr::F64Lt => { 673 | self.run_reop(|x: f64, y: f64| -> bool { x < y }); 674 | } 675 | Instr::F64Gt => { 676 | self.run_reop(|x: f64, y: f64| -> bool { x > y }); 677 | } 678 | Instr::F64Le => { 679 | self.run_reop(|x: f64, y: f64| -> bool { x <= y }); 680 | } 681 | Instr::F64Ge => { 682 | self.run_reop(|x: f64, y: f64| -> bool { x >= y }); 683 | } 684 | Instr::I32WrapI64 => { 685 | self.run_cvtop(|x: i64| -> Result { Ok(x as i32) })?; 686 | } 687 | Instr::I64ExtendI32S => { 688 | self.run_cvtop(|x: i32| -> Result { Ok(x as i64) })?; 689 | } 690 | Instr::I64ExtendI32U => { 691 | self.run_cvtop(|x: u32| -> Result { Ok(x as i64) })?; 692 | } 693 | Instr::I32TruncF32S => { 694 | self.run_cvtop(|x: f32| -> Result { 695 | Ok(::from(x) 696 | .ok_or_else(|| WasmError::RuntimeError)?) 697 | })?; 698 | } 699 | Instr::I32TruncF32U => { 700 | self.run_cvtop(|x: f32| -> Result { 701 | Ok(::from(x) 702 | .ok_or_else(|| WasmError::RuntimeError)?) 703 | })?; 704 | } 705 | Instr::I32TruncF64S => { 706 | self.run_cvtop(|x: f64| -> Result { 707 | Ok(::from(x) 708 | .ok_or_else(|| WasmError::RuntimeError)?) 709 | })?; 710 | } 711 | Instr::I32TruncF64U => { 712 | self.run_cvtop(|x: f64| -> Result { 713 | Ok(::from(x) 714 | .ok_or_else(|| WasmError::RuntimeError)?) 715 | })?; 716 | } 717 | Instr::I64TruncF32S => { 718 | self.run_cvtop(|x: f32| -> Result { 719 | Ok(::from(x) 720 | .ok_or_else(|| WasmError::RuntimeError)?) 721 | })?; 722 | } 723 | Instr::I64TruncF32U => { 724 | self.run_cvtop(|x: f32| -> Result { 725 | Ok(::from(x) 726 | .ok_or_else(|| WasmError::RuntimeError)?) 727 | })?; 728 | } 729 | Instr::I64TruncF64S => { 730 | self.run_cvtop(|x: f64| -> Result { 731 | Ok(::from(x) 732 | .ok_or_else(|| WasmError::RuntimeError)?) 733 | })?; 734 | } 735 | Instr::I64TruncF64U => { 736 | self.run_cvtop(|x: f64| -> Result { 737 | Ok(::from(x) 738 | .ok_or_else(|| WasmError::RuntimeError)?) 739 | })?; 740 | } 741 | Instr::F32DemoteF64 => { 742 | self.run_cvtop(|x: f64| -> Result { Ok(x as f32) })?; 743 | } 744 | Instr::F64PromoteF32 => { 745 | self.run_cvtop(|x: f32| -> Result { Ok(x as f64) })?; 746 | } 747 | Instr::F32ConvertI32S => { 748 | self.run_cvtop(|x: i32| -> Result { Ok(x as f32) })?; 749 | } 750 | Instr::F32ConvertI32U => { 751 | self.run_cvtop(|x: u32| -> Result { Ok(x as f32) })?; 752 | } 753 | Instr::F32ConvertI64S => { 754 | self.run_cvtop(|x: i64| -> Result { Ok(x as f32) })?; 755 | } 756 | Instr::F32ConvertI64U => { 757 | self.run_cvtop(|x: u64| -> Result { Ok(x as f32) })?; 758 | } 759 | Instr::F64ConvertI32S => { 760 | self.run_cvtop(|x: i32| -> Result { Ok(x as f64) })?; 761 | } 762 | Instr::F64ConvertI32U => { 763 | self.run_cvtop(|x: u32| -> Result { Ok(x as f64) })?; 764 | } 765 | Instr::F64ConvertI64S => { 766 | self.run_cvtop(|x: i64| -> Result { Ok(x as f64) })?; 767 | } 768 | Instr::F64ConvertI64U => { 769 | self.run_cvtop(|x: u64| -> Result { Ok(x as f64) })?; 770 | } 771 | Instr::I32ReinterpretF32 => { 772 | self.run_cvtop(|x: f32| -> Result { 773 | let mut wtr = vec![]; 774 | wtr.write_f32::(x).unwrap(); 775 | let mut rdr = Cursor::new(wtr); 776 | Ok(rdr.read_i32::().unwrap()) 777 | })?; 778 | } 779 | Instr::I64ReinterpretF64 => { 780 | self.run_cvtop(|x: f64| -> Result { 781 | let mut wtr = vec![]; 782 | wtr.write_f64::(x).unwrap(); 783 | let mut rdr = Cursor::new(wtr); 784 | Ok(rdr.read_i64::().unwrap()) 785 | })?; 786 | } 787 | Instr::F32ReinterpretI32 => { 788 | self.run_cvtop(|x: i32| -> Result { 789 | let mut wtr = vec![]; 790 | wtr.write_i32::(x).unwrap(); 791 | let mut rdr = Cursor::new(wtr); 792 | Ok(rdr.read_f32::().unwrap()) 793 | })?; 794 | } 795 | Instr::F64ReinterpretI64 => { 796 | self.run_cvtop(|x: i64| -> Result { 797 | let mut wtr = vec![]; 798 | wtr.write_i64::(x).unwrap(); 799 | let mut rdr = Cursor::new(wtr); 800 | Ok(rdr.read_f64::().unwrap()) 801 | })?; 802 | } 803 | Instr::Drop => { 804 | self.run_ok(|(_,): (Val,)| -> () {}); 805 | } 806 | Instr::Select => { 807 | self.run_ok(|(x, y, c): (Val, Val, bool)| -> (Val,) { 808 | (if c { x } else { y },) 809 | }); 810 | } 811 | Instr::LocalGet(idx) => { 812 | self.run_ok(|(): ()| -> (Val,) { (frame.locals[idx.to_idx()],) }); 813 | } 814 | Instr::LocalSet(idx) => { 815 | self.run_ok(|(x,): (Val,)| -> () { 816 | frame.locals[idx.to_idx()] = x; 817 | () 818 | }); 819 | } 820 | Instr::LocalTee(idx) => { 821 | self.run_ok(|(x,): (Val,)| -> (Val,) { 822 | frame.locals[idx.to_idx()] = x; 823 | (x,) 824 | }); 825 | } 826 | Instr::GlobalGet(idx) => { 827 | let instance = frame.module.upgrade().unwrap(); 828 | 829 | self.run_ok(|(): ()| -> (Val,) { 830 | (instance.globals[idx.to_idx()].get(),) 831 | }); 832 | } 833 | Instr::GlobalSet(idx) => { 834 | let instance = frame.module.upgrade().unwrap(); 835 | 836 | self.run_ok(|(x,): (Val,)| -> () { 837 | instance.globals[idx.to_idx()].set(x).unwrap(); 838 | () 839 | }); 840 | } 841 | Instr::I32Load(m) => { 842 | let instance = frame.module.upgrade().unwrap(); 843 | self.run(|(ptr,): (i32,)| -> Result<(i32,), _> { 844 | Ok((instance.mem.as_ref().unwrap().read::(&m, ptr)?,)) 845 | })?; 846 | } 847 | Instr::I64Load(m) => { 848 | let instance = frame.module.upgrade().unwrap(); 849 | self.run(|(ptr,): (i32,)| -> Result<(i64,), _> { 850 | Ok((instance.mem.as_ref().unwrap().read::(&m, ptr)?,)) 851 | })?; 852 | } 853 | Instr::F32Load(m) => { 854 | let instance = frame.module.upgrade().unwrap(); 855 | self.run(|(ptr,): (i32,)| -> Result<(f32,), _> { 856 | Ok((instance.mem.as_ref().unwrap().read::(&m, ptr)?,)) 857 | })?; 858 | } 859 | Instr::F64Load(m) => { 860 | let instance = frame.module.upgrade().unwrap(); 861 | self.run(|(ptr,): (i32,)| -> Result<(f64,), _> { 862 | Ok((instance.mem.as_ref().unwrap().read::(&m, ptr)?,)) 863 | })?; 864 | } 865 | Instr::I32Store(m) => { 866 | let instance = frame.module.upgrade().unwrap(); 867 | self.run(|(ptr, x): (i32, i32)| -> Result<(), _> { 868 | instance.mem.as_ref().unwrap().write::(&m, ptr, x)?; 869 | Ok(()) 870 | })?; 871 | } 872 | Instr::I64Store(m) => { 873 | let instance = frame.module.upgrade().unwrap(); 874 | self.run(|(ptr, x): (i32, i64)| -> Result<(), _> { 875 | instance.mem.as_ref().unwrap().write::(&m, ptr, x)?; 876 | Ok(()) 877 | })?; 878 | } 879 | Instr::F32Store(m) => { 880 | let instance = frame.module.upgrade().unwrap(); 881 | self.run(|(ptr, x): (i32, f32)| -> Result<(), _> { 882 | instance.mem.as_ref().unwrap().write::(&m, ptr, x)?; 883 | Ok(()) 884 | })?; 885 | } 886 | Instr::F64Store(m) => { 887 | let instance = frame.module.upgrade().unwrap(); 888 | self.run(|(ptr, x): (i32, f64)| -> Result<(), _> { 889 | instance.mem.as_ref().unwrap().write::(&m, ptr, x)?; 890 | Ok(()) 891 | })?; 892 | } 893 | Instr::I32Load8S(m) => { 894 | let instance = frame.module.upgrade().unwrap(); 895 | self.run(|(ptr,): (i32,)| -> Result<(i32,), _> { 896 | Ok((instance.mem.as_ref().unwrap().read::(&m, ptr)? as i32,)) 897 | })?; 898 | } 899 | Instr::I32Load8U(m) => { 900 | let instance = frame.module.upgrade().unwrap(); 901 | self.run(|(ptr,): (i32,)| -> Result<(i32,), _> { 902 | Ok((instance.mem.as_ref().unwrap().read::(&m, ptr)? as i32,)) 903 | })?; 904 | } 905 | Instr::I64Load8S(m) => { 906 | let instance = frame.module.upgrade().unwrap(); 907 | self.run(|(ptr,): (i32,)| -> Result<(i64,), _> { 908 | Ok((instance.mem.as_ref().unwrap().read::(&m, ptr)? as i64,)) 909 | })?; 910 | } 911 | Instr::I64Load8U(m) => { 912 | let instance = frame.module.upgrade().unwrap(); 913 | self.run(|(ptr,): (i32,)| -> Result<(i64,), _> { 914 | Ok((instance.mem.as_ref().unwrap().read::(&m, ptr)? as i64,)) 915 | })?; 916 | } 917 | Instr::I32Load16S(m) => { 918 | let instance = frame.module.upgrade().unwrap(); 919 | self.run(|(ptr,): (i32,)| -> Result<(i32,), _> { 920 | Ok((instance.mem.as_ref().unwrap().read::(&m, ptr)? as i32,)) 921 | })?; 922 | } 923 | Instr::I32Load16U(m) => { 924 | let instance = frame.module.upgrade().unwrap(); 925 | self.run(|(ptr,): (i32,)| -> Result<(i32,), _> { 926 | Ok((instance.mem.as_ref().unwrap().read::(&m, ptr)? as i32,)) 927 | })?; 928 | } 929 | Instr::I64Load16S(m) => { 930 | let instance = frame.module.upgrade().unwrap(); 931 | self.run(|(ptr,): (i32,)| -> Result<(i64,), _> { 932 | Ok((instance.mem.as_ref().unwrap().read::(&m, ptr)? as i64,)) 933 | })?; 934 | } 935 | Instr::I64Load16U(m) => { 936 | let instance = frame.module.upgrade().unwrap(); 937 | self.run(|(ptr,): (i32,)| -> Result<(i64,), _> { 938 | Ok((instance.mem.as_ref().unwrap().read::(&m, ptr)? as i64,)) 939 | })?; 940 | } 941 | Instr::I64Load32S(m) => { 942 | let instance = frame.module.upgrade().unwrap(); 943 | self.run(|(ptr,): (i32,)| -> Result<(i64,), _> { 944 | Ok((instance.mem.as_ref().unwrap().read::(&m, ptr)? as i64,)) 945 | })?; 946 | } 947 | Instr::I64Load32U(m) => { 948 | let instance = frame.module.upgrade().unwrap(); 949 | self.run(|(ptr,): (i32,)| -> Result<(i64,), _> { 950 | Ok((instance.mem.as_ref().unwrap().read::(&m, ptr)? as i64,)) 951 | })?; 952 | } 953 | Instr::I32Store8(m) => { 954 | let instance = frame.module.upgrade().unwrap(); 955 | self.run(|(ptr, x): (i32, i32)| -> Result<(), _> { 956 | instance 957 | .mem 958 | .as_ref() 959 | .unwrap() 960 | .write::(&m, ptr, x as i8)?; 961 | Ok(()) 962 | })?; 963 | } 964 | Instr::I64Store8(m) => { 965 | let instance = frame.module.upgrade().unwrap(); 966 | self.run(|(ptr, x): (i32, i64)| -> Result<(), _> { 967 | instance 968 | .mem 969 | .as_ref() 970 | .unwrap() 971 | .write::(&m, ptr, x as i8)?; 972 | Ok(()) 973 | })?; 974 | } 975 | Instr::I32Store16(m) => { 976 | let instance = frame.module.upgrade().unwrap(); 977 | self.run(|(ptr, x): (i32, i32)| -> Result<(), _> { 978 | instance 979 | .mem 980 | .as_ref() 981 | .unwrap() 982 | .write::(&m, ptr, x as i16)?; 983 | Ok(()) 984 | })?; 985 | } 986 | Instr::I64Store16(m) => { 987 | let instance = frame.module.upgrade().unwrap(); 988 | self.run(|(ptr, x): (i32, i64)| -> Result<(), _> { 989 | instance 990 | .mem 991 | .as_ref() 992 | .unwrap() 993 | .write::(&m, ptr, x as i16)?; 994 | Ok(()) 995 | })?; 996 | } 997 | Instr::I64Store32(m) => { 998 | let instance = frame.module.upgrade().unwrap(); 999 | self.run(|(ptr, x): (i32, i64)| -> Result<(), _> { 1000 | instance 1001 | .mem 1002 | .as_ref() 1003 | .unwrap() 1004 | .write::(&m, ptr, x as i32)?; 1005 | Ok(()) 1006 | })?; 1007 | } 1008 | Instr::MemorySize => { 1009 | let instance = frame.module.upgrade().unwrap(); 1010 | self.run_ok(|(): ()| -> (i32,) { 1011 | (instance.mem.as_ref().unwrap().page_size(),) 1012 | }); 1013 | } 1014 | Instr::MemoryGrow => { 1015 | let instance = frame.module.upgrade().unwrap(); 1016 | self.run_ok(|(x,): (i32,)| -> (i32,) { 1017 | (instance.mem.as_ref().unwrap().grow(x),) 1018 | }); 1019 | } 1020 | Instr::Nop => {} 1021 | Instr::Unreachable => return Err(WasmError::RuntimeError), 1022 | Instr::Block(rt, is) => { 1023 | self.instrs.push(AdminInstr::Label( 1024 | Label { 1025 | instrs: vec![], 1026 | n: rt.0.iter().count(), 1027 | }, 1028 | is, 1029 | )); 1030 | } 1031 | Instr::Loop(rt, is) => { 1032 | self.instrs.push(AdminInstr::Label( 1033 | Label { 1034 | instrs: vec![Instr::Loop(rt, is.clone())], 1035 | n: 0, 1036 | }, 1037 | is, 1038 | )); 1039 | } 1040 | Instr::If(rt, is1, is2) => { 1041 | let (x,) = self.pop_values::<(bool,)>(); 1042 | self.instrs.push(AdminInstr::Label( 1043 | Label { 1044 | instrs: vec![], 1045 | n: rt.0.iter().count(), 1046 | }, 1047 | if x { is1 } else { is2 }, 1048 | )); 1049 | } 1050 | Instr::Br(l) => self.instrs.push(AdminInstr::Br(l)), 1051 | Instr::BrIf(l) => { 1052 | let (x,) = self.pop_values::<(bool,)>(); 1053 | if x { 1054 | self.instrs.push(AdminInstr::Br(l)); 1055 | } 1056 | } 1057 | Instr::BrTable(ls, l) => { 1058 | let (i,) = self.pop_values::<(i32,)>(); 1059 | if (i as usize) < ls.len() { 1060 | self.instrs.push(AdminInstr::Br(ls[i as usize])); 1061 | } else { 1062 | self.instrs.push(AdminInstr::Br(l)); 1063 | } 1064 | } 1065 | Instr::Return => { 1066 | self.instrs.push(AdminInstr::Return); 1067 | } 1068 | Instr::Call(idx) => { 1069 | let instance = frame.module.upgrade().unwrap(); 1070 | self.instrs 1071 | .push(AdminInstr::Invoke(instance.funcs.get_idx(idx).clone())); 1072 | } 1073 | Instr::CallIndirect(t) => { 1074 | let instance = frame.module.upgrade().unwrap(); 1075 | let (i,) = self.pop_values::<(i32,)>(); 1076 | let func = { 1077 | if let Some(Some(func)) = instance.table.as_ref().unwrap().get(i) { 1078 | func 1079 | } else { 1080 | return Err(WasmError::RuntimeError); 1081 | } 1082 | }; 1083 | if &func.type_() != instance.types.get_idx(t) { 1084 | return Err(WasmError::RuntimeError); 1085 | } 1086 | self.instrs.push(AdminInstr::Invoke(func.clone())); 1087 | } 1088 | } 1089 | None 1090 | } 1091 | AdminInstr::Invoke(x) => Some(FrameLevelInstr::Invoke(x)), 1092 | AdminInstr::Label(l, is) => Some(FrameLevelInstr::Label(l, is)), 1093 | AdminInstr::Br(l) => Some(FrameLevelInstr::Br(l)), 1094 | AdminInstr::Return => Some(FrameLevelInstr::Return), 1095 | }, 1096 | None => Some(FrameLevelInstr::LabelEnd), 1097 | }) 1098 | } 1099 | } 1100 | 1101 | #[derive(Debug)] 1102 | pub struct Stack { 1103 | // not empty 1104 | pub stack: Vec, 1105 | } 1106 | 1107 | impl Stack { 1108 | pub fn step(&mut self) -> Result<(), WasmError> { 1109 | let cur_frame = self.stack.last_mut().unwrap(); 1110 | if let Some(instr) = cur_frame.step()? { 1111 | let cur_label = cur_frame.stack.last_mut().unwrap(); 1112 | match instr { 1113 | ModuleLevelInstr::Invoke(func) => match &*func.borrow() { 1114 | FuncInst::RuntimeFunc { 1115 | type_, 1116 | code, 1117 | module, 1118 | } => { 1119 | let fs = FrameStack { 1120 | frame: Frame { 1121 | locals: { 1122 | let mut locals = Vec::new(); 1123 | locals.append(&mut pop_n( 1124 | &mut cur_label.stack, 1125 | type_.params().len(), 1126 | )); 1127 | locals.append( 1128 | &mut code 1129 | .locals 1130 | .iter() 1131 | .map(|vt| match vt { 1132 | ValType::I32 => Val::I32(0), 1133 | ValType::I64 => Val::I64(0), 1134 | ValType::F32 => Val::F32(0.0), 1135 | ValType::F64 => Val::F64(0.0), 1136 | }) 1137 | .collect(), 1138 | ); 1139 | 1140 | locals 1141 | }, 1142 | module: module.clone(), 1143 | n: type_.ret().iter().count(), 1144 | }, 1145 | stack: vec![LabelStack { 1146 | stack: vec![], 1147 | label: Label { 1148 | instrs: vec![], 1149 | n: type_.ret().iter().count(), 1150 | }, 1151 | instrs: code 1152 | .body 1153 | .0 1154 | .clone() 1155 | .into_iter() 1156 | .map(AdminInstr::Instr) 1157 | .rev() 1158 | .collect(), 1159 | }], 1160 | }; 1161 | self.stack.push(fs); 1162 | } 1163 | FuncInst::HostFunc { type_, host_code } => { 1164 | let params = pop_n(&mut cur_label.stack, type_.params().len()); 1165 | if let Some(result) = host_code(params)? { 1166 | cur_label.stack.push(result); 1167 | } 1168 | } 1169 | }, 1170 | ModuleLevelInstr::Return => { 1171 | let ret = cur_label.stack.pop(); 1172 | if self.stack.pop().unwrap().frame.n != 0 { 1173 | self.stack 1174 | .last_mut() 1175 | .unwrap() 1176 | .stack 1177 | .last_mut() 1178 | .unwrap() 1179 | .stack 1180 | .push(ret.unwrap()); 1181 | } 1182 | } 1183 | } 1184 | } 1185 | Ok(()) 1186 | } 1187 | } 1188 | --------------------------------------------------------------------------------