use crate::error::Error; use crate::module::{ModuleContext, SigType, Signature}; use smallvec::{smallvec, SmallVec}; use std::{ convert::TryInto, fmt, iter::{self, FromIterator}, ops::RangeInclusive, }; use wasmparser::{ BinaryReaderError, FunctionBody, Ieee32 as WasmIeee32, Ieee64 as WasmIeee64, MemoryImmediate as WasmMemoryImmediate, Operator as WasmOperator, OperatorsReader, }; pub fn dis( mut out: impl std::io::Write, function_name: impl fmt::Display, microwasm: impl IntoIterator>, ) -> std::io::Result<()> where BrTarget: fmt::Display, L: Clone, { writeln!(out, ".fn_{}:", function_name)?; let p = " "; for op in microwasm { if op.is_label() || op.is_block() { writeln!(out, "{}", op)?; } else { writeln!(out, "{}{}", p, op)?; } } Ok(()) } /// A constant value embedded in the instructions #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Value { I32(i32), I64(i64), F32(Ieee32), F64(Ieee64), } impl fmt::Display for Value { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Value::I32(v) => write!(f, "{}i32", v), Value::I64(v) => write!(f, "{}i64", v), Value::F32(v) => write!(f, "{}f32", f32::from_bits(v.to_bits())), Value::F64(v) => write!(f, "{}f64", f64::from_bits(v.to_bits())), } } } impl Value { pub fn as_int(self) -> Option { self.as_i64().or_else(|| self.as_i32().map(|i| i as _)) } pub fn as_bytes(self) -> i64 { match self { Value::I32(val) => val as _, Value::I64(val) => val, Value::F32(val) => val.0 as _, Value::F64(val) => val.0 as _, } } pub fn as_i32(self) -> Option { match self { Value::I32(val) => Some(val), _ => None, } } pub fn as_i64(self) -> Option { match self { Value::I64(val) => Some(val), _ => None, } } pub fn as_f32(self) -> Option { match self { Value::F32(val) => Some(val), _ => None, } } pub fn as_f64(self) -> Option { match self { Value::F64(val) => Some(val), _ => None, } } pub fn type_(&self) -> SignlessType { match self { Value::I32(_) => Type::Int(Size::_32), Value::I64(_) => Type::Int(Size::_64), Value::F32(Ieee32(_)) => Type::Float(Size::_32), Value::F64(Ieee64(_)) => Type::Float(Size::_64), } } fn default_for_type(ty: SignlessType) -> Self { match ty { Type::Int(Size::_32) => Value::I32(0), Type::Int(Size::_64) => Value::I64(0), Type::Float(Size::_32) => Value::F32(Ieee32(0)), Type::Float(Size::_64) => Value::F64(Ieee64(0)), } } } impl From for Value { fn from(other: i32) -> Self { Value::I32(other) } } impl From for Value { fn from(other: i64) -> Self { Value::I64(other) } } impl From for Value { fn from(other: u32) -> Self { Value::I32(other as _) } } impl From for Value { fn from(other: u64) -> Self { Value::I64(other as _) } } impl From for Value { fn from(other: Ieee32) -> Self { Value::F32(other) } } impl From for Value { fn from(other: Ieee64) -> Self { Value::F64(other) } } /// Whether to interpret an integer as signed or unsigned #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Signedness { Signed, Unsigned, } #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Size { _32, _64, } type Int = Size; type Float = Size; #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct SignfulInt(pub Signedness, pub Size); #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Type { Int(I), Float(Size), } pub trait IntoType { fn into_type() -> T; } impl IntoType for i32 { fn into_type() -> SignlessType { I32 } } impl IntoType for i64 { fn into_type() -> SignlessType { I64 } } impl IntoType for u32 { fn into_type() -> SignlessType { I32 } } impl IntoType for u64 { fn into_type() -> SignlessType { I64 } } impl IntoType for f32 { fn into_type() -> SignlessType { F32 } } impl IntoType for f64 { fn into_type() -> SignlessType { F64 } } impl Type { pub fn for_>() -> Self { T::into_type() } } impl fmt::Display for SignfulType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Type::Int(i) => write!(f, "{}", i), Type::Float(Size::_32) => write!(f, "f32"), Type::Float(Size::_64) => write!(f, "f64"), } } } impl fmt::Display for SignlessType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Type::Int(Size::_32) => write!(f, "i32"), Type::Int(Size::_64) => write!(f, "i64"), Type::Float(Size::_32) => write!(f, "f32"), Type::Float(Size::_64) => write!(f, "f64"), } } } impl fmt::Display for SignfulInt { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { SignfulInt(Signedness::Signed, Size::_32) => write!(f, "i32"), SignfulInt(Signedness::Unsigned, Size::_32) => write!(f, "u32"), SignfulInt(Signedness::Signed, Size::_64) => write!(f, "i64"), SignfulInt(Signedness::Unsigned, Size::_64) => write!(f, "u64"), } } } pub type SignlessType = Type; pub type SignfulType = Type; pub const I32: SignlessType = Type::Int(Size::_32); pub const I64: SignlessType = Type::Int(Size::_64); pub const F32: SignlessType = Type::Float(Size::_32); pub const F64: SignlessType = Type::Float(Size::_64); pub mod sint { use super::{Signedness, SignfulInt, Size}; pub const I32: SignfulInt = SignfulInt(Signedness::Signed, Size::_32); pub const I64: SignfulInt = SignfulInt(Signedness::Signed, Size::_64); pub const U32: SignfulInt = SignfulInt(Signedness::Unsigned, Size::_32); pub const U64: SignfulInt = SignfulInt(Signedness::Unsigned, Size::_64); } pub const SI32: SignfulType = Type::Int(sint::I32); pub const SI64: SignfulType = Type::Int(sint::I64); pub const SU32: SignfulType = Type::Int(sint::U32); pub const SU64: SignfulType = Type::Int(sint::U64); pub const SF32: SignfulType = Type::Float(Size::_32); pub const SF64: SignfulType = Type::Float(Size::_64); impl SignlessType { pub fn from_wasm(other: wasmparser::Type) -> Result { use wasmparser::Type; match other { Type::I32 => Ok(I32), Type::I64 => Ok(I64), Type::F32 => Ok(F32), Type::F64 => Ok(F64), Type::EmptyBlockType => Err(BinaryReaderError { message: "SignlessType with EmptyBlockType", offset: -1isize as usize, }), _ => Err(BinaryReaderError { message: "SignlessType unimplemented", offset: -1isize as usize, }), } } } fn create_returns_from_wasm_type( ty: wasmparser::TypeOrFuncType, ) -> Result, BinaryReaderError> { match ty { wasmparser::TypeOrFuncType::Type(ty) => Ok(Vec::from_iter(Type::from_wasm(ty))), wasmparser::TypeOrFuncType::FuncType(_) => Err(BinaryReaderError { message: "Unsupported func type", offset: -1isize as usize, }), } } #[derive(Debug, Clone)] pub struct BrTable { pub targets: Vec>, pub default: BrTargetDrop, } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum NameTag { Header, Else, End, } pub type WasmLabel = (u32, NameTag); pub type OperatorFromWasm = Operator; #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] pub enum BrTarget { Return, Label(L), } impl BrTarget { pub fn label(&self) -> Option<&L> { match self { BrTarget::Return => None, BrTarget::Label(l) => Some(l), } } } impl From for BrTarget { fn from(other: L) -> Self { BrTarget::Label(other) } } impl fmt::Display for BrTarget { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { BrTarget::Return => write!(f, ".return"), BrTarget::Label((i, NameTag::Header)) => write!(f, ".L{}", i), BrTarget::Label((i, NameTag::Else)) => write!(f, ".L{}_else", i), BrTarget::Label((i, NameTag::End)) => write!(f, ".L{}_end", i), } } } impl fmt::Display for BrTarget<&str> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { BrTarget::Return => write!(f, ".return"), BrTarget::Label(l) => write!(f, ".L{}", l), } } } #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct BrTargetDrop { pub target: BrTarget, pub to_drop: Option>, } impl From> for BrTargetDrop { fn from(other: BrTarget) -> Self { BrTargetDrop { target: other, to_drop: None, } } } impl fmt::Display for BrTargetDrop where BrTarget: fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if let Some(drop) = &self.to_drop { write!( f, "({}, drop {}..={})", self.target, drop.start(), drop.end() ) } else { write!(f, "{}", self.target) } } } #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct Ieee32(u32); #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct Ieee64(u64); impl Ieee32 { pub fn to_bits(self) -> u32 { self.0 } pub fn from_bits(other: u32) -> Self { Ieee32(other) } } impl From for Ieee32 { fn from(other: WasmIeee32) -> Self { Self::from_bits(other.bits()) } } impl Ieee64 { pub fn to_bits(self) -> u64 { self.0 } pub fn from_bits(other: u64) -> Self { Ieee64(other) } } impl From for Ieee64 { fn from(other: WasmIeee64) -> Self { Self::from_bits(other.bits()) } } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct MemoryImmediate { pub flags: u32, pub offset: u32, } impl From for MemoryImmediate { fn from(other: WasmMemoryImmediate) -> Self { MemoryImmediate { flags: other.flags, offset: other.offset, } } } // TODO: Explicit VmCtx? #[derive(Debug, Clone)] pub enum Operator