mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-06-28 22:22:02 +00:00
1231 lines
33 KiB
Rust
1231 lines
33 KiB
Rust
use std::{io, fmt};
|
|
use super::{
|
|
Serialize, Deserialize, Error,
|
|
Uint8, VarUint32, CountedList, BlockType,
|
|
Uint32, Uint64, CountedListWriter,
|
|
VarInt32, VarInt64,
|
|
};
|
|
|
|
/// Collection of opcodes (usually inside a block section).
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub struct Opcodes(Vec<Opcode>);
|
|
|
|
impl Opcodes {
|
|
/// New list of opcodes from vector of opcodes.
|
|
pub fn new(elements: Vec<Opcode>) -> Self {
|
|
Opcodes(elements)
|
|
}
|
|
|
|
/// Empty expression with only `Opcode::End` opcode.
|
|
pub fn empty() -> Self {
|
|
Opcodes(vec![Opcode::End])
|
|
}
|
|
|
|
/// List of individual opcodes.
|
|
pub fn elements(&self) -> &[Opcode] { &self.0 }
|
|
|
|
/// Individual opcodes, mutable.
|
|
pub fn elements_mut(&mut self) -> &mut Vec<Opcode> { &mut self.0 }
|
|
}
|
|
|
|
impl Deserialize for Opcodes {
|
|
type Error = Error;
|
|
|
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
|
let mut opcodes = Vec::new();
|
|
let mut block_count = 1usize;
|
|
|
|
loop {
|
|
let opcode = Opcode::deserialize(reader)?;
|
|
if opcode.is_terminal() {
|
|
block_count -= 1;
|
|
} else if opcode.is_block() {
|
|
block_count = block_count.checked_add(1).ok_or(Error::Other("too many opcodes"))?;
|
|
}
|
|
|
|
opcodes.push(opcode);
|
|
if block_count == 0 {
|
|
break;
|
|
}
|
|
}
|
|
|
|
Ok(Opcodes(opcodes))
|
|
}
|
|
}
|
|
|
|
/// Initialization expression.
|
|
#[derive(Debug, Clone)]
|
|
pub struct InitExpr(Vec<Opcode>);
|
|
|
|
impl InitExpr {
|
|
/// New initialization expression from list of opcodes.
|
|
/// `code` must end with the `Opcode::End` opcode!
|
|
pub fn new(code: Vec<Opcode>) -> Self {
|
|
InitExpr(code)
|
|
}
|
|
|
|
/// Empty expression with only `Opcode::End` opcode
|
|
pub fn empty() -> Self {
|
|
InitExpr(vec![Opcode::End])
|
|
}
|
|
|
|
/// List of opcodes used in the expression.
|
|
pub fn code(&self) -> &[Opcode] {
|
|
&self.0
|
|
}
|
|
|
|
/// List of opcodes used in the expression.
|
|
pub fn code_mut(&mut self) -> &mut Vec<Opcode> {
|
|
&mut self.0
|
|
}
|
|
}
|
|
|
|
// todo: check if kind of opcode sequence is valid as an expression
|
|
impl Deserialize for InitExpr {
|
|
type Error = Error;
|
|
|
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
|
let mut opcodes = Vec::new();
|
|
|
|
loop {
|
|
let opcode = Opcode::deserialize(reader)?;
|
|
let is_terminal = opcode.is_terminal();
|
|
opcodes.push(opcode);
|
|
if is_terminal {
|
|
break;
|
|
}
|
|
}
|
|
|
|
Ok(InitExpr(opcodes))
|
|
}
|
|
}
|
|
|
|
/// Opcode
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
#[allow(missing_docs)]
|
|
pub enum Opcode {
|
|
Unreachable,
|
|
Nop,
|
|
Block(BlockType),
|
|
Loop(BlockType),
|
|
If(BlockType),
|
|
Else,
|
|
End,
|
|
Br(u32),
|
|
BrIf(u32),
|
|
BrTable(Box<[u32]>, u32),
|
|
Return,
|
|
|
|
Call(u32),
|
|
CallIndirect(u32, u8),
|
|
|
|
Drop,
|
|
Select,
|
|
|
|
GetLocal(u32),
|
|
SetLocal(u32),
|
|
TeeLocal(u32),
|
|
GetGlobal(u32),
|
|
SetGlobal(u32),
|
|
|
|
// All store/load opcodes operate with 'memory immediates'
|
|
// which represented here as (flag, offset) tuple
|
|
I32Load(u32, u32),
|
|
I64Load(u32, u32),
|
|
F32Load(u32, u32),
|
|
F64Load(u32, u32),
|
|
I32Load8S(u32, u32),
|
|
I32Load8U(u32, u32),
|
|
I32Load16S(u32, u32),
|
|
I32Load16U(u32, u32),
|
|
I64Load8S(u32, u32),
|
|
I64Load8U(u32, u32),
|
|
I64Load16S(u32, u32),
|
|
I64Load16U(u32, u32),
|
|
I64Load32S(u32, u32),
|
|
I64Load32U(u32, u32),
|
|
I32Store(u32, u32),
|
|
I64Store(u32, u32),
|
|
F32Store(u32, u32),
|
|
F64Store(u32, u32),
|
|
I32Store8(u32, u32),
|
|
I32Store16(u32, u32),
|
|
I64Store8(u32, u32),
|
|
I64Store16(u32, u32),
|
|
I64Store32(u32, u32),
|
|
|
|
CurrentMemory(u8),
|
|
GrowMemory(u8),
|
|
|
|
I32Const(i32),
|
|
I64Const(i64),
|
|
F32Const(u32),
|
|
F64Const(u64),
|
|
|
|
I32Eqz,
|
|
I32Eq,
|
|
I32Ne,
|
|
I32LtS,
|
|
I32LtU,
|
|
I32GtS,
|
|
I32GtU,
|
|
I32LeS,
|
|
I32LeU,
|
|
I32GeS,
|
|
I32GeU,
|
|
|
|
I64Eqz,
|
|
I64Eq,
|
|
I64Ne,
|
|
I64LtS,
|
|
I64LtU,
|
|
I64GtS,
|
|
I64GtU,
|
|
I64LeS,
|
|
I64LeU,
|
|
I64GeS,
|
|
I64GeU,
|
|
|
|
F32Eq,
|
|
F32Ne,
|
|
F32Lt,
|
|
F32Gt,
|
|
F32Le,
|
|
F32Ge,
|
|
|
|
F64Eq,
|
|
F64Ne,
|
|
F64Lt,
|
|
F64Gt,
|
|
F64Le,
|
|
F64Ge,
|
|
|
|
I32Clz,
|
|
I32Ctz,
|
|
I32Popcnt,
|
|
I32Add,
|
|
I32Sub,
|
|
I32Mul,
|
|
I32DivS,
|
|
I32DivU,
|
|
I32RemS,
|
|
I32RemU,
|
|
I32And,
|
|
I32Or,
|
|
I32Xor,
|
|
I32Shl,
|
|
I32ShrS,
|
|
I32ShrU,
|
|
I32Rotl,
|
|
I32Rotr,
|
|
|
|
I64Clz,
|
|
I64Ctz,
|
|
I64Popcnt,
|
|
I64Add,
|
|
I64Sub,
|
|
I64Mul,
|
|
I64DivS,
|
|
I64DivU,
|
|
I64RemS,
|
|
I64RemU,
|
|
I64And,
|
|
I64Or,
|
|
I64Xor,
|
|
I64Shl,
|
|
I64ShrS,
|
|
I64ShrU,
|
|
I64Rotl,
|
|
I64Rotr,
|
|
F32Abs,
|
|
F32Neg,
|
|
F32Ceil,
|
|
F32Floor,
|
|
F32Trunc,
|
|
F32Nearest,
|
|
F32Sqrt,
|
|
F32Add,
|
|
F32Sub,
|
|
F32Mul,
|
|
F32Div,
|
|
F32Min,
|
|
F32Max,
|
|
F32Copysign,
|
|
F64Abs,
|
|
F64Neg,
|
|
F64Ceil,
|
|
F64Floor,
|
|
F64Trunc,
|
|
F64Nearest,
|
|
F64Sqrt,
|
|
F64Add,
|
|
F64Sub,
|
|
F64Mul,
|
|
F64Div,
|
|
F64Min,
|
|
F64Max,
|
|
F64Copysign,
|
|
|
|
I32WrapI64,
|
|
I32TruncSF32,
|
|
I32TruncUF32,
|
|
I32TruncSF64,
|
|
I32TruncUF64,
|
|
I64ExtendSI32,
|
|
I64ExtendUI32,
|
|
I64TruncSF32,
|
|
I64TruncUF32,
|
|
I64TruncSF64,
|
|
I64TruncUF64,
|
|
F32ConvertSI32,
|
|
F32ConvertUI32,
|
|
F32ConvertSI64,
|
|
F32ConvertUI64,
|
|
F32DemoteF64,
|
|
F64ConvertSI32,
|
|
F64ConvertUI32,
|
|
F64ConvertSI64,
|
|
F64ConvertUI64,
|
|
F64PromoteF32,
|
|
|
|
I32ReinterpretF32,
|
|
I64ReinterpretF64,
|
|
F32ReinterpretI32,
|
|
F64ReinterpretI64,
|
|
}
|
|
|
|
impl Opcode {
|
|
/// Is this opcode starts the new block (which should end with terminal opcode).
|
|
pub fn is_block(&self) -> bool {
|
|
match self {
|
|
&Opcode::Block(_) | &Opcode::Loop(_) | &Opcode::If(_) => true,
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
/// Is this opcode determines the termination of opcode sequence
|
|
/// `true` for `Opcode::End`
|
|
pub fn is_terminal(&self) -> bool {
|
|
match self {
|
|
&Opcode::End => true,
|
|
_ => false,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Deserialize for Opcode {
|
|
type Error = Error;
|
|
|
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
|
use self::Opcode::*;
|
|
|
|
let val: u8 = Uint8::deserialize(reader)?.into();
|
|
|
|
Ok(
|
|
match val {
|
|
0x00 => Unreachable,
|
|
0x01 => Nop,
|
|
0x02 => Block(BlockType::deserialize(reader)?),
|
|
0x03 => Loop(BlockType::deserialize(reader)?),
|
|
0x04 => If(BlockType::deserialize(reader)?),
|
|
0x05 => Else,
|
|
0x0b => End,
|
|
|
|
0x0c => Br(VarUint32::deserialize(reader)?.into()),
|
|
0x0d => BrIf(VarUint32::deserialize(reader)?.into()),
|
|
0x0e => {
|
|
let t1: Vec<u32> = CountedList::<VarUint32>::deserialize(reader)?
|
|
.into_inner()
|
|
.into_iter()
|
|
.map(Into::into)
|
|
.collect();
|
|
|
|
BrTable(t1.into_boxed_slice(), VarUint32::deserialize(reader)?.into())
|
|
},
|
|
0x0f => Return,
|
|
0x10 => Call(VarUint32::deserialize(reader)?.into()),
|
|
0x11 => CallIndirect(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
Uint8::deserialize(reader)?.into()),
|
|
0x1a => Drop,
|
|
0x1b => Select,
|
|
|
|
0x20 => GetLocal(VarUint32::deserialize(reader)?.into()),
|
|
0x21 => SetLocal(VarUint32::deserialize(reader)?.into()),
|
|
0x22 => TeeLocal(VarUint32::deserialize(reader)?.into()),
|
|
0x23 => GetGlobal(VarUint32::deserialize(reader)?.into()),
|
|
0x24 => SetGlobal(VarUint32::deserialize(reader)?.into()),
|
|
|
|
0x28 => I32Load(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
VarUint32::deserialize(reader)?.into()),
|
|
|
|
0x29 => I64Load(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
VarUint32::deserialize(reader)?.into()),
|
|
|
|
0x2a => F32Load(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
VarUint32::deserialize(reader)?.into()),
|
|
|
|
0x2b => F64Load(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
VarUint32::deserialize(reader)?.into()),
|
|
|
|
0x2c => I32Load8S(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
VarUint32::deserialize(reader)?.into()),
|
|
|
|
0x2d => I32Load8U(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
VarUint32::deserialize(reader)?.into()),
|
|
|
|
0x2e => I32Load16S(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
VarUint32::deserialize(reader)?.into()),
|
|
|
|
0x2f => I32Load16U(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
VarUint32::deserialize(reader)?.into()),
|
|
|
|
0x30 => I64Load8S(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
VarUint32::deserialize(reader)?.into()),
|
|
|
|
0x31 => I64Load8U(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
VarUint32::deserialize(reader)?.into()),
|
|
|
|
0x32 => I64Load16S(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
VarUint32::deserialize(reader)?.into()),
|
|
|
|
0x33 => I64Load16U(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
VarUint32::deserialize(reader)?.into()),
|
|
|
|
0x34 => I64Load32S(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
VarUint32::deserialize(reader)?.into()),
|
|
|
|
0x35 => I64Load32U(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
VarUint32::deserialize(reader)?.into()),
|
|
|
|
0x36 => I32Store(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
VarUint32::deserialize(reader)?.into()),
|
|
|
|
0x37 => I64Store(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
VarUint32::deserialize(reader)?.into()),
|
|
|
|
0x38 => F32Store(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
VarUint32::deserialize(reader)?.into()),
|
|
|
|
0x39 => F64Store(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
VarUint32::deserialize(reader)?.into()),
|
|
|
|
0x3a => I32Store8(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
VarUint32::deserialize(reader)?.into()),
|
|
|
|
0x3b => I32Store16(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
VarUint32::deserialize(reader)?.into()),
|
|
|
|
0x3c => I64Store8(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
VarUint32::deserialize(reader)?.into()),
|
|
|
|
0x3d => I64Store16(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
VarUint32::deserialize(reader)?.into()),
|
|
|
|
0x3e => I64Store32(
|
|
VarUint32::deserialize(reader)?.into(),
|
|
VarUint32::deserialize(reader)?.into()),
|
|
|
|
|
|
0x3f => CurrentMemory(Uint8::deserialize(reader)?.into()),
|
|
0x40 => GrowMemory(Uint8::deserialize(reader)?.into()),
|
|
|
|
0x41 => I32Const(VarInt32::deserialize(reader)?.into()),
|
|
0x42 => I64Const(VarInt64::deserialize(reader)?.into()),
|
|
0x43 => F32Const(Uint32::deserialize(reader)?.into()),
|
|
0x44 => F64Const(Uint64::deserialize(reader)?.into()),
|
|
0x45 => I32Eqz,
|
|
0x46 => I32Eq,
|
|
0x47 => I32Ne,
|
|
0x48 => I32LtS,
|
|
0x49 => I32LtU,
|
|
0x4a => I32GtS,
|
|
0x4b => I32GtU,
|
|
0x4c => I32LeS,
|
|
0x4d => I32LeU,
|
|
0x4e => I32GeS,
|
|
0x4f => I32GeU,
|
|
|
|
0x50 => I64Eqz,
|
|
0x51 => I64Eq,
|
|
0x52 => I64Ne,
|
|
0x53 => I64LtS,
|
|
0x54 => I64LtU,
|
|
0x55 => I64GtS,
|
|
0x56 => I64GtU,
|
|
0x57 => I64LeS,
|
|
0x58 => I64LeU,
|
|
0x59 => I64GeS,
|
|
0x5a => I64GeU,
|
|
|
|
0x5b => F32Eq,
|
|
0x5c => F32Ne,
|
|
0x5d => F32Lt,
|
|
0x5e => F32Gt,
|
|
0x5f => F32Le,
|
|
0x60 => F32Ge,
|
|
|
|
0x61 => F64Eq,
|
|
0x62 => F64Ne,
|
|
0x63 => F64Lt,
|
|
0x64 => F64Gt,
|
|
0x65 => F64Le,
|
|
0x66 => F64Ge,
|
|
|
|
0x67 => I32Clz,
|
|
0x68 => I32Ctz,
|
|
0x69 => I32Popcnt,
|
|
0x6a => I32Add,
|
|
0x6b => I32Sub,
|
|
0x6c => I32Mul,
|
|
0x6d => I32DivS,
|
|
0x6e => I32DivU,
|
|
0x6f => I32RemS,
|
|
0x70 => I32RemU,
|
|
0x71 => I32And,
|
|
0x72 => I32Or,
|
|
0x73 => I32Xor,
|
|
0x74 => I32Shl,
|
|
0x75 => I32ShrS,
|
|
0x76 => I32ShrU,
|
|
0x77 => I32Rotl,
|
|
0x78 => I32Rotr,
|
|
|
|
0x79 => I64Clz,
|
|
0x7a => I64Ctz,
|
|
0x7b => I64Popcnt,
|
|
0x7c => I64Add,
|
|
0x7d => I64Sub,
|
|
0x7e => I64Mul,
|
|
0x7f => I64DivS,
|
|
0x80 => I64DivU,
|
|
0x81 => I64RemS,
|
|
0x82 => I64RemU,
|
|
0x83 => I64And,
|
|
0x84 => I64Or,
|
|
0x85 => I64Xor,
|
|
0x86 => I64Shl,
|
|
0x87 => I64ShrS,
|
|
0x88 => I64ShrU,
|
|
0x89 => I64Rotl,
|
|
0x8a => I64Rotr,
|
|
0x8b => F32Abs,
|
|
0x8c => F32Neg,
|
|
0x8d => F32Ceil,
|
|
0x8e => F32Floor,
|
|
0x8f => F32Trunc,
|
|
0x90 => F32Nearest,
|
|
0x91 => F32Sqrt,
|
|
0x92 => F32Add,
|
|
0x93 => F32Sub,
|
|
0x94 => F32Mul,
|
|
0x95 => F32Div,
|
|
0x96 => F32Min,
|
|
0x97 => F32Max,
|
|
0x98 => F32Copysign,
|
|
0x99 => F64Abs,
|
|
0x9a => F64Neg,
|
|
0x9b => F64Ceil,
|
|
0x9c => F64Floor,
|
|
0x9d => F64Trunc,
|
|
0x9e => F64Nearest,
|
|
0x9f => F64Sqrt,
|
|
0xa0 => F64Add,
|
|
0xa1 => F64Sub,
|
|
0xa2 => F64Mul,
|
|
0xa3 => F64Div,
|
|
0xa4 => F64Min,
|
|
0xa5 => F64Max,
|
|
0xa6 => F64Copysign,
|
|
|
|
0xa7 => I32WrapI64,
|
|
0xa8 => I32TruncSF32,
|
|
0xa9 => I32TruncUF32,
|
|
0xaa => I32TruncSF64,
|
|
0xab => I32TruncUF64,
|
|
0xac => I64ExtendSI32,
|
|
0xad => I64ExtendUI32,
|
|
0xae => I64TruncSF32,
|
|
0xaf => I64TruncUF32,
|
|
0xb0 => I64TruncSF64,
|
|
0xb1 => I64TruncUF64,
|
|
0xb2 => F32ConvertSI32,
|
|
0xb3 => F32ConvertUI32,
|
|
0xb4 => F32ConvertSI64,
|
|
0xb5 => F32ConvertUI64,
|
|
0xb6 => F32DemoteF64,
|
|
0xb7 => F64ConvertSI32,
|
|
0xb8 => F64ConvertUI32,
|
|
0xb9 => F64ConvertSI64,
|
|
0xba => F64ConvertUI64,
|
|
0xbb => F64PromoteF32,
|
|
|
|
0xbc => I32ReinterpretF32,
|
|
0xbd => I64ReinterpretF64,
|
|
0xbe => F32ReinterpretI32,
|
|
0xbf => F64ReinterpretI64,
|
|
|
|
_ => { return Err(Error::UnknownOpcode(val)); }
|
|
}
|
|
)
|
|
}
|
|
}
|
|
|
|
macro_rules! op {
|
|
($writer: expr, $byte: expr) => ({
|
|
let b: u8 = $byte;
|
|
$writer.write_all(&[b])?;
|
|
});
|
|
($writer: expr, $byte: expr, $s: block) => ({
|
|
op!($writer, $byte);
|
|
$s;
|
|
});
|
|
}
|
|
|
|
impl Serialize for Opcode {
|
|
type Error = Error;
|
|
|
|
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
|
use self::Opcode::*;
|
|
|
|
match self {
|
|
Unreachable => op!(writer, 0x00),
|
|
Nop => op!(writer, 0x01),
|
|
Block(block_type) => op!(writer, 0x02, {
|
|
block_type.serialize(writer)?;
|
|
}),
|
|
Loop(block_type) => op!(writer, 0x03, {
|
|
block_type.serialize(writer)?;
|
|
}),
|
|
If(block_type) => op!(writer, 0x04, {
|
|
block_type.serialize(writer)?;
|
|
}),
|
|
Else => op!(writer, 0x05),
|
|
End => op!(writer, 0x0b),
|
|
Br(idx) => op!(writer, 0x0c, {
|
|
VarUint32::from(idx).serialize(writer)?;
|
|
}),
|
|
BrIf(idx) => op!(writer, 0x0d, {
|
|
VarUint32::from(idx).serialize(writer)?;
|
|
}),
|
|
BrTable(table, default) => op!(writer, 0x0e, {
|
|
let list_writer = CountedListWriter::<VarUint32, _>(
|
|
table.len(),
|
|
table.into_iter().map(|x| VarUint32::from(*x)),
|
|
);
|
|
list_writer.serialize(writer)?;
|
|
VarUint32::from(default).serialize(writer)?;
|
|
}),
|
|
Return => op!(writer, 0x0f),
|
|
Call(index) => op!(writer, 0x10, {
|
|
VarUint32::from(index).serialize(writer)?;
|
|
}),
|
|
CallIndirect(index, reserved) => op!(writer, 0x11, {
|
|
VarUint32::from(index).serialize(writer)?;
|
|
Uint8::from(reserved).serialize(writer)?;
|
|
}),
|
|
Drop => op!(writer, 0x1a),
|
|
Select => op!(writer, 0x1b),
|
|
GetLocal(index) => op!(writer, 0x20, {
|
|
VarUint32::from(index).serialize(writer)?;
|
|
}),
|
|
SetLocal(index) => op!(writer, 0x21, {
|
|
VarUint32::from(index).serialize(writer)?;
|
|
}),
|
|
TeeLocal(index) => op!(writer, 0x22, {
|
|
VarUint32::from(index).serialize(writer)?;
|
|
}),
|
|
GetGlobal(index) => op!(writer, 0x23, {
|
|
VarUint32::from(index).serialize(writer)?;
|
|
}),
|
|
SetGlobal(index) => op!(writer, 0x24, {
|
|
VarUint32::from(index).serialize(writer)?;
|
|
}),
|
|
I32Load(flags, offset) => op!(writer, 0x28, {
|
|
VarUint32::from(flags).serialize(writer)?;
|
|
VarUint32::from(offset).serialize(writer)?;
|
|
}),
|
|
I64Load(flags, offset) => op!(writer, 0x29, {
|
|
VarUint32::from(flags).serialize(writer)?;
|
|
VarUint32::from(offset).serialize(writer)?;
|
|
}),
|
|
F32Load(flags, offset) => op!(writer, 0x2a, {
|
|
VarUint32::from(flags).serialize(writer)?;
|
|
VarUint32::from(offset).serialize(writer)?;
|
|
}),
|
|
F64Load(flags, offset) => op!(writer, 0x2b, {
|
|
VarUint32::from(flags).serialize(writer)?;
|
|
VarUint32::from(offset).serialize(writer)?;
|
|
}),
|
|
I32Load8S(flags, offset) => op!(writer, 0x2c, {
|
|
VarUint32::from(flags).serialize(writer)?;
|
|
VarUint32::from(offset).serialize(writer)?;
|
|
}),
|
|
I32Load8U(flags, offset) => op!(writer, 0x2d, {
|
|
VarUint32::from(flags).serialize(writer)?;
|
|
VarUint32::from(offset).serialize(writer)?;
|
|
}),
|
|
I32Load16S(flags, offset) => op!(writer, 0x2e, {
|
|
VarUint32::from(flags).serialize(writer)?;
|
|
VarUint32::from(offset).serialize(writer)?;
|
|
}),
|
|
I32Load16U(flags, offset) => op!(writer, 0x2f, {
|
|
VarUint32::from(flags).serialize(writer)?;
|
|
VarUint32::from(offset).serialize(writer)?;
|
|
}),
|
|
I64Load8S(flags, offset) => op!(writer, 0x30, {
|
|
VarUint32::from(flags).serialize(writer)?;
|
|
VarUint32::from(offset).serialize(writer)?;
|
|
}),
|
|
I64Load8U(flags, offset) => op!(writer, 0x31, {
|
|
VarUint32::from(flags).serialize(writer)?;
|
|
VarUint32::from(offset).serialize(writer)?;
|
|
}),
|
|
I64Load16S(flags, offset) => op!(writer, 0x32, {
|
|
VarUint32::from(flags).serialize(writer)?;
|
|
VarUint32::from(offset).serialize(writer)?;
|
|
}),
|
|
I64Load16U(flags, offset) => op!(writer, 0x33, {
|
|
VarUint32::from(flags).serialize(writer)?;
|
|
VarUint32::from(offset).serialize(writer)?;
|
|
}),
|
|
I64Load32S(flags, offset) => op!(writer, 0x34, {
|
|
VarUint32::from(flags).serialize(writer)?;
|
|
VarUint32::from(offset).serialize(writer)?;
|
|
}),
|
|
I64Load32U(flags, offset) => op!(writer, 0x35, {
|
|
VarUint32::from(flags).serialize(writer)?;
|
|
VarUint32::from(offset).serialize(writer)?;
|
|
}),
|
|
I32Store(flags, offset) => op!(writer, 0x36, {
|
|
VarUint32::from(flags).serialize(writer)?;
|
|
VarUint32::from(offset).serialize(writer)?;
|
|
}),
|
|
I64Store(flags, offset) => op!(writer, 0x37, {
|
|
VarUint32::from(flags).serialize(writer)?;
|
|
VarUint32::from(offset).serialize(writer)?;
|
|
}),
|
|
F32Store(flags, offset) => op!(writer, 0x38, {
|
|
VarUint32::from(flags).serialize(writer)?;
|
|
VarUint32::from(offset).serialize(writer)?;
|
|
}),
|
|
F64Store(flags, offset) => op!(writer, 0x39, {
|
|
VarUint32::from(flags).serialize(writer)?;
|
|
VarUint32::from(offset).serialize(writer)?;
|
|
}),
|
|
I32Store8(flags, offset) => op!(writer, 0x3a, {
|
|
VarUint32::from(flags).serialize(writer)?;
|
|
VarUint32::from(offset).serialize(writer)?;
|
|
}),
|
|
I32Store16(flags, offset) => op!(writer, 0x3b, {
|
|
VarUint32::from(flags).serialize(writer)?;
|
|
VarUint32::from(offset).serialize(writer)?;
|
|
}),
|
|
I64Store8(flags, offset) => op!(writer, 0x3c, {
|
|
VarUint32::from(flags).serialize(writer)?;
|
|
VarUint32::from(offset).serialize(writer)?;
|
|
}),
|
|
I64Store16(flags, offset) => op!(writer, 0x3d, {
|
|
VarUint32::from(flags).serialize(writer)?;
|
|
VarUint32::from(offset).serialize(writer)?;
|
|
}),
|
|
I64Store32(flags, offset) => op!(writer, 0x3e, {
|
|
VarUint32::from(flags).serialize(writer)?;
|
|
VarUint32::from(offset).serialize(writer)?;
|
|
}),
|
|
CurrentMemory(flag) => op!(writer, 0x3f, {
|
|
Uint8::from(flag).serialize(writer)?;
|
|
}),
|
|
GrowMemory(flag) => op!(writer, 0x40, {
|
|
Uint8::from(flag).serialize(writer)?;
|
|
}),
|
|
I32Const(def) => op!(writer, 0x41, {
|
|
VarInt32::from(def).serialize(writer)?;
|
|
}),
|
|
I64Const(def) => op!(writer, 0x42, {
|
|
VarInt64::from(def).serialize(writer)?;
|
|
}),
|
|
F32Const(def) => op!(writer, 0x43, {
|
|
Uint32::from(def).serialize(writer)?;
|
|
}),
|
|
F64Const(def) => op!(writer, 0x44, {
|
|
Uint64::from(def).serialize(writer)?;
|
|
}),
|
|
I32Eqz => op!(writer, 0x45),
|
|
I32Eq => op!(writer, 0x46),
|
|
I32Ne => op!(writer, 0x47),
|
|
I32LtS => op!(writer, 0x48),
|
|
I32LtU => op!(writer, 0x49),
|
|
I32GtS => op!(writer, 0x4a),
|
|
I32GtU => op!(writer, 0x4b),
|
|
I32LeS => op!(writer, 0x4c),
|
|
I32LeU => op!(writer, 0x4d),
|
|
I32GeS => op!(writer, 0x4e),
|
|
I32GeU => op!(writer, 0x4f),
|
|
|
|
I64Eqz => op!(writer, 0x50),
|
|
I64Eq => op!(writer, 0x51),
|
|
I64Ne => op!(writer, 0x52),
|
|
I64LtS => op!(writer, 0x53),
|
|
I64LtU => op!(writer, 0x54),
|
|
I64GtS => op!(writer, 0x55),
|
|
I64GtU => op!(writer, 0x56),
|
|
I64LeS => op!(writer, 0x57),
|
|
I64LeU => op!(writer, 0x58),
|
|
I64GeS => op!(writer, 0x59),
|
|
I64GeU => op!(writer, 0x5a),
|
|
|
|
F32Eq => op!(writer, 0x5b),
|
|
F32Ne => op!(writer, 0x5c),
|
|
F32Lt => op!(writer, 0x5d),
|
|
F32Gt => op!(writer, 0x5e),
|
|
F32Le => op!(writer, 0x5f),
|
|
F32Ge => op!(writer, 0x60),
|
|
|
|
F64Eq => op!(writer, 0x61),
|
|
F64Ne => op!(writer, 0x62),
|
|
F64Lt => op!(writer, 0x63),
|
|
F64Gt => op!(writer, 0x64),
|
|
F64Le => op!(writer, 0x65),
|
|
F64Ge => op!(writer, 0x66),
|
|
|
|
I32Clz => op!(writer, 0x67),
|
|
I32Ctz => op!(writer, 0x68),
|
|
I32Popcnt => op!(writer, 0x69),
|
|
I32Add => op!(writer, 0x6a),
|
|
I32Sub => op!(writer, 0x6b),
|
|
I32Mul => op!(writer, 0x6c),
|
|
I32DivS => op!(writer, 0x6d),
|
|
I32DivU => op!(writer, 0x6e),
|
|
I32RemS => op!(writer, 0x6f),
|
|
I32RemU => op!(writer, 0x70),
|
|
I32And => op!(writer, 0x71),
|
|
I32Or => op!(writer, 0x72),
|
|
I32Xor => op!(writer, 0x73),
|
|
I32Shl => op!(writer, 0x74),
|
|
I32ShrS => op!(writer, 0x75),
|
|
I32ShrU => op!(writer, 0x76),
|
|
I32Rotl => op!(writer, 0x77),
|
|
I32Rotr => op!(writer, 0x78),
|
|
|
|
I64Clz => op!(writer, 0x79),
|
|
I64Ctz => op!(writer, 0x7a),
|
|
I64Popcnt => op!(writer, 0x7b),
|
|
I64Add => op!(writer, 0x7c),
|
|
I64Sub => op!(writer, 0x7d),
|
|
I64Mul => op!(writer, 0x7e),
|
|
I64DivS => op!(writer, 0x7f),
|
|
I64DivU => op!(writer, 0x80),
|
|
I64RemS => op!(writer, 0x81),
|
|
I64RemU => op!(writer, 0x82),
|
|
I64And => op!(writer, 0x83),
|
|
I64Or => op!(writer, 0x84),
|
|
I64Xor => op!(writer, 0x85),
|
|
I64Shl => op!(writer, 0x86),
|
|
I64ShrS => op!(writer, 0x87),
|
|
I64ShrU => op!(writer, 0x88),
|
|
I64Rotl => op!(writer, 0x89),
|
|
I64Rotr => op!(writer, 0x8a),
|
|
F32Abs => op!(writer, 0x8b),
|
|
F32Neg => op!(writer, 0x8c),
|
|
F32Ceil => op!(writer, 0x8d),
|
|
F32Floor => op!(writer, 0x8e),
|
|
F32Trunc => op!(writer, 0x8f),
|
|
F32Nearest => op!(writer, 0x90),
|
|
F32Sqrt => op!(writer, 0x91),
|
|
F32Add => op!(writer, 0x92),
|
|
F32Sub => op!(writer, 0x93),
|
|
F32Mul => op!(writer, 0x94),
|
|
F32Div => op!(writer, 0x95),
|
|
F32Min => op!(writer, 0x96),
|
|
F32Max => op!(writer, 0x97),
|
|
F32Copysign => op!(writer, 0x98),
|
|
F64Abs => op!(writer, 0x99),
|
|
F64Neg => op!(writer, 0x9a),
|
|
F64Ceil => op!(writer, 0x9b),
|
|
F64Floor => op!(writer, 0x9c),
|
|
F64Trunc => op!(writer, 0x9d),
|
|
F64Nearest => op!(writer, 0x9e),
|
|
F64Sqrt => op!(writer, 0x9f),
|
|
F64Add => op!(writer, 0xa0),
|
|
F64Sub => op!(writer, 0xa1),
|
|
F64Mul => op!(writer, 0xa2),
|
|
F64Div => op!(writer, 0xa3),
|
|
F64Min => op!(writer, 0xa4),
|
|
F64Max => op!(writer, 0xa5),
|
|
F64Copysign => op!(writer, 0xa6),
|
|
|
|
I32WrapI64 => op!(writer, 0xa7),
|
|
I32TruncSF32 => op!(writer, 0xa8),
|
|
I32TruncUF32 => op!(writer, 0xa9),
|
|
I32TruncSF64 => op!(writer, 0xaa),
|
|
I32TruncUF64 => op!(writer, 0xab),
|
|
I64ExtendSI32 => op!(writer, 0xac),
|
|
I64ExtendUI32 => op!(writer, 0xad),
|
|
I64TruncSF32 => op!(writer, 0xae),
|
|
I64TruncUF32 => op!(writer, 0xaf),
|
|
I64TruncSF64 => op!(writer, 0xb0),
|
|
I64TruncUF64 => op!(writer, 0xb1),
|
|
F32ConvertSI32 => op!(writer, 0xb2),
|
|
F32ConvertUI32 => op!(writer, 0xb3),
|
|
F32ConvertSI64 => op!(writer, 0xb4),
|
|
F32ConvertUI64 => op!(writer, 0xb5),
|
|
F32DemoteF64 => op!(writer, 0xb6),
|
|
F64ConvertSI32 => op!(writer, 0xb7),
|
|
F64ConvertUI32 => op!(writer, 0xb8),
|
|
F64ConvertSI64 => op!(writer, 0xb9),
|
|
F64ConvertUI64 => op!(writer, 0xba),
|
|
F64PromoteF32 => op!(writer, 0xbb),
|
|
|
|
I32ReinterpretF32 => op!(writer, 0xbc),
|
|
I64ReinterpretF64 => op!(writer, 0xbd),
|
|
F32ReinterpretI32 => op!(writer, 0xbe),
|
|
F64ReinterpretI64 => op!(writer, 0xbf),
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
macro_rules! fmt_op {
|
|
($f: expr, $mnemonic: expr) => ({
|
|
write!($f, "{}", $mnemonic)
|
|
});
|
|
($f: expr, $mnemonic: expr, $immediate: expr) => ({
|
|
write!($f, "{} {}", $mnemonic, $immediate)
|
|
});
|
|
($f: expr, $mnemonic: expr, $immediate1: expr, $immediate2: expr) => ({
|
|
write!($f, "{} {} {}", $mnemonic, $immediate1, $immediate2)
|
|
});
|
|
}
|
|
|
|
impl fmt::Display for Opcode {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
use self::Opcode::*;
|
|
use super::BlockType;
|
|
|
|
match *self {
|
|
Unreachable => fmt_op!(f, "unreachable"),
|
|
Nop => fmt_op!(f, "nop"),
|
|
Block(BlockType::NoResult) => fmt_op!(f, "block"),
|
|
Block(BlockType::Value(value_type)) => fmt_op!(f, "block", value_type),
|
|
Loop(BlockType::NoResult) => fmt_op!(f, "loop"),
|
|
Loop(BlockType::Value(value_type)) => fmt_op!(f, "loop", value_type),
|
|
If(BlockType::NoResult) => fmt_op!(f, "if"),
|
|
If(BlockType::Value(value_type)) => fmt_op!(f, "if", value_type),
|
|
Else => fmt_op!(f, "else"),
|
|
End => fmt_op!(f, "end"),
|
|
Br(idx) => fmt_op!(f, "br", idx),
|
|
BrIf(idx) => fmt_op!(f, "br_if", idx),
|
|
BrTable(_, default) => fmt_op!(f, "br_table", default),
|
|
Return => fmt_op!(f, "return"),
|
|
Call(index) => fmt_op!(f, "call", index),
|
|
CallIndirect(index, _) => fmt_op!(f, "call_indirect", index),
|
|
Drop => fmt_op!(f, "drop"),
|
|
Select => fmt_op!(f, "select"),
|
|
GetLocal(index) => fmt_op!(f, "get_local", index),
|
|
SetLocal(index) => fmt_op!(f, "set_local", index),
|
|
TeeLocal(index) => fmt_op!(f, "tee_local", index),
|
|
GetGlobal(index) => fmt_op!(f, "get_global", index),
|
|
SetGlobal(index) => fmt_op!(f, "set_global", index),
|
|
|
|
I32Load(_, 0) => write!(f, "i32.load"),
|
|
I32Load(_, offset) => write!(f, "i32.load offset={}", offset),
|
|
|
|
I64Load(_, 0) => write!(f, "i64.load"),
|
|
I64Load(_, offset) => write!(f, "i64.load offset={}", offset),
|
|
|
|
F32Load(_, 0) => write!(f, "f32.load"),
|
|
F32Load(_, offset) => write!(f, "f32.load offset={}", offset),
|
|
|
|
F64Load(_, 0) => write!(f, "f64.load"),
|
|
F64Load(_, offset) => write!(f, "f64.load offset={}", offset),
|
|
|
|
I32Load8S(_, 0) => write!(f, "i32.load8_s"),
|
|
I32Load8S(_, offset) => write!(f, "i32.load8_s offset={}", offset),
|
|
|
|
I32Load8U(_, 0) => write!(f, "i32.load8_u"),
|
|
I32Load8U(_, offset) => write!(f, "i32.load8_u offset={}", offset),
|
|
|
|
I32Load16S(_, 0) => write!(f, "i32.load16_s"),
|
|
I32Load16S(_, offset) => write!(f, "i32.load16_s offset={}", offset),
|
|
|
|
I32Load16U(_, 0) => write!(f, "i32.load16_u"),
|
|
I32Load16U(_, offset) => write!(f, "i32.load16_u offset={}", offset),
|
|
|
|
I64Load8S(_, 0) => write!(f, "i64.load8_s"),
|
|
I64Load8S(_, offset) => write!(f, "i64.load8_s offset={}", offset),
|
|
|
|
I64Load8U(_, 0) => write!(f, "i64.load8_u"),
|
|
I64Load8U(_, offset) => write!(f, "i64.load8_u offset={}", offset),
|
|
|
|
I64Load16S(_, 0) => write!(f, "i64.load16_s"),
|
|
I64Load16S(_, offset) => write!(f, "i64.load16_s offset={}", offset),
|
|
|
|
I64Load16U(_, 0) => write!(f, "i64.load16_u"),
|
|
I64Load16U(_, offset) => write!(f, "i64.load16_u offset={}", offset),
|
|
|
|
I64Load32S(_, 0) => write!(f, "i64.load32_s"),
|
|
I64Load32S(_, offset) => write!(f, "i64.load32_s offset={}", offset),
|
|
|
|
I64Load32U(_, 0) => write!(f, "i64.load32_u"),
|
|
I64Load32U(_, offset) => write!(f, "i64.load32_u offset={}", offset),
|
|
|
|
I32Store(_, 0) => write!(f, "i32.store"),
|
|
I32Store(_, offset) => write!(f, "i32.store offset={}", offset),
|
|
|
|
I64Store(_, 0) => write!(f, "i64.store"),
|
|
I64Store(_, offset) => write!(f, "i64.store offset={}", offset),
|
|
|
|
F32Store(_, 0) => write!(f, "f32.store"),
|
|
F32Store(_, offset) => write!(f, "f32.store offset={}", offset),
|
|
|
|
F64Store(_, 0) => write!(f, "f64.store"),
|
|
F64Store(_, offset) => write!(f, "f64.store offset={}", offset),
|
|
|
|
I32Store8(_, 0) => write!(f, "i32.store8"),
|
|
I32Store8(_, offset) => write!(f, "i32.store8 offset={}", offset),
|
|
|
|
I32Store16(_, 0) => write!(f, "i32.store16"),
|
|
I32Store16(_, offset) => write!(f, "i32.store16 offset={}", offset),
|
|
|
|
I64Store8(_, 0) => write!(f, "i64.store8"),
|
|
I64Store8(_, offset) => write!(f, "i64.store8 offset={}", offset),
|
|
|
|
I64Store16(_, 0) => write!(f, "i64.store16"),
|
|
I64Store16(_, offset) => write!(f, "i64.store16 offset={}", offset),
|
|
|
|
I64Store32(_, 0) => write!(f, "i64.store32"),
|
|
I64Store32(_, offset) => write!(f, "i64.store32 offset={}", offset),
|
|
|
|
CurrentMemory(_) => fmt_op!(f, "current_memory"),
|
|
GrowMemory(_) => fmt_op!(f, "grow_memory"),
|
|
|
|
I32Const(def) => fmt_op!(f, "i32.const", def),
|
|
I64Const(def) => fmt_op!(f, "i64.const", def),
|
|
F32Const(def) => fmt_op!(f, "f32.const", def),
|
|
F64Const(def) => fmt_op!(f, "f64.const", def),
|
|
|
|
I32Eq => write!(f, "i32.eq"),
|
|
I32Eqz => write!(f, "i32.eqz"),
|
|
I32Ne => write!(f, "i32.ne"),
|
|
I32LtS => write!(f, "i32.lt_s"),
|
|
I32LtU => write!(f, "i32.lt_u"),
|
|
I32GtS => write!(f, "i32.gt_s"),
|
|
I32GtU => write!(f, "i32.gt_u"),
|
|
I32LeS => write!(f, "i32.le_s"),
|
|
I32LeU => write!(f, "i32.le_u"),
|
|
I32GeS => write!(f, "i32.ge_s"),
|
|
I32GeU => write!(f, "i32.ge_u"),
|
|
|
|
I64Eq => write!(f, "i64.eq"),
|
|
I64Eqz => write!(f, "i64.eqz"),
|
|
I64Ne => write!(f, "i64.ne"),
|
|
I64LtS => write!(f, "i64.lt_s"),
|
|
I64LtU => write!(f, "i64.lt_u"),
|
|
I64GtS => write!(f, "i64.gt_s"),
|
|
I64GtU => write!(f, "i64.gt_u"),
|
|
I64LeS => write!(f, "i64.le_s"),
|
|
I64LeU => write!(f, "i64.le_u"),
|
|
I64GeS => write!(f, "i64.ge_s"),
|
|
I64GeU => write!(f, "i64.ge_u"),
|
|
|
|
F32Eq => write!(f, "f32.eq"),
|
|
F32Ne => write!(f, "f32.ne"),
|
|
F32Lt => write!(f, "f32.lt"),
|
|
F32Gt => write!(f, "f32.gt"),
|
|
F32Le => write!(f, "f32.le"),
|
|
F32Ge => write!(f, "f32.ge"),
|
|
|
|
F64Eq => write!(f, "f64.eq"),
|
|
F64Ne => write!(f, "f64.ne"),
|
|
F64Lt => write!(f, "f64.lt"),
|
|
F64Gt => write!(f, "f64.gt"),
|
|
F64Le => write!(f, "f64.le"),
|
|
F64Ge => write!(f, "f64.ge"),
|
|
|
|
I32Clz => write!(f, "i32.clz"),
|
|
I32Ctz => write!(f, "i32.ctz"),
|
|
I32Popcnt => write!(f, "i32.popcnt"),
|
|
I32Add => write!(f, "i32.add"),
|
|
I32Sub => write!(f, "i32.sub"),
|
|
I32Mul => write!(f, "i32.mul"),
|
|
I32DivS => write!(f, "i32.div_s"),
|
|
I32DivU => write!(f, "i32.div_u"),
|
|
I32RemS => write!(f, "i32.rem_s"),
|
|
I32RemU => write!(f, "i32.rem_u"),
|
|
I32And => write!(f, "i32.and"),
|
|
I32Or => write!(f, "i32.or"),
|
|
I32Xor => write!(f, "i32.xor"),
|
|
I32Shl => write!(f, "i32.shl"),
|
|
I32ShrS => write!(f, "i32.shr_s"),
|
|
I32ShrU => write!(f, "i32.shr_u"),
|
|
I32Rotl => write!(f, "i32.rotl"),
|
|
I32Rotr => write!(f, "i32.rotr"),
|
|
|
|
I64Clz => write!(f, "i64.clz"),
|
|
I64Ctz => write!(f, "i64.ctz"),
|
|
I64Popcnt => write!(f, "i64.popcnt"),
|
|
I64Add => write!(f, "i64.add"),
|
|
I64Sub => write!(f, "i64.sub"),
|
|
I64Mul => write!(f, "i64.mul"),
|
|
I64DivS => write!(f, "i64.div_s"),
|
|
I64DivU => write!(f, "i64.div_u"),
|
|
I64RemS => write!(f, "i64.rem_s"),
|
|
I64RemU => write!(f, "i64.rem_u"),
|
|
I64And => write!(f, "i64.and"),
|
|
I64Or => write!(f, "i64.or"),
|
|
I64Xor => write!(f, "i64.xor"),
|
|
I64Shl => write!(f, "i64.shl"),
|
|
I64ShrS => write!(f, "i64.shr_s"),
|
|
I64ShrU => write!(f, "i64.shr_u"),
|
|
I64Rotl => write!(f, "i64.rotl"),
|
|
I64Rotr => write!(f, "i64.rotr"),
|
|
|
|
F32Abs => write!(f, "f32.abs"),
|
|
F32Neg => write!(f, "f32.neg"),
|
|
F32Ceil => write!(f, "f32.ceil"),
|
|
F32Floor => write!(f, "f32.floor"),
|
|
F32Trunc => write!(f, "f32.trunc"),
|
|
F32Nearest => write!(f, "f32.nearest"),
|
|
F32Sqrt => write!(f, "f32.sqrt"),
|
|
F32Add => write!(f, "f32.add"),
|
|
F32Sub => write!(f, "f32.sub"),
|
|
F32Mul => write!(f, "f32.mul"),
|
|
F32Div => write!(f, "f32.div"),
|
|
F32Min => write!(f, "f32.min"),
|
|
F32Max => write!(f, "f32.max"),
|
|
F32Copysign => write!(f, "f32.copysign"),
|
|
|
|
F64Abs => write!(f, "f64.abs"),
|
|
F64Neg => write!(f, "f64.neg"),
|
|
F64Ceil => write!(f, "f64.ceil"),
|
|
F64Floor => write!(f, "f64.floor"),
|
|
F64Trunc => write!(f, "f64.trunc"),
|
|
F64Nearest => write!(f, "f64.nearest"),
|
|
F64Sqrt => write!(f, "f64.sqrt"),
|
|
F64Add => write!(f, "f64.add"),
|
|
F64Sub => write!(f, "f64.sub"),
|
|
F64Mul => write!(f, "f64.mul"),
|
|
F64Div => write!(f, "f64.div"),
|
|
F64Min => write!(f, "f64.min"),
|
|
F64Max => write!(f, "f64.max"),
|
|
F64Copysign => write!(f, "f64.copysign"),
|
|
|
|
I32WrapI64 => write!(f, "i32.wrap/i64"),
|
|
I32TruncSF32 => write!(f, "i32.trunc_s/f32"),
|
|
I32TruncUF32 => write!(f, "i32.trunc_u/f32"),
|
|
I32TruncSF64 => write!(f, "i32.trunc_s/f64"),
|
|
I32TruncUF64 => write!(f, "i32.trunc_u/f64"),
|
|
|
|
I64ExtendSI32 => write!(f, "i64.extend_s/i32"),
|
|
I64ExtendUI32 => write!(f, "i64.extend_u/i32"),
|
|
|
|
I64TruncSF32 => write!(f, "i64.trunc_s/f32"),
|
|
I64TruncUF32 => write!(f, "i64.trunc_u/f32"),
|
|
I64TruncSF64 => write!(f, "i64.trunc_s/f64"),
|
|
I64TruncUF64 => write!(f, "i64.trunc_u/f64"),
|
|
|
|
F32ConvertSI32 => write!(f, "f32.convert_s/i32"),
|
|
F32ConvertUI32 => write!(f, "f32.convert_u/i32"),
|
|
F32ConvertSI64 => write!(f, "f32.convert_s/i64"),
|
|
F32ConvertUI64 => write!(f, "f32.convert_u/i64"),
|
|
F32DemoteF64 => write!(f, "f32.demote/f64"),
|
|
|
|
F64ConvertSI32 => write!(f, "f64.convert_s/i32"),
|
|
F64ConvertUI32 => write!(f, "f64.convert_u/i32"),
|
|
F64ConvertSI64 => write!(f, "f64.convert_s/i64"),
|
|
F64ConvertUI64 => write!(f, "f64.convert_u/i64"),
|
|
F64PromoteF32 => write!(f, "f64.promote/f32"),
|
|
|
|
I32ReinterpretF32 => write!(f, "i32.reinterpret/f32"),
|
|
I64ReinterpretF64 => write!(f, "i64.reinterpret/f64"),
|
|
F32ReinterpretI32 => write!(f, "f32.reinterpret/i32"),
|
|
F64ReinterpretI64 => write!(f, "f64.reinterpret/i64"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Serialize for Opcodes {
|
|
type Error = Error;
|
|
|
|
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
|
for op in self.0.into_iter() {
|
|
op.serialize(writer)?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl Serialize for InitExpr {
|
|
type Error = Error;
|
|
|
|
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
|
for op in self.0.into_iter() {
|
|
op.serialize(writer)?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn ifelse() {
|
|
// see if-else.wast/if-else.wasm
|
|
let opcode = super::deserialize_buffer::<Opcodes>(&[0x04, 0x7F, 0x41, 0x05, 0x05, 0x41, 0x07, 0x0B, 0x0B])
|
|
.expect("valid hex of if instruction");
|
|
let opcodes = opcode.elements();
|
|
match &opcodes[0] {
|
|
&Opcode::If(_) => (),
|
|
_ => panic!("Should be deserialized as if opcode"),
|
|
}
|
|
let before_else = opcodes.iter().skip(1)
|
|
.take_while(|op| match **op { Opcode::Else => false, _ => true }).count();
|
|
let after_else = opcodes.iter().skip(1)
|
|
.skip_while(|op| match **op { Opcode::Else => false, _ => true })
|
|
.take_while(|op| match **op { Opcode::End => false, _ => true })
|
|
.count()
|
|
- 1; // minus Opcode::Else itself
|
|
assert_eq!(before_else, after_else);
|
|
}
|
|
|
|
#[test]
|
|
fn display() {
|
|
let opcode = Opcode::GetLocal(0);
|
|
assert_eq!("get_local 0", format!("{}", opcode));
|
|
|
|
let opcode = Opcode::F64Store(0, 24);
|
|
assert_eq!("f64.store offset=24", format!("{}", opcode));
|
|
|
|
let opcode = Opcode::I64Store(0, 0);
|
|
assert_eq!("i64.store", format!("{}", opcode));
|
|
}
|
|
|
|
#[test]
|
|
fn size_off() {
|
|
assert!(::std::mem::size_of::<Opcode>() <= 24);
|
|
}
|