use crate::module::ModuleContext; use smallvec::SmallVec; use std::{ fmt, iter::{self, FromIterator}, ops::RangeInclusive, }; use wasmparser::{ FunctionBody, Ieee32, Ieee64, MemoryImmediate, Operator as WasmOperator, OperatorsReader, }; pub fn dis(function_name: impl fmt::Display, microwasm: &[Operator]) -> String where BrTarget: fmt::Display, L: Clone, { use std::fmt::Write; const DISASSEMBLE_BLOCK_DEFS: bool = true; let mut asm = format!(".fn_{}:\n", function_name); let mut out = String::new(); let p = " "; for op in microwasm { if op.is_label() { writeln!(asm, "{}", op).unwrap(); } else if op.is_block() { writeln!(out, "{}", op).unwrap(); } else { writeln!(asm, "{}{}", p, op).unwrap(); } } let out = if DISASSEMBLE_BLOCK_DEFS { writeln!(out).unwrap(); writeln!(out, "{}", asm).unwrap(); out } else { asm }; out } /// 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.bits())), Value::F64(v) => write!(f, "{}f64", f64::from_bits(v.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(Signedness, Size); #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Type { Int(I), Float(Size), } 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) -> Option { use wasmparser::Type; match other { Type::I32 => Some(I32), Type::I64 => Some(I64), Type::F32 => Some(F32), Type::F64 => Some(F64), Type::EmptyBlockType => None, _ => unimplemented!(), } } } #[derive(Debug, Clone)] pub struct BrTable { targets: Vec, } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum NameTag { Header, Else, End, } pub type WasmLabel = (u32, NameTag); trait Label { // TODO } // TODO: This is for Wasm blocks - we should have an increasing ID for each block that we hit. impl Label for (u32, NameTag) {} 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 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), } } } // TODO: Explicit VmCtx? #[derive(Debug, Clone)] pub enum Operator