summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorHenry Gressmann <mail@henrygressmann.de>2024-01-25 13:49:52 +0100
committerHenry Gressmann <mail@henrygressmann.de>2024-01-25 13:49:52 +0100
commit79463500a7ade3df7dc99454f5797beaf1d7eef9 (patch)
treefe6ef0899c070a82fd723a7b78eb0b50878f4fd1 /crates
parent00ac90357bbd256436846beceba67b38d4743bf6 (diff)
chore: refactor executor and improve documentation
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
Diffstat (limited to 'crates')
-rw-r--r--crates/parser/src/error.rs1
-rw-r--r--crates/tinywasm/src/error.rs26
-rw-r--r--crates/tinywasm/src/func.rs4
-rw-r--r--crates/tinywasm/src/imports.rs109
-rw-r--r--crates/tinywasm/src/instance.rs8
-rw-r--r--crates/tinywasm/src/lib.rs40
-rw-r--r--crates/tinywasm/src/runtime/interpreter/macros.rs (renamed from crates/tinywasm/src/runtime/executor/macros.rs)0
-rw-r--r--crates/tinywasm/src/runtime/interpreter/mod.rs (renamed from crates/tinywasm/src/runtime/executor/mod.rs)17
-rw-r--r--crates/tinywasm/src/runtime/interpreter/traits.rs (renamed from crates/tinywasm/src/runtime/executor/traits.rs)0
-rw-r--r--crates/tinywasm/src/runtime/mod.rs20
-rw-r--r--crates/tinywasm/src/runtime/stack/call_stack.rs7
-rw-r--r--crates/tinywasm/src/store.rs10
-rw-r--r--crates/tinywasm/tests/generated/mvp.csv1
13 files changed, 139 insertions, 104 deletions
diff --git a/crates/parser/src/error.rs b/crates/parser/src/error.rs
index 714535a..35bad28 100644
--- a/crates/parser/src/error.rs
+++ b/crates/parser/src/error.rs
@@ -4,6 +4,7 @@ use alloc::string::{String, ToString};
use wasmparser::Encoding;
#[derive(Debug)]
+/// Errors that can occur when parsing a WebAssembly module
pub enum ParseError {
InvalidType,
UnsupportedSection(String),
diff --git a/crates/tinywasm/src/error.rs b/crates/tinywasm/src/error.rs
index f9b41be..0344e82 100644
--- a/crates/tinywasm/src/error.rs
+++ b/crates/tinywasm/src/error.rs
@@ -3,24 +3,18 @@ use core::fmt::Display;
use tinywasm_types::FuncType;
#[cfg(feature = "parser")]
-use tinywasm_parser::ParseError;
+pub use tinywasm_parser::ParseError;
-/// A tinywasm error
+/// Errors that can occur for TinyWasm operations
#[derive(Debug)]
pub enum Error {
- #[cfg(feature = "parser")]
- /// A parsing error occurred
- ParseError(ParseError),
-
#[cfg(feature = "std")]
/// An I/O error occurred
Io(crate::std::io::Error),
- /// A WebAssembly feature is not supported
- UnsupportedFeature(String),
-
- /// An unknown error occurred
- Other(String),
+ #[cfg(feature = "parser")]
+ /// A parsing error occurred
+ ParseError(ParseError),
/// A WebAssembly trap occurred
Trap(Trap),
@@ -28,6 +22,12 @@ pub enum Error {
/// A linking error occurred
Linker(LinkingError),
+ /// A WebAssembly feature is not supported
+ UnsupportedFeature(String),
+
+ /// An unknown error occurred
+ Other(String),
+
/// A function did not return a value
FuncDidNotReturn,
@@ -48,7 +48,7 @@ pub enum Error {
}
#[derive(Debug)]
-/// A linking error
+/// Errors that can occur when linking a WebAssembly module
pub enum LinkingError {
/// An unknown import was encountered
UnknownImport {
@@ -210,5 +210,5 @@ impl From<tinywasm_parser::ParseError> for Error {
}
}
-/// A specialized [`Result`] type for tinywasm operations
+/// A wrapper around [`core::result::Result`] for tinywasm operations
pub type Result<T, E = Error> = crate::std::result::Result<T, E>;
diff --git a/crates/tinywasm/src/func.rs b/crates/tinywasm/src/func.rs
index 19d1325..7a29e18 100644
--- a/crates/tinywasm/src/func.rs
+++ b/crates/tinywasm/src/func.rs
@@ -89,7 +89,7 @@ impl FuncHandle {
#[derive(Debug)]
/// A typed function handle
-pub struct TypedFuncHandle<P, R> {
+pub struct FuncHandleTyped<P, R> {
/// The underlying function handle
pub func: FuncHandle,
pub(crate) marker: core::marker::PhantomData<(P, R)>,
@@ -105,7 +105,7 @@ pub trait FromWasmValueTuple {
Self: Sized;
}
-impl<P: IntoWasmValueTuple, R: FromWasmValueTuple> TypedFuncHandle<P, R> {
+impl<P: IntoWasmValueTuple, R: FromWasmValueTuple> FuncHandleTyped<P, R> {
/// Call a typed function
pub fn call(&self, store: &mut Store, params: P) -> Result<R> {
// Convert params into Vec<WasmValue>
diff --git a/crates/tinywasm/src/imports.rs b/crates/tinywasm/src/imports.rs
index 804aa12..0720d02 100644
--- a/crates/tinywasm/src/imports.rs
+++ b/crates/tinywasm/src/imports.rs
@@ -90,56 +90,45 @@ impl Debug for HostFunction {
/// An external value
pub enum Extern {
/// A global value
- Global(ExternGlobal),
+ Global {
+ /// The type of the global value.
+ ty: GlobalType,
+ /// The actual value of the global, encapsulated in `WasmValue`.
+ val: WasmValue,
+ },
/// A table
- Table(ExternTable),
+ Table {
+ /// Defines the type of the table, including its element type and limits.
+ ty: TableType,
+ /// The initial value of the table.
+ init: WasmValue,
+ },
/// A memory
- Memory(ExternMemory),
+ Memory {
+ /// Defines the type of the memory, including its limits and the type of its pages.
+ ty: MemoryType,
+ },
/// A function
Function(Function),
}
-/// A function
-#[derive(Debug, Clone)]
-pub struct ExternFunc(pub(crate) HostFunction);
-
-/// A global value
-#[derive(Debug, Clone)]
-pub struct ExternGlobal {
- pub(crate) ty: GlobalType,
- pub(crate) val: WasmValue,
-}
-
-/// A table
-#[derive(Debug, Clone)]
-pub struct ExternTable {
- pub(crate) ty: TableType,
- pub(crate) val: WasmValue,
-}
-
-/// A memory
-#[derive(Debug, Clone)]
-pub struct ExternMemory {
- pub(crate) ty: MemoryType,
-}
-
impl Extern {
/// Create a new global import
pub fn global(val: WasmValue, mutable: bool) -> Self {
- Self::Global(ExternGlobal { ty: GlobalType { ty: val.val_type(), mutable }, val })
+ Self::Global { ty: GlobalType { ty: val.val_type(), mutable }, val }
}
/// Create a new table import
- pub fn table(ty: TableType, val: WasmValue) -> Self {
- Self::Table(ExternTable { ty, val })
+ pub fn table(ty: TableType, init: WasmValue) -> Self {
+ Self::Table { ty, init }
}
/// Create a new memory import
pub fn memory(ty: MemoryType) -> Self {
- Self::Memory(ExternMemory { ty })
+ Self::Memory { ty }
}
/// Create a new function import
@@ -174,10 +163,10 @@ impl Extern {
pub(crate) fn kind(&self) -> ExternalKind {
match self {
- Self::Global(_) => ExternalKind::Global,
- Self::Table(_) => ExternalKind::Table,
- Self::Memory(_) => ExternalKind::Memory,
- Self::Function(_) => ExternalKind::Func,
+ Self::Global { .. } => ExternalKind::Global,
+ Self::Table { .. } => ExternalKind::Table,
+ Self::Memory { .. } => ExternalKind::Memory,
+ Self::Function { .. } => ExternalKind::Func,
}
}
}
@@ -197,6 +186,38 @@ impl From<&Import> for ExternName {
#[derive(Debug, Default)]
/// Imports for a module instance
+///
+/// This is used to link a module instance to its imports
+///
+/// ## Example
+/// ```rust
+/// # fn main() -> tinywasm::Result<()> {
+/// use tinywasm::{Imports, Extern};
+/// use tinywasm::types::{ValType, TableType, MemoryType, WasmValue};
+/// let mut imports = Imports::new();
+///
+/// // function args can be either a single
+/// // value that implements `TryFrom<WasmValue>` or a tuple of them
+/// let print_i32 = Extern::typed_func(|_ctx: tinywasm::FuncContext<'_>, arg: i32| {
+/// log::debug!("print_i32: {}", arg);
+/// Ok(())
+/// });
+///
+/// let table_type = TableType::new(ValType::RefFunc, 10, Some(20));
+/// let table_init = WasmValue::default_for(ValType::RefFunc);
+///
+/// imports
+/// .define("my_module", "print_i32", print_i32)?
+/// .define("my_module", "table", Extern::table(table_type, table_init))?
+/// .define("my_module", "memory", Extern::memory(MemoryType::new_32(1, Some(2))))?
+/// .define("my_module", "global_i32", Extern::global(WasmValue::I32(666), false))?
+/// .link_module("my_other_module", 0)?;
+/// # Ok(())
+/// # }
+/// ```
+///
+/// Note that module instance addresses for [`Imports::link_module`] can be obtained from [`crate::ModuleInstance::id`].
+/// Now, the imports object can be passed to [`crate::ModuleInstance::instantiate`].
pub struct Imports {
values: BTreeMap<ExternName, Extern>,
modules: BTreeMap<String, ModuleInstanceAddr>,
@@ -334,17 +355,17 @@ impl Imports {
match val {
// A link to something that needs to be added to the store
ResolvedExtern::Extern(ex) => match (ex, &import.kind) {
- (Extern::Global(extern_global), ImportKind::Global(ty)) => {
- Self::compare_types(import, &extern_global.ty, ty)?;
- imports.globals.push(store.add_global(extern_global.ty, extern_global.val.into(), idx)?);
+ (Extern::Global { ty, val }, ImportKind::Global(import_ty)) => {
+ Self::compare_types(import, &ty, import_ty)?;
+ imports.globals.push(store.add_global(ty, val.into(), idx)?);
}
- (Extern::Table(extern_table), ImportKind::Table(ty)) => {
- Self::compare_table_types(import, &extern_table.ty, ty)?;
- imports.tables.push(store.add_table(extern_table.ty, idx)?);
+ (Extern::Table { ty, .. }, ImportKind::Table(import_ty)) => {
+ Self::compare_table_types(import, &ty, import_ty)?;
+ imports.tables.push(store.add_table(ty, idx)?);
}
- (Extern::Memory(extern_memory), ImportKind::Memory(ty)) => {
- Self::compare_memory_types(import, &extern_memory.ty, ty, None)?;
- imports.memories.push(store.add_mem(extern_memory.ty, idx)?);
+ (Extern::Memory { ty }, ImportKind::Memory(import_ty)) => {
+ Self::compare_memory_types(import, &ty, import_ty, None)?;
+ imports.memories.push(store.add_mem(ty, idx)?);
}
(Extern::Function(extern_func), ImportKind::Function(ty)) => {
let import_func_type = module
diff --git a/crates/tinywasm/src/instance.rs b/crates/tinywasm/src/instance.rs
index d1fbd6f..75d1f87 100644
--- a/crates/tinywasm/src/instance.rs
+++ b/crates/tinywasm/src/instance.rs
@@ -6,10 +6,10 @@ use tinywasm_types::{
use crate::{
func::{FromWasmValueTuple, IntoWasmValueTuple},
- Error, FuncHandle, Imports, Module, Result, Store, TypedFuncHandle,
+ Error, FuncHandle, FuncHandleTyped, Imports, Module, Result, Store,
};
-/// A WebAssembly Module Instance
+/// An instanciated WebAssembly module
///
/// Backed by an Arc, so cloning is cheap
///
@@ -178,13 +178,13 @@ impl ModuleInstance {
}
/// Get a typed exported function by name
- pub fn typed_func<P, R>(&self, store: &Store, name: &str) -> Result<TypedFuncHandle<P, R>>
+ pub fn typed_func<P, R>(&self, store: &Store, name: &str) -> Result<FuncHandleTyped<P, R>>
where
P: IntoWasmValueTuple,
R: FromWasmValueTuple,
{
let func = self.exported_func_by_name(store, name)?;
- Ok(TypedFuncHandle { func, marker: core::marker::PhantomData })
+ Ok(FuncHandleTyped { func, marker: core::marker::PhantomData })
}
/// Get the start function of the module
diff --git a/crates/tinywasm/src/lib.rs b/crates/tinywasm/src/lib.rs
index 64d34df..1b63b99 100644
--- a/crates/tinywasm/src/lib.rs
+++ b/crates/tinywasm/src/lib.rs
@@ -14,12 +14,23 @@
//! to be useful for embedded systems and other environments where a full-featured
//! runtime is not required.
//!
-//! ## Getting Started
+//! ## Features
+//! - `std` (default): Enables the use of `std` and `std::io` for parsing from files and streams.
+//! - `logging` (default): Enables logging via the `log` crate.
+//! - `parser` (default): Enables the `tinywasm_parser` crate for parsing WebAssembly modules.
+//!
+//! ## No-std support
+//! TinyWasm supports `no_std` environments by disabling the `std` feature and registering
+//! a custom allocator. This removes support for parsing from files and streams,
+//! but otherwise the API is the same.
+//! Additionally, to have proper error types, you currently need a `nightly` compiler to have the error trait in core.
//!
+//! ## Getting Started
//! The easiest way to get started is to use the [`Module::parse_bytes`] function to load a
//! WebAssembly module from bytes. This will parse the module and validate it, returning
//! a [`Module`] that can be used to instantiate the module.
//!
+//!
//! ```rust
//! use tinywasm::{Store, Module};
//!
@@ -39,25 +50,21 @@
//!
//! // Get a typed handle to the exported "add" function
//! // Alternatively, you can use `instance.get_func` to get an untyped handle
-//! // that takes and returns WasmValue types
-//! let func = instance.typed_func::<(i32, i32), (i32,)>(&mut store, "add")?;
+//! // that takes and returns [`WasmValue`]s
+//! let func = instance.typed_func::<(i32, i32), i32>(&mut store, "add")?;
//! let res = func.call(&mut store, (1, 2))?;
//!
-//! assert_eq!(res, (3,));
+//! assert_eq!(res, 3);
//! # Ok::<(), tinywasm::Error>(())
//! ```
//!
-//! ## Features
-//! - `std` (default): Enables the use of `std` and `std::io` for parsing from files and streams.
-//! - `logging` (default): Enables logging via the `log` crate.
-//! - `parser` (default): Enables the `tinywasm_parser` crate for parsing WebAssembly modules.
+//! ## Custom Imports
//!
-//! ## No-std support
-//! TinyWasm supports `no_std` environments by disabling the `std` feature and registering
-//! a custom allocator. This removes support for parsing from files and streams,
-//! but otherwise the API is the same.
+//! To provide custom imports to a module, you can use the [`Imports`] struct.
+//! This struct allows you to register custom functions, globals, memories, tables,
+//! and other modules to be linked into the module when it is instantiated.
//!
-//! Additionally, if you want proper error types, you must use a `nightly` compiler to have the error trait in core.
+//! See the [`Imports`] documentation for more information.
mod std;
extern crate alloc;
@@ -87,13 +94,14 @@ mod instance;
pub use instance::ModuleInstance;
mod func;
-pub use func::{FuncHandle, TypedFuncHandle};
+pub use func::{FuncHandle, FuncHandleTyped};
mod imports;
pub use imports::*;
-mod runtime;
-pub use runtime::*;
+/// Runtime for executing WebAssembly modules.
+pub mod runtime;
+pub use runtime::InterpreterRuntime;
#[cfg(feature = "parser")]
/// Re-export of [`tinywasm_parser`]. Requires `parser` feature.
diff --git a/crates/tinywasm/src/runtime/executor/macros.rs b/crates/tinywasm/src/runtime/interpreter/macros.rs
index 909acb3..909acb3 100644
--- a/crates/tinywasm/src/runtime/executor/macros.rs
+++ b/crates/tinywasm/src/runtime/interpreter/macros.rs
diff --git a/crates/tinywasm/src/runtime/executor/mod.rs b/crates/tinywasm/src/runtime/interpreter/mod.rs
index d0f011f..48ce21d 100644
--- a/crates/tinywasm/src/runtime/executor/mod.rs
+++ b/crates/tinywasm/src/runtime/interpreter/mod.rs
@@ -1,10 +1,10 @@
use core::ops::{BitAnd, BitOr, BitXor, Neg};
-use super::{DefaultRuntime, Stack};
+use super::{InterpreterRuntime, Stack};
use crate::{
log::debug,
- runtime::{BlockType, LabelFrame},
- CallFrame, Error, FuncContext, LabelArgs, ModuleInstance, Result, Store, Trap,
+ runtime::{BlockType, CallFrame, LabelArgs, LabelFrame},
+ Error, FuncContext, ModuleInstance, Result, Store, Trap,
};
use alloc::{string::ToString, vec::Vec};
use tinywasm_types::{ElementKind, Instruction, ValType};
@@ -14,7 +14,7 @@ mod traits;
use macros::*;
use traits::*;
-impl DefaultRuntime {
+impl InterpreterRuntime {
pub(crate) fn exec(&self, store: &mut Store, stack: &mut Stack) -> Result<()> {
// The current call frame, gets updated inside of exec_one
let mut cf = stack.call_stack.pop()?;
@@ -246,7 +246,7 @@ fn exec_one(
instr_ptr: cf.instr_ptr + *else_offset,
end_instr_ptr: cf.instr_ptr + *end_offset,
stack_ptr: stack.values.len(), // - params,
- args: crate::LabelArgs::new(*args, module)?,
+ args: LabelArgs::new(*args, module)?,
ty: BlockType::Else,
},
&mut stack.values,
@@ -302,11 +302,8 @@ fn exec_one(
}
let idx = stack.values.pop_t::<i32>()? as usize;
- if let Some(label) = instr.get(idx) {
- break_to!(cf, stack, label);
- } else {
- break_to!(cf, stack, default);
- }
+ let to = instr.get(idx).unwrap_or(default);
+ break_to!(cf, stack, to);
}
Br(v) => break_to!(cf, stack, v),
diff --git a/crates/tinywasm/src/runtime/executor/traits.rs b/crates/tinywasm/src/runtime/interpreter/traits.rs
index 06aab2a..06aab2a 100644
--- a/crates/tinywasm/src/runtime/executor/traits.rs
+++ b/crates/tinywasm/src/runtime/interpreter/traits.rs
diff --git a/crates/tinywasm/src/runtime/mod.rs b/crates/tinywasm/src/runtime/mod.rs
index 610810f..3b9a57c 100644
--- a/crates/tinywasm/src/runtime/mod.rs
+++ b/crates/tinywasm/src/runtime/mod.rs
@@ -1,19 +1,23 @@
-mod executor;
+mod interpreter;
mod stack;
mod value;
pub use stack::*;
pub(crate) use value::RawWasmValue;
+use crate::Result;
+
#[allow(rustdoc::private_intra_doc_links)]
-/// A WebAssembly Runtime.
-///
-/// Generic over `CheckTypes` to enable type checking at runtime.
-/// This is useful for debugging, but should be disabled if you know
-/// that the module is valid.
+/// A WebAssembly runtime.
///
/// See <https://webassembly.github.io/spec/core/exec/runtime.html>
+pub trait Runtime {
+ /// Execute all call-frames on the stack until the stack is empty.
+ fn exec(&self, store: &mut crate::Store, stack: &mut crate::runtime::Stack) -> Result<()>;
+}
+
+/// The main TinyWasm runtime.
///
-/// Execution is implemented in the [`crate::runtime::executor`] module
+/// This is the default runtime used by TinyWasm.
#[derive(Debug, Default)]
-pub struct DefaultRuntime {}
+pub struct InterpreterRuntime {}
diff --git a/crates/tinywasm/src/runtime/stack/call_stack.rs b/crates/tinywasm/src/runtime/stack/call_stack.rs
index 1bcd474..098b918 100644
--- a/crates/tinywasm/src/runtime/stack/call_stack.rs
+++ b/crates/tinywasm/src/runtime/stack/call_stack.rs
@@ -1,8 +1,11 @@
-use crate::{runtime::RawWasmValue, BlockType, Error, FunctionInstance, LabelFrame, Result, Trap};
+use crate::{
+ runtime::{BlockType, RawWasmValue},
+ Error, FunctionInstance, Result, Trap,
+};
use alloc::{boxed::Box, rc::Rc, vec::Vec};
use tinywasm_types::{ValType, WasmValue};
-use super::blocks::Labels;
+use super::{blocks::Labels, LabelFrame};
// minimum call stack size
const CALL_STACK_SIZE: usize = 128;
diff --git a/crates/tinywasm/src/store.rs b/crates/tinywasm/src/store.rs
index aabbf71..4d3e326 100644
--- a/crates/tinywasm/src/store.rs
+++ b/crates/tinywasm/src/store.rs
@@ -7,8 +7,8 @@ use alloc::{boxed::Box, format, rc::Rc, string::ToString, vec, vec::Vec};
use tinywasm_types::*;
use crate::{
- runtime::{self, DefaultRuntime},
- Error, Function, ModuleInstance, RawWasmValue, Result, Trap,
+ runtime::{self, InterpreterRuntime, RawWasmValue},
+ Error, Function, ModuleInstance, Result, Trap,
};
// global store id counter
@@ -51,9 +51,9 @@ impl Store {
}
/// Create a new store with the given runtime
- pub(crate) fn runtime(&self) -> runtime::DefaultRuntime {
+ pub(crate) fn runtime(&self) -> runtime::InterpreterRuntime {
match self.runtime {
- Runtime::Default => DefaultRuntime::default(),
+ Runtime::Default => InterpreterRuntime::default(),
}
}
}
@@ -441,7 +441,7 @@ impl Store {
/// A WebAssembly Function Instance
///
/// See <https://webassembly.github.io/spec/core/exec/runtime.html#function-instances>
-pub struct FunctionInstance {
+pub(crate) struct FunctionInstance {
pub(crate) func: Function,
pub(crate) _type_idx: TypeAddr,
pub(crate) owner: ModuleInstanceAddr, // index into store.module_instances, none for host functions
diff --git a/crates/tinywasm/tests/generated/mvp.csv b/crates/tinywasm/tests/generated/mvp.csv
index 23c080d..03241b3 100644
--- a/crates/tinywasm/tests/generated/mvp.csv
+++ b/crates/tinywasm/tests/generated/mvp.csv
@@ -3,3 +3,4 @@
0.1.0,17630,2598,[{"name":"address.wast","passed":5,"failed":255},{"name":"align.wast","passed":108,"failed":48},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":110,"failed":2},{"name":"block.wast","passed":193,"failed":30},{"name":"br.wast","passed":84,"failed":13},{"name":"br_if.wast","passed":90,"failed":28},{"name":"br_table.wast","passed":25,"failed":149},{"name":"call.wast","passed":29,"failed":62},{"name":"call_indirect.wast","passed":36,"failed":134},{"name":"comments.wast","passed":7,"failed":1},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":371,"failed":248},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":47,"failed":14},{"name":"elem.wast","passed":50,"failed":49},{"name":"endianness.wast","passed":1,"failed":68},{"name":"exports.wast","passed":92,"failed":4},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":2,"failed":6},{"name":"float_exprs.wast","passed":761,"failed":139},{"name":"float_literals.wast","passed":163,"failed":0},{"name":"float_memory.wast","passed":6,"failed":84},{"name":"float_misc.wast","passed":437,"failed":4},{"name":"forward.wast","passed":1,"failed":4},{"name":"func.wast","passed":124,"failed":48},{"name":"func_ptrs.wast","passed":10,"failed":26},{"name":"global.wast","passed":51,"failed":59},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":120,"failed":121},{"name":"imports.wast","passed":74,"failed":109},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":14,"failed":15},{"name":"left-to-right.wast","passed":1,"failed":95},{"name":"linking.wast","passed":21,"failed":111},{"name":"load.wast","passed":60,"failed":37},{"name":"local_get.wast","passed":32,"failed":4},{"name":"local_set.wast","passed":50,"failed":3},{"name":"local_tee.wast","passed":68,"failed":29},{"name":"loop.wast","passed":93,"failed":27},{"name":"memory.wast","passed":34,"failed":45},{"name":"memory_grow.wast","passed":12,"failed":84},{"name":"memory_redundancy.wast","passed":1,"failed":7},{"name":"memory_size.wast","passed":6,"failed":36},{"name":"memory_trap.wast","passed":2,"failed":180},{"name":"names.wast","passed":485,"failed":1},{"name":"nop.wast","passed":46,"failed":42},{"name":"return.wast","passed":73,"failed":11},{"name":"select.wast","passed":86,"failed":62},{"name":"skip-stack-guard-page.wast","passed":1,"failed":10},{"name":"stack.wast","passed":2,"failed":5},{"name":"start.wast","passed":9,"failed":11},{"name":"store.wast","passed":59,"failed":9},{"name":"switch.wast","passed":2,"failed":26},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":22,"failed":14},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":50,"failed":14},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unwind.wast","passed":35,"failed":15},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}]
0.2.0,19344,884,[{"name":"address.wast","passed":181,"failed":79},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":220,"failed":3},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":171,"failed":3},{"name":"call.wast","passed":73,"failed":18},{"name":"call_indirect.wast","passed":50,"failed":120},{"name":"comments.wast","passed":7,"failed":1},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":439,"failed":180},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":47,"failed":14},{"name":"elem.wast","passed":56,"failed":43},{"name":"endianness.wast","passed":29,"failed":40},{"name":"exports.wast","passed":92,"failed":4},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":6,"failed":2},{"name":"float_exprs.wast","passed":890,"failed":10},{"name":"float_literals.wast","passed":163,"failed":0},{"name":"float_memory.wast","passed":78,"failed":12},{"name":"float_misc.wast","passed":437,"failed":4},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":168,"failed":4},{"name":"func_ptrs.wast","passed":10,"failed":26},{"name":"global.wast","passed":103,"failed":7},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":231,"failed":10},{"name":"imports.wast","passed":80,"failed":103},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":26,"failed":3},{"name":"left-to-right.wast","passed":92,"failed":4},{"name":"linking.wast","passed":29,"failed":103},{"name":"load.wast","passed":93,"failed":4},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":93,"failed":4},{"name":"loop.wast","passed":116,"failed":4},{"name":"memory.wast","passed":78,"failed":1},{"name":"memory_grow.wast","passed":91,"failed":5},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":35,"failed":7},{"name":"memory_trap.wast","passed":180,"failed":2},{"name":"names.wast","passed":485,"failed":1},{"name":"nop.wast","passed":78,"failed":10},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":114,"failed":34},{"name":"skip-stack-guard-page.wast","passed":1,"failed":10},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":11,"failed":9},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}]
0.3.0,20254,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":99,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":163,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":183,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}]
+0.3.0-alpha.0,20254,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":99,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":163,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":183,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}]