sophon_wasm/elements/
ops.rs

1use std::{io, fmt};
2use super::{
3    Serialize, Deserialize, Error, VarUint7,
4    VarUint1, VarUint32, CountedList, BlockType,
5    Uint32, Uint64, CountedListWriter,
6    VarInt32, VarInt64,
7};
8
9/// Collection of opcodes (usually inside a block section).
10#[derive(Debug, PartialEq, Clone)]
11pub struct Opcodes(Vec<Opcode>);
12
13impl Opcodes {
14    /// New list of opcodes from vector of opcodes.
15    pub fn new(elements: Vec<Opcode>) -> Self {
16        Opcodes(elements)
17    }
18
19    /// Empty expression with only `Opcode::End` opcode.
20    pub fn empty() -> Self {
21        Opcodes(vec![Opcode::End])
22    }
23
24    /// List of individual opcodes.
25    pub fn elements(&self) -> &[Opcode] { &self.0 }
26
27    /// Individual opcodes, mutable.
28    pub fn elements_mut(&mut self) -> &mut Vec<Opcode> { &mut self.0 }
29}
30
31impl Deserialize for Opcodes {
32    type Error = Error;
33
34    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
35        let mut opcodes = Vec::new();
36        let mut block_count = 1usize;
37
38        loop {
39            let opcode = Opcode::deserialize(reader)?;
40            if opcode.is_terminal() {
41                block_count -= 1;
42            } else if opcode.is_block() {
43                block_count = block_count.checked_add(1).ok_or(Error::Other("too many opcodes"))?;
44            }
45
46            opcodes.push(opcode);
47            if block_count == 0 {
48                break;
49            }
50        }
51
52        Ok(Opcodes(opcodes))
53    }
54}
55
56/// Initialization expression.
57#[derive(Debug, Clone)]
58pub struct InitExpr(Vec<Opcode>);
59
60impl InitExpr {
61    /// New initialization expression from list of opcodes.
62    ///   `code` must end with the `Opcode::End` opcode!
63    pub fn new(code: Vec<Opcode>) -> Self {
64        InitExpr(code)
65    }
66
67    /// Empty expression with only `Opcode::End` opcode
68    pub fn empty() -> Self {
69        InitExpr(vec![Opcode::End])
70    }
71
72    /// List of opcodes used in the expression.
73    pub fn code(&self) -> &[Opcode] {
74        &self.0
75    }
76
77    /// List of opcodes used in the expression.
78    pub fn code_mut(&mut self) -> &mut Vec<Opcode> {
79        &mut self.0
80    }
81}
82
83// todo: check if kind of opcode sequence is valid as an expression
84impl Deserialize for InitExpr {
85    type Error = Error;
86
87    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
88        let mut opcodes = Vec::new();
89
90        loop {
91            let opcode = Opcode::deserialize(reader)?;
92            let is_terminal = opcode.is_terminal();
93            opcodes.push(opcode);
94            if is_terminal {
95                break;
96            }
97        }
98
99        Ok(InitExpr(opcodes))
100    }
101}
102
103/// Opcode
104#[derive(Clone, Debug, PartialEq)]
105#[allow(missing_docs)]
106pub enum Opcode {
107    Unreachable,
108    Nop,
109    Block(BlockType),
110    Loop(BlockType),
111    If(BlockType),
112    Else,
113    End,
114    Br(u32),
115    BrIf(u32),
116    BrTable(Vec<u32>, u32),
117    Return,
118
119    Call(u32),
120    CallIndirect(u32, bool),
121
122    Drop,
123    Select,
124
125    GetLocal(u32),
126    SetLocal(u32),
127    TeeLocal(u32),
128    GetGlobal(u32),
129    SetGlobal(u32),
130
131    // All store/load opcodes operate with 'memory immediates'
132    // which represented here as (flag, offset) tuple
133    I32Load(u32, u32),
134    I64Load(u32, u32),
135    F32Load(u32, u32),
136    F64Load(u32, u32),
137    I32Load8S(u32, u32),
138    I32Load8U(u32, u32),
139    I32Load16S(u32, u32),
140    I32Load16U(u32, u32),
141    I64Load8S(u32, u32),
142    I64Load8U(u32, u32),
143    I64Load16S(u32, u32),
144    I64Load16U(u32, u32),
145    I64Load32S(u32, u32),
146    I64Load32U(u32, u32),
147    I32Store(u32, u32),
148    I64Store(u32, u32),
149    F32Store(u32, u32),
150    F64Store(u32, u32),
151    I32Store8(u32, u32),
152    I32Store16(u32, u32),
153    I64Store8(u32, u32),
154    I64Store16(u32, u32),
155    I64Store32(u32, u32),
156
157    CurrentMemory(bool),
158    GrowMemory(bool),
159
160    I32Const(i32),
161    I64Const(i64),
162    F32Const(u32),
163    F64Const(u64),
164
165    I32Eqz,
166    I32Eq,
167    I32Ne,
168    I32LtS,
169    I32LtU,
170    I32GtS,
171    I32GtU,
172    I32LeS,
173    I32LeU,
174    I32GeS,
175    I32GeU,
176
177    I64Eqz,
178    I64Eq,
179    I64Ne,
180    I64LtS,
181    I64LtU,
182    I64GtS,
183    I64GtU,
184    I64LeS,
185    I64LeU,
186    I64GeS,
187    I64GeU,
188
189    F32Eq,
190    F32Ne,
191    F32Lt,
192    F32Gt,
193    F32Le,
194    F32Ge,
195
196    F64Eq,
197    F64Ne,
198    F64Lt,
199    F64Gt,
200    F64Le,
201    F64Ge,
202
203    I32Clz,
204    I32Ctz,
205    I32Popcnt,
206    I32Add,
207    I32Sub,
208    I32Mul,
209    I32DivS,
210    I32DivU,
211    I32RemS,
212    I32RemU,
213    I32And,
214    I32Or,
215    I32Xor,
216    I32Shl,
217    I32ShrS,
218    I32ShrU,
219    I32Rotl,
220    I32Rotr,
221
222    I64Clz,
223    I64Ctz,
224    I64Popcnt,
225    I64Add,
226    I64Sub,
227    I64Mul,
228    I64DivS,
229    I64DivU,
230    I64RemS,
231    I64RemU,
232    I64And,
233    I64Or,
234    I64Xor,
235    I64Shl,
236    I64ShrS,
237    I64ShrU,
238    I64Rotl,
239    I64Rotr,
240    F32Abs,
241    F32Neg,
242    F32Ceil,
243    F32Floor,
244    F32Trunc,
245    F32Nearest,
246    F32Sqrt,
247    F32Add,
248    F32Sub,
249    F32Mul,
250    F32Div,
251    F32Min,
252    F32Max,
253    F32Copysign,
254    F64Abs,
255    F64Neg,
256    F64Ceil,
257    F64Floor,
258    F64Trunc,
259    F64Nearest,
260    F64Sqrt,
261    F64Add,
262    F64Sub,
263    F64Mul,
264    F64Div,
265    F64Min,
266    F64Max,
267    F64Copysign,
268
269    I32WarpI64,
270    I32TruncSF32,
271    I32TruncUF32,
272    I32TruncSF64,
273    I32TruncUF64,
274    I64ExtendSI32,
275    I64ExtendUI32,
276    I64TruncSF32,
277    I64TruncUF32,
278    I64TruncSF64,
279    I64TruncUF64,
280    F32ConvertSI32,
281    F32ConvertUI32,
282    F32ConvertSI64,
283    F32ConvertUI64,
284    F32DemoteF64,
285    F64ConvertSI32,
286    F64ConvertUI32,
287    F64ConvertSI64,
288    F64ConvertUI64,
289    F64PromoteF32,
290
291    I32ReinterpretF32,
292    I64ReinterpretF64,
293    F32ReinterpretI32,
294    F64ReinterpretI64,
295}
296
297impl Opcode {
298    /// Is this opcode starts the new block (which should end with terminal opcode).
299    pub fn is_block(&self) -> bool {
300        match self {
301            &Opcode::Block(_) | &Opcode::Loop(_) | &Opcode::If(_) => true,
302            _ => false,
303        }
304    }
305
306    /// Is this opcode determines the termination of opcode sequence
307    /// `true` for `Opcode::End`
308    pub fn is_terminal(&self) -> bool {
309        match self {
310            &Opcode::End => true,
311            _ => false,
312        }
313    }
314}
315
316impl Deserialize for Opcode {
317    type Error = Error;
318
319    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
320        use self::Opcode::*;
321
322        let val: u8 = VarUint7::deserialize(reader)?.into();
323
324        Ok(
325            match val {
326                0x00 => Unreachable,
327                0x01 => Nop,
328                0x02 => Block(BlockType::deserialize(reader)?),
329                0x03 => Loop(BlockType::deserialize(reader)?),
330                0x04 => If(BlockType::deserialize(reader)?),
331                0x05 => Else,
332                0x0b => End,
333
334                0x0c => Br(VarUint32::deserialize(reader)?.into()),
335                0x0d => BrIf(VarUint32::deserialize(reader)?.into()),
336                0x0e => {
337                    let t1: Vec<u32> = CountedList::<VarUint32>::deserialize(reader)?
338                        .into_inner()
339                        .into_iter()
340                        .map(Into::into)
341                        .collect();
342
343                    BrTable(t1, VarUint32::deserialize(reader)?.into())
344                },
345                0x0f => Return,
346                0x10 => Call(VarUint32::deserialize(reader)?.into()),
347                0x11 => CallIndirect(
348                    VarUint32::deserialize(reader)?.into(),
349                    VarUint1::deserialize(reader)?.into()),
350                0x1a => Drop,
351                0x1b => Select,
352
353                0x20 => GetLocal(VarUint32::deserialize(reader)?.into()),
354                0x21 => SetLocal(VarUint32::deserialize(reader)?.into()),
355                0x22 => TeeLocal(VarUint32::deserialize(reader)?.into()),
356                0x23 => GetGlobal(VarUint32::deserialize(reader)?.into()),
357                0x24 => SetGlobal(VarUint32::deserialize(reader)?.into()),
358
359                0x28 => I32Load(
360                    VarUint32::deserialize(reader)?.into(),
361                    VarUint32::deserialize(reader)?.into()),
362
363                0x29 => I64Load(
364                    VarUint32::deserialize(reader)?.into(),
365                    VarUint32::deserialize(reader)?.into()),
366
367                0x2a => F32Load(
368                    VarUint32::deserialize(reader)?.into(),
369                    VarUint32::deserialize(reader)?.into()),
370
371                0x2b => F64Load(
372                    VarUint32::deserialize(reader)?.into(),
373                    VarUint32::deserialize(reader)?.into()),
374
375                0x2c => I32Load8S(
376                    VarUint32::deserialize(reader)?.into(),
377                    VarUint32::deserialize(reader)?.into()),
378
379                0x2d => I32Load8U(
380                    VarUint32::deserialize(reader)?.into(),
381                    VarUint32::deserialize(reader)?.into()),
382
383                0x2e => I32Load16S(
384                    VarUint32::deserialize(reader)?.into(),
385                    VarUint32::deserialize(reader)?.into()),
386
387                0x2f => I32Load16U(
388                    VarUint32::deserialize(reader)?.into(),
389                    VarUint32::deserialize(reader)?.into()),
390
391                0x30 => I64Load8S(
392                    VarUint32::deserialize(reader)?.into(),
393                    VarUint32::deserialize(reader)?.into()),
394
395                0x31 => I64Load8U(
396                    VarUint32::deserialize(reader)?.into(),
397                    VarUint32::deserialize(reader)?.into()),
398
399                0x32 => I64Load16S(
400                    VarUint32::deserialize(reader)?.into(),
401                    VarUint32::deserialize(reader)?.into()),
402
403                0x33 => I64Load16U(
404                    VarUint32::deserialize(reader)?.into(),
405                    VarUint32::deserialize(reader)?.into()),
406
407                0x34 => I64Load32S(
408                    VarUint32::deserialize(reader)?.into(),
409                    VarUint32::deserialize(reader)?.into()),
410
411                0x35 => I64Load32U(
412                    VarUint32::deserialize(reader)?.into(),
413                    VarUint32::deserialize(reader)?.into()),
414
415                0x36 => I32Store(
416                    VarUint32::deserialize(reader)?.into(),
417                    VarUint32::deserialize(reader)?.into()),
418
419                0x37 => I64Store(
420                    VarUint32::deserialize(reader)?.into(),
421                    VarUint32::deserialize(reader)?.into()),
422
423                0x38 => F32Store(
424                    VarUint32::deserialize(reader)?.into(),
425                    VarUint32::deserialize(reader)?.into()),
426
427                0x39 => F64Store(
428                    VarUint32::deserialize(reader)?.into(),
429                    VarUint32::deserialize(reader)?.into()),
430
431                0x3a => I32Store8(
432                    VarUint32::deserialize(reader)?.into(),
433                    VarUint32::deserialize(reader)?.into()),
434
435                0x3b => I32Store16(
436                    VarUint32::deserialize(reader)?.into(),
437                    VarUint32::deserialize(reader)?.into()),
438
439                0x3c => I64Store8(
440                    VarUint32::deserialize(reader)?.into(),
441                    VarUint32::deserialize(reader)?.into()),
442
443                0x3d => I64Store16(
444                    VarUint32::deserialize(reader)?.into(),
445                    VarUint32::deserialize(reader)?.into()),
446
447                0x3e => I64Store32(
448                    VarUint32::deserialize(reader)?.into(),
449                    VarUint32::deserialize(reader)?.into()),
450
451
452                0x3f => CurrentMemory(VarUint1::deserialize(reader)?.into()),
453                0x40 => GrowMemory(VarUint1::deserialize(reader)?.into()),
454
455                0x41 => I32Const(VarInt32::deserialize(reader)?.into()),
456                0x42 => I64Const(VarInt64::deserialize(reader)?.into()),
457                0x43 => F32Const(Uint32::deserialize(reader)?.into()),
458                0x44 => F64Const(Uint64::deserialize(reader)?.into()),
459                0x45 => I32Eqz,
460                0x46 => I32Eq,
461                0x47 => I32Ne,
462                0x48 => I32LtS,
463                0x49 => I32LtU,
464                0x4a => I32GtS,
465                0x4b => I32GtU,
466                0x4c => I32LeS,
467                0x4d => I32LeU,
468                0x4e => I32GeS,
469                0x4f => I32GeU,
470
471                0x50 => I64Eqz,
472                0x51 => I64Eq,
473                0x52 => I64Ne,
474                0x53 => I64LtS,
475                0x54 => I64LtU,
476                0x55 => I64GtS,
477                0x56 => I64GtU,
478                0x57 => I64LeS,
479                0x58 => I64LeU,
480                0x59 => I64GeS,
481                0x5a => I64GeU,
482
483                0x5b => F32Eq,
484                0x5c => F32Ne,
485                0x5d => F32Lt,
486                0x5e => F32Gt,
487                0x5f => F32Le,
488                0x60 => F32Ge,
489
490                0x61 => F64Eq,
491                0x62 => F64Ne,
492                0x63 => F64Lt,
493                0x64 => F64Gt,
494                0x65 => F64Le,
495                0x66 => F64Ge,
496
497                0x67 => I32Clz,
498                0x68 => I32Ctz,
499                0x69 => I32Popcnt,
500                0x6a => I32Add,
501                0x6b => I32Sub,
502                0x6c => I32Mul,
503                0x6d => I32DivS,
504                0x6e => I32DivU,
505                0x6f => I32RemS,
506                0x70 => I32RemU,
507                0x71 => I32And,
508                0x72 => I32Or,
509                0x73 => I32Xor,
510                0x74 => I32Shl,
511                0x75 => I32ShrS,
512                0x76 => I32ShrU,
513                0x77 => I32Rotl,
514                0x78 => I32Rotr,
515
516                0x79 => I64Clz,
517                0x7a => I64Ctz,
518                0x7b => I64Popcnt,
519                0x7c => I64Add,
520                0x7d => I64Sub,
521                0x7e => I64Mul,
522                0x7f => I64DivS,
523                0x80 => I64DivU,
524                0x81 => I64RemS,
525                0x82 => I64RemU,
526                0x83 => I64And,
527                0x84 => I64Or,
528                0x85 => I64Xor,
529                0x86 => I64Shl,
530                0x87 => I64ShrS,
531                0x88 => I64ShrU,
532                0x89 => I64Rotl,
533                0x8a => I64Rotr,
534                0x8b => F32Abs,
535                0x8c => F32Neg,
536                0x8d => F32Ceil,
537                0x8e => F32Floor,
538                0x8f => F32Trunc,
539                0x90 => F32Nearest,
540                0x91 => F32Sqrt,
541                0x92 => F32Add,
542                0x93 => F32Sub,
543                0x94 => F32Mul,
544                0x95 => F32Div,
545                0x96 => F32Min,
546                0x97 => F32Max,
547                0x98 => F32Copysign,
548                0x99 => F64Abs,
549                0x9a => F64Neg,
550                0x9b => F64Ceil,
551                0x9c => F64Floor,
552                0x9d => F64Trunc,
553                0x9e => F64Nearest,
554                0x9f => F64Sqrt,
555                0xa0 => F64Add,
556                0xa1 => F64Sub,
557                0xa2 => F64Mul,
558                0xa3 => F64Div,
559                0xa4 => F64Min,
560                0xa5 => F64Max,
561                0xa6 => F64Copysign,
562
563                0xa7 => I32WarpI64,
564                0xa8 => I32TruncSF32,
565                0xa9 => I32TruncUF32,
566                0xaa => I32TruncSF64,
567                0xab => I32TruncUF64,
568                0xac => I64ExtendSI32,
569                0xad => I64ExtendUI32,
570                0xae => I64TruncSF32,
571                0xaf => I64TruncUF32,
572                0xb0 => I64TruncSF64,
573                0xb1 => I64TruncUF64,
574                0xb2 => F32ConvertSI32,
575                0xb3 => F32ConvertUI32,
576                0xb4 => F32ConvertSI64,
577                0xb5 => F32ConvertUI64,
578                0xb6 => F32DemoteF64,
579                0xb7 => F64ConvertSI32,
580                0xb8 => F64ConvertUI32,
581                0xb9 => F64ConvertSI64,
582                0xba => F64ConvertUI64,
583                0xbb => F64PromoteF32,
584
585                0xbc => I32ReinterpretF32,
586                0xbd => I64ReinterpretF64,
587                0xbe => F32ReinterpretI32,
588                0xbf => F64ReinterpretI64,
589
590                _ => { return Err(Error::UnknownOpcode(val)); }
591            }
592        )
593    }
594}
595
596macro_rules! op {
597    ($writer: expr, $byte: expr) => ({
598        let b: u8 = $byte;
599        $writer.write_all(&[b])?;
600    });
601    ($writer: expr, $byte: expr, $s: block) => ({
602        op!($writer, $byte);
603        $s;
604    });
605}
606
607impl Serialize for Opcode {
608    type Error = Error;
609
610    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
611        use self::Opcode::*;
612
613        match self {
614            Unreachable => op!(writer, 0x00),
615            Nop => op!(writer, 0x01),
616            Block(block_type) => op!(writer, 0x02, {
617               block_type.serialize(writer)?;
618            }),
619            Loop(block_type) => op!(writer, 0x03, {
620               block_type.serialize(writer)?;
621            }),
622            If(block_type) => op!(writer, 0x04, {
623               block_type.serialize(writer)?;
624            }),
625            Else => op!(writer, 0x05),
626            End => op!(writer, 0x0b),
627            Br(idx) => op!(writer, 0x0c, {
628                VarUint32::from(idx).serialize(writer)?;
629            }),
630            BrIf(idx) => op!(writer, 0x0d, {
631                VarUint32::from(idx).serialize(writer)?;
632            }),
633            BrTable(table, default) => op!(writer, 0x0e, {
634                let list_writer = CountedListWriter::<VarUint32, _>(
635                    table.len(),
636                    table.into_iter().map(Into::into),
637                );
638                list_writer.serialize(writer)?;
639                VarUint32::from(default).serialize(writer)?;
640            }),
641            Return => op!(writer, 0x0f),
642            Call(index) => op!(writer, 0x10, {
643                VarUint32::from(index).serialize(writer)?;
644            }),
645            CallIndirect(index, reserved) => op!(writer, 0x11, {
646                VarUint32::from(index).serialize(writer)?;
647                VarUint1::from(reserved).serialize(writer)?;
648            }),
649            Drop => op!(writer, 0x1a),
650            Select => op!(writer, 0x1b),
651            GetLocal(index) => op!(writer, 0x20, {
652                VarUint32::from(index).serialize(writer)?;
653            }),
654            SetLocal(index) => op!(writer, 0x21, {
655                VarUint32::from(index).serialize(writer)?;
656            }),
657            TeeLocal(index) => op!(writer, 0x22, {
658                VarUint32::from(index).serialize(writer)?;
659            }),
660            GetGlobal(index) => op!(writer, 0x23, {
661                VarUint32::from(index).serialize(writer)?;
662            }),
663            SetGlobal(index) => op!(writer, 0x24, {
664                VarUint32::from(index).serialize(writer)?;
665            }),
666            I32Load(flags, offset) => op!(writer, 0x28, {
667                VarUint32::from(flags).serialize(writer)?;
668                VarUint32::from(offset).serialize(writer)?;
669            }),
670            I64Load(flags, offset) => op!(writer, 0x29, {
671                VarUint32::from(flags).serialize(writer)?;
672                VarUint32::from(offset).serialize(writer)?;
673            }),
674            F32Load(flags, offset) => op!(writer, 0x2a, {
675                VarUint32::from(flags).serialize(writer)?;
676                VarUint32::from(offset).serialize(writer)?;
677            }),
678            F64Load(flags, offset) => op!(writer, 0x2b, {
679                VarUint32::from(flags).serialize(writer)?;
680                VarUint32::from(offset).serialize(writer)?;
681            }),
682            I32Load8S(flags, offset) => op!(writer, 0x2c, {
683                VarUint32::from(flags).serialize(writer)?;
684                VarUint32::from(offset).serialize(writer)?;
685            }),
686            I32Load8U(flags, offset) => op!(writer, 0x2d, {
687                VarUint32::from(flags).serialize(writer)?;
688                VarUint32::from(offset).serialize(writer)?;
689            }),
690            I32Load16S(flags, offset) => op!(writer, 0x2e, {
691                VarUint32::from(flags).serialize(writer)?;
692                VarUint32::from(offset).serialize(writer)?;
693            }),
694            I32Load16U(flags, offset) => op!(writer, 0x2f, {
695                VarUint32::from(flags).serialize(writer)?;
696                VarUint32::from(offset).serialize(writer)?;
697            }),
698            I64Load8S(flags, offset) => op!(writer, 0x30, {
699                VarUint32::from(flags).serialize(writer)?;
700                VarUint32::from(offset).serialize(writer)?;
701            }),
702            I64Load8U(flags, offset) => op!(writer, 0x31, {
703                VarUint32::from(flags).serialize(writer)?;
704                VarUint32::from(offset).serialize(writer)?;
705            }),
706            I64Load16S(flags, offset) => op!(writer, 0x32, {
707                VarUint32::from(flags).serialize(writer)?;
708                VarUint32::from(offset).serialize(writer)?;
709            }),
710            I64Load16U(flags, offset) => op!(writer, 0x33, {
711                VarUint32::from(flags).serialize(writer)?;
712                VarUint32::from(offset).serialize(writer)?;
713            }),
714            I64Load32S(flags, offset) => op!(writer, 0x34, {
715                VarUint32::from(flags).serialize(writer)?;
716                VarUint32::from(offset).serialize(writer)?;
717            }),
718            I64Load32U(flags, offset) => op!(writer, 0x35, {
719                VarUint32::from(flags).serialize(writer)?;
720                VarUint32::from(offset).serialize(writer)?;
721            }),
722            I32Store(flags, offset) => op!(writer, 0x36, {
723                VarUint32::from(flags).serialize(writer)?;
724                VarUint32::from(offset).serialize(writer)?;
725            }),
726            I64Store(flags, offset) => op!(writer, 0x37, {
727                VarUint32::from(flags).serialize(writer)?;
728                VarUint32::from(offset).serialize(writer)?;
729            }),
730            F32Store(flags, offset) => op!(writer, 0x38, {
731                VarUint32::from(flags).serialize(writer)?;
732                VarUint32::from(offset).serialize(writer)?;
733            }),
734            F64Store(flags, offset) => op!(writer, 0x39, {
735                VarUint32::from(flags).serialize(writer)?;
736                VarUint32::from(offset).serialize(writer)?;
737            }),
738            I32Store8(flags, offset) => op!(writer, 0x3a, {
739                VarUint32::from(flags).serialize(writer)?;
740                VarUint32::from(offset).serialize(writer)?;
741            }),
742            I32Store16(flags, offset) => op!(writer, 0x3b, {
743                VarUint32::from(flags).serialize(writer)?;
744                VarUint32::from(offset).serialize(writer)?;
745            }),
746            I64Store8(flags, offset) => op!(writer, 0x3c, {
747                VarUint32::from(flags).serialize(writer)?;
748                VarUint32::from(offset).serialize(writer)?;
749            }),
750            I64Store16(flags, offset) => op!(writer, 0x3d, {
751                VarUint32::from(flags).serialize(writer)?;
752                VarUint32::from(offset).serialize(writer)?;
753            }),
754            I64Store32(flags, offset) => op!(writer, 0x3e, {
755                VarUint32::from(flags).serialize(writer)?;
756                VarUint32::from(offset).serialize(writer)?;
757            }),
758            CurrentMemory(flag) => op!(writer, 0x3f, {
759                VarUint1::from(flag).serialize(writer)?;
760            }),
761            GrowMemory(flag) => op!(writer, 0x40, {
762                VarUint1::from(flag).serialize(writer)?;
763            }),
764            I32Const(def) => op!(writer, 0x41, {
765                VarInt32::from(def).serialize(writer)?;
766            }),
767            I64Const(def) => op!(writer, 0x42, {
768                VarInt64::from(def).serialize(writer)?;
769            }),
770            F32Const(def) => op!(writer, 0x43, {
771                Uint32::from(def).serialize(writer)?;
772            }),
773            F64Const(def) => op!(writer, 0x44, {
774                Uint64::from(def).serialize(writer)?;
775            }),
776            I32Eqz => op!(writer, 0x45),
777            I32Eq => op!(writer, 0x46),
778            I32Ne => op!(writer, 0x47),
779            I32LtS => op!(writer, 0x48),
780            I32LtU => op!(writer, 0x49),
781            I32GtS => op!(writer, 0x4a),
782            I32GtU => op!(writer, 0x4b),
783            I32LeS => op!(writer, 0x4c),
784            I32LeU => op!(writer, 0x4d),
785            I32GeS => op!(writer, 0x4e),
786            I32GeU => op!(writer, 0x4f),
787
788            I64Eqz => op!(writer, 0x50),
789            I64Eq => op!(writer, 0x51),
790            I64Ne => op!(writer, 0x52),
791            I64LtS => op!(writer, 0x53),
792            I64LtU => op!(writer, 0x54),
793            I64GtS => op!(writer, 0x55),
794            I64GtU => op!(writer, 0x56),
795            I64LeS => op!(writer, 0x57),
796            I64LeU => op!(writer, 0x58),
797            I64GeS => op!(writer, 0x59),
798            I64GeU => op!(writer, 0x5a),
799
800            F32Eq => op!(writer, 0x5b),
801            F32Ne => op!(writer, 0x5c),
802            F32Lt => op!(writer, 0x5d),
803            F32Gt => op!(writer, 0x5e),
804            F32Le => op!(writer, 0x5f),
805            F32Ge => op!(writer, 0x60),
806
807            F64Eq => op!(writer, 0x61),
808            F64Ne => op!(writer, 0x62),
809            F64Lt => op!(writer, 0x63),
810            F64Gt => op!(writer, 0x64),
811            F64Le => op!(writer, 0x65),
812            F64Ge => op!(writer, 0x66),
813
814            I32Clz => op!(writer, 0x67),
815            I32Ctz => op!(writer, 0x68),
816            I32Popcnt => op!(writer, 0x69),
817            I32Add => op!(writer, 0x6a),
818            I32Sub => op!(writer, 0x6b),
819            I32Mul => op!(writer, 0x6c),
820            I32DivS => op!(writer, 0x6d),
821            I32DivU => op!(writer, 0x6e),
822            I32RemS => op!(writer, 0x6f),
823            I32RemU => op!(writer, 0x70),
824            I32And => op!(writer, 0x71),
825            I32Or => op!(writer, 0x72),
826            I32Xor => op!(writer, 0x73),
827            I32Shl => op!(writer, 0x74),
828            I32ShrS => op!(writer, 0x75),
829            I32ShrU => op!(writer, 0x76),
830            I32Rotl => op!(writer, 0x77),
831            I32Rotr => op!(writer, 0x78),
832
833            I64Clz => op!(writer, 0x79),
834            I64Ctz => op!(writer, 0x7a),
835            I64Popcnt => op!(writer, 0x7b),
836            I64Add => op!(writer, 0x7c),
837            I64Sub => op!(writer, 0x7d),
838            I64Mul => op!(writer, 0x7e),
839            I64DivS => op!(writer, 0x7f),
840            I64DivU => op!(writer, 0x80),
841            I64RemS => op!(writer, 0x81),
842            I64RemU => op!(writer, 0x82),
843            I64And => op!(writer, 0x83),
844            I64Or => op!(writer, 0x84),
845            I64Xor => op!(writer, 0x85),
846            I64Shl => op!(writer, 0x86),
847            I64ShrS => op!(writer, 0x87),
848            I64ShrU => op!(writer, 0x88),
849            I64Rotl => op!(writer, 0x89),
850            I64Rotr => op!(writer, 0x8a),
851            F32Abs => op!(writer, 0x8b),
852            F32Neg => op!(writer, 0x8c),
853            F32Ceil => op!(writer, 0x8d),
854            F32Floor => op!(writer, 0x8e),
855            F32Trunc => op!(writer, 0x8f),
856            F32Nearest => op!(writer, 0x90),
857            F32Sqrt => op!(writer, 0x91),
858            F32Add => op!(writer, 0x92),
859            F32Sub => op!(writer, 0x93),
860            F32Mul => op!(writer, 0x94),
861            F32Div => op!(writer, 0x95),
862            F32Min => op!(writer, 0x96),
863            F32Max => op!(writer, 0x97),
864            F32Copysign => op!(writer, 0x98),
865            F64Abs => op!(writer, 0x99),
866            F64Neg => op!(writer, 0x9a),
867            F64Ceil => op!(writer, 0x9b),
868            F64Floor => op!(writer, 0x9c),
869            F64Trunc => op!(writer, 0x9d),
870            F64Nearest => op!(writer, 0x9e),
871            F64Sqrt => op!(writer, 0x9f),
872            F64Add => op!(writer, 0xa0),
873            F64Sub => op!(writer, 0xa1),
874            F64Mul => op!(writer, 0xa2),
875            F64Div => op!(writer, 0xa3),
876            F64Min => op!(writer, 0xa4),
877            F64Max => op!(writer, 0xa5),
878            F64Copysign => op!(writer, 0xa6),
879
880            I32WarpI64 => op!(writer, 0xa7),
881            I32TruncSF32 => op!(writer, 0xa8),
882            I32TruncUF32 => op!(writer, 0xa9),
883            I32TruncSF64 => op!(writer, 0xaa),
884            I32TruncUF64 => op!(writer, 0xab),
885            I64ExtendSI32 => op!(writer, 0xac),
886            I64ExtendUI32 => op!(writer, 0xad),
887            I64TruncSF32 => op!(writer, 0xae),
888            I64TruncUF32 => op!(writer, 0xaf),
889            I64TruncSF64 => op!(writer, 0xb0),
890            I64TruncUF64 => op!(writer, 0xb1),
891            F32ConvertSI32 => op!(writer, 0xb2),
892            F32ConvertUI32 => op!(writer, 0xb3),
893            F32ConvertSI64 => op!(writer, 0xb4),
894            F32ConvertUI64 => op!(writer, 0xb5),
895            F32DemoteF64 => op!(writer, 0xb6),
896            F64ConvertSI32 => op!(writer, 0xb7),
897            F64ConvertUI32 => op!(writer, 0xb8),
898            F64ConvertSI64 => op!(writer, 0xb9),
899            F64ConvertUI64 => op!(writer, 0xba),
900            F64PromoteF32 => op!(writer, 0xbb),
901
902            I32ReinterpretF32 => op!(writer, 0xbc),
903            I64ReinterpretF64 => op!(writer, 0xbd),
904            F32ReinterpretI32 => op!(writer, 0xbe),
905            F64ReinterpretI64 => op!(writer, 0xbf),
906        }
907
908        Ok(())
909    }
910}
911
912macro_rules! fmt_op {
913    ($f: expr, $mnemonic: expr) => ({
914        write!($f, "{}", $mnemonic)
915    });
916    ($f: expr, $mnemonic: expr, $immediate: expr) => ({
917        write!($f, "{} {}", $mnemonic, $immediate)
918    });
919    ($f: expr, $mnemonic: expr, $immediate1: expr, $immediate2: expr) => ({
920        write!($f, "{} {} {}", $mnemonic, $immediate1, $immediate2)
921    });
922}
923
924impl fmt::Display for Opcode {
925    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
926        use self::Opcode::*;
927        use super::BlockType;
928
929        match *self {
930            Unreachable => fmt_op!(f, "unreachable"),
931            Nop => fmt_op!(f, "nop"),
932            Block(BlockType::NoResult) => fmt_op!(f, "block"),
933            Block(BlockType::Value(value_type)) => fmt_op!(f, "block", value_type),
934            Loop(BlockType::NoResult) => fmt_op!(f, "loop"),
935            Loop(BlockType::Value(value_type)) => fmt_op!(f, "loop", value_type),
936            If(BlockType::NoResult) => fmt_op!(f, "if"),
937            If(BlockType::Value(value_type)) => fmt_op!(f, "if", value_type),
938            Else => fmt_op!(f, "else"),
939            End => fmt_op!(f, "end"),
940            Br(idx) => fmt_op!(f, "br",  idx),
941            BrIf(idx) => fmt_op!(f, "br_if",  idx),
942            BrTable(_, default) => fmt_op!(f, "br_table", default),
943            Return => fmt_op!(f, "return"),
944            Call(index) => fmt_op!(f, "call", index),
945            CallIndirect(index, _) =>  fmt_op!(f, "call_indirect", index),
946            Drop => fmt_op!(f, "drop"),
947            Select => fmt_op!(f, "select"),
948            GetLocal(index) => fmt_op!(f, "get_local", index),
949            SetLocal(index) => fmt_op!(f, "set_local", index),
950            TeeLocal(index) => fmt_op!(f, "tee_local", index),
951            GetGlobal(index) => fmt_op!(f, "get_global", index),
952            SetGlobal(index) => fmt_op!(f, "set_global", index),
953
954            I32Load(_, 0) => write!(f, "i32.load"),
955            I32Load(_, offset) => write!(f, "i32.load offset={}", offset),
956
957            I64Load(_, 0) => write!(f, "i64.load"),
958            I64Load(_, offset) => write!(f, "i64.load offset={}", offset),
959
960            F32Load(_, 0) => write!(f, "f32.load"),
961            F32Load(_, offset) => write!(f, "f32.load offset={}", offset),
962
963            F64Load(_, 0) => write!(f, "f64.load"),
964            F64Load(_, offset) => write!(f, "f64.load offset={}", offset),
965
966            I32Load8S(_, 0) => write!(f, "i32.load8_s"),
967            I32Load8S(_, offset) => write!(f, "i32.load8_s offset={}", offset),
968
969            I32Load8U(_, 0) => write!(f, "i32.load8_u"),
970            I32Load8U(_, offset) => write!(f, "i32.load8_u offset={}", offset),
971
972            I32Load16S(_, 0) => write!(f, "i32.load16_s"),
973            I32Load16S(_, offset) => write!(f, "i32.load16_s offset={}", offset),
974
975            I32Load16U(_, 0) => write!(f, "i32.load16_u"),
976            I32Load16U(_, offset) => write!(f, "i32.load16_u offset={}", offset),
977
978            I64Load8S(_, 0) => write!(f, "i64.load8_s"),
979            I64Load8S(_, offset) => write!(f, "i64.load8_s offset={}", offset),
980
981            I64Load8U(_, 0) => write!(f, "i64.load8_u"),
982            I64Load8U(_, offset) => write!(f, "i64.load8_u offset={}", offset),
983
984            I64Load16S(_, 0) => write!(f, "i64.load16_s"),
985            I64Load16S(_, offset) => write!(f, "i64.load16_s offset={}", offset),
986
987            I64Load16U(_, 0) => write!(f, "i64.load16_u"),
988            I64Load16U(_, offset) => write!(f, "i64.load16_u offset={}", offset),
989
990            I64Load32S(_, 0) => write!(f, "i64.load32_s"),
991            I64Load32S(_, offset) => write!(f, "i64.load32_s offset={}", offset),
992
993            I64Load32U(_, 0) => write!(f, "i64.load32_u"),
994            I64Load32U(_, offset) => write!(f, "i64.load32_u offset={}", offset),
995
996            I32Store(_, 0) => write!(f, "i32.store"),
997            I32Store(_, offset) => write!(f, "i32.store offset={}", offset),
998
999            I64Store(_, 0) => write!(f, "i64.store"),
1000            I64Store(_, offset) => write!(f, "i64.store offset={}", offset),
1001
1002            F32Store(_, 0) => write!(f, "f32.store"),
1003            F32Store(_, offset) => write!(f, "f32.store offset={}", offset),
1004
1005            F64Store(_, 0) => write!(f, "f64.store"),
1006            F64Store(_, offset) => write!(f, "f64.store offset={}", offset),
1007
1008            I32Store8(_, 0) => write!(f, "i32.store8"),
1009            I32Store8(_, offset) => write!(f, "i32.store8 offset={}", offset),
1010
1011            I32Store16(_, 0) => write!(f, "i32.store16"),
1012            I32Store16(_, offset) => write!(f, "i32.store16 offset={}", offset),
1013
1014            I64Store8(_, 0) => write!(f, "i64.store8"),
1015            I64Store8(_, offset) => write!(f, "i64.store8 offset={}", offset),
1016
1017            I64Store16(_, 0) => write!(f, "i64.store16"),
1018            I64Store16(_, offset) => write!(f, "i64.store16 offset={}", offset),
1019
1020            I64Store32(_, 0) => write!(f, "i64.store32"),
1021            I64Store32(_, offset) => write!(f, "i64.store32 offset={}", offset),
1022
1023            CurrentMemory(_) => fmt_op!(f, "current_memory"),
1024            GrowMemory(_) => fmt_op!(f, "grow_memory"),
1025
1026            I32Const(def) => fmt_op!(f, "i32.const", def),
1027            I64Const(def) => fmt_op!(f, "i64.const", def),
1028            F32Const(def) => fmt_op!(f, "f32.const", def),
1029            F64Const(def) => fmt_op!(f, "f64.const", def),
1030
1031            I32Eq => write!(f, "i32.eq"),
1032            I32Eqz => write!(f, "i32.eqz"),
1033            I32Ne => write!(f, "i32.ne"),
1034            I32LtS => write!(f, "i32.lt_s"),
1035            I32LtU => write!(f, "i32.lt_u"),
1036            I32GtS => write!(f, "i32.gt_s"),
1037            I32GtU => write!(f, "i32.gt_u"),
1038            I32LeS => write!(f, "i32.le_s"),
1039            I32LeU => write!(f, "i32.le_u"),
1040            I32GeS => write!(f, "i32.ge_s"),
1041            I32GeU => write!(f, "i32.ge_u"),
1042
1043            I64Eq => write!(f, "i64.eq"),
1044            I64Eqz => write!(f, "i64.eqz"),
1045            I64Ne => write!(f, "i64.ne"),
1046            I64LtS => write!(f, "i64.lt_s"),
1047            I64LtU => write!(f, "i64.lt_u"),
1048            I64GtS => write!(f, "i64.gt_s"),
1049            I64GtU => write!(f, "i64.gt_u"),
1050            I64LeS => write!(f, "i64.le_s"),
1051            I64LeU => write!(f, "i64.le_u"),
1052            I64GeS => write!(f, "i64.ge_s"),
1053            I64GeU => write!(f, "i64.ge_u"),
1054
1055            F32Eq => write!(f, "f32.eq"),
1056            F32Ne => write!(f, "f32.ne"),
1057            F32Lt => write!(f, "f32.lt"),
1058            F32Gt => write!(f, "f32.gt"),
1059            F32Le => write!(f, "f32.le"),
1060            F32Ge => write!(f, "f32.ge"),
1061
1062            F64Eq => write!(f, "f64.eq"),
1063            F64Ne => write!(f, "f64.ne"),
1064            F64Lt => write!(f, "f64.lt"),
1065            F64Gt => write!(f, "f64.gt"),
1066            F64Le => write!(f, "f64.le"),
1067            F64Ge => write!(f, "f64.ge"),
1068
1069            I32Clz => write!(f, "i32.clz"),
1070            I32Ctz => write!(f, "i32.ctz"),
1071            I32Popcnt => write!(f, "i32.popcnt"),
1072            I32Add => write!(f, "i32.add"),
1073            I32Sub => write!(f, "i32.sub"),
1074            I32Mul => write!(f, "i32.mul"),
1075            I32DivS => write!(f, "i32.div_s"),
1076            I32DivU => write!(f, "i32.div_u"),
1077            I32RemS => write!(f, "i32.rem_s"),
1078            I32RemU => write!(f, "i32.rem_u"),
1079            I32And => write!(f, "i32.and"),
1080            I32Or => write!(f, "i32.or"),
1081            I32Xor => write!(f, "i32.xor"),
1082            I32Shl => write!(f, "i32.shl"),
1083            I32ShrS => write!(f, "i32.shr_s"),
1084            I32ShrU => write!(f, "i32.shr_u"),
1085            I32Rotl => write!(f, "i32.rotl"),
1086            I32Rotr => write!(f, "i32.rotr"),
1087
1088            I64Clz => write!(f, "i64.clz"),
1089            I64Ctz => write!(f, "i64.ctz"),
1090            I64Popcnt => write!(f, "i64.popcnt"),
1091            I64Add => write!(f, "i64.add"),
1092            I64Sub => write!(f, "i64.sub"),
1093            I64Mul => write!(f, "i64.mul"),
1094            I64DivS => write!(f, "i64.div_s"),
1095            I64DivU => write!(f, "i64.div_u"),
1096            I64RemS => write!(f, "i64.rem_s"),
1097            I64RemU => write!(f, "i64.rem_u"),
1098            I64And => write!(f, "i64.and"),
1099            I64Or => write!(f, "i64.or"),
1100            I64Xor => write!(f, "i64.xor"),
1101            I64Shl => write!(f, "i64.shl"),
1102            I64ShrS => write!(f, "i64.shr_s"),
1103            I64ShrU => write!(f, "i64.shr_u"),
1104            I64Rotl => write!(f, "i64.rotl"),
1105            I64Rotr => write!(f, "i64.rotr"),
1106
1107            F32Abs => write!(f, "f32.abs"),
1108            F32Neg => write!(f, "f32.neg"),
1109            F32Ceil => write!(f, "f32.ceil"),
1110            F32Floor => write!(f, "f32.floor"),
1111            F32Trunc => write!(f, "f32.trunc"),
1112            F32Nearest => write!(f, "f32.nearest"),
1113            F32Sqrt => write!(f, "f32.sqrt"),
1114            F32Add => write!(f, "f32.add"),
1115            F32Sub => write!(f, "f32.sub"),
1116            F32Mul => write!(f, "f32.mul"),
1117            F32Div => write!(f, "f32.div"),
1118            F32Min => write!(f, "f32.min"),
1119            F32Max => write!(f, "f32.max"),
1120            F32Copysign => write!(f, "f32.copysign"),
1121
1122            F64Abs => write!(f, "f64.abs"),
1123            F64Neg => write!(f, "f64.neg"),
1124            F64Ceil => write!(f, "f64.ceil"),
1125            F64Floor => write!(f, "f64.floor"),
1126            F64Trunc => write!(f, "f64.trunc"),
1127            F64Nearest => write!(f, "f64.nearest"),
1128            F64Sqrt => write!(f, "f64.sqrt"),
1129            F64Add => write!(f, "f64.add"),
1130            F64Sub => write!(f, "f64.sub"),
1131            F64Mul => write!(f, "f64.mul"),
1132            F64Div => write!(f, "f64.div"),
1133            F64Min => write!(f, "f64.min"),
1134            F64Max => write!(f, "f64.max"),
1135            F64Copysign => write!(f, "f64.copysign"),
1136
1137            I32WarpI64 => write!(f, "i32.wrap/i64"),
1138            I32TruncSF32 => write!(f, "i32.trunc_s/f32"),
1139            I32TruncUF32 => write!(f, "i32.trunc_u/f32"),
1140            I32TruncSF64 => write!(f, "i32.trunc_s/f64"),
1141            I32TruncUF64 => write!(f, "i32.trunc_u/f64"),
1142
1143            I64ExtendSI32 => write!(f, "i64.extend_s/i32"),
1144            I64ExtendUI32 => write!(f, "i64.extend_u/i32"),
1145
1146            I64TruncSF32 => write!(f, "i64.trunc_s/f32"),
1147            I64TruncUF32 => write!(f, "i64.trunc_u/f32"),
1148            I64TruncSF64 => write!(f, "i64.trunc_s/f64"),
1149            I64TruncUF64 => write!(f, "i64.trunc_u/f64"),
1150
1151            F32ConvertSI32 => write!(f, "f32.convert_s/i32"),
1152            F32ConvertUI32 => write!(f, "f32.convert_u/i32"),
1153            F32ConvertSI64 => write!(f, "f32.convert_s/i64"),
1154            F32ConvertUI64 => write!(f, "f32.convert_u/i64"),
1155            F32DemoteF64 => write!(f, "f32.demote/f64"),
1156
1157            F64ConvertSI32 => write!(f, "f64.convert_s/i32"),
1158            F64ConvertUI32 => write!(f, "f64.convert_u/i32"),
1159            F64ConvertSI64 => write!(f, "f64.convert_s/i64"),
1160            F64ConvertUI64 => write!(f, "f64.convert_u/i64"),
1161            F64PromoteF32 => write!(f, "f64.promote/f32"),
1162
1163            I32ReinterpretF32 => write!(f, "i32.reinterpret/f32"),
1164            I64ReinterpretF64 => write!(f, "i64.reinterpret/f64"),
1165            F32ReinterpretI32 => write!(f, "f32.reinterpret/i32"),
1166            F64ReinterpretI64 => write!(f, "f64.reinterpret/i64"),
1167        }
1168    }
1169}
1170
1171impl Serialize for Opcodes {
1172    type Error = Error;
1173
1174    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
1175        for op in self.0.into_iter() {
1176            op.serialize(writer)?;
1177        }
1178
1179        Ok(())
1180    }
1181}
1182
1183impl Serialize for InitExpr {
1184    type Error = Error;
1185
1186    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
1187        for op in self.0.into_iter() {
1188            op.serialize(writer)?;
1189        }
1190
1191        Ok(())
1192    }
1193}
1194
1195#[test]
1196fn ifelse() {
1197    // see if-else.wast/if-else.wasm
1198    let opcode = super::deserialize_buffer::<Opcodes>(&[0x04, 0x7F, 0x41, 0x05, 0x05, 0x41, 0x07, 0x0B, 0x0B])
1199        .expect("valid hex of if instruction");
1200    let opcodes = opcode.elements();
1201    match &opcodes[0] {
1202        &Opcode::If(_) => (),
1203        _ => panic!("Should be deserialized as if opcode"),
1204    }
1205    let before_else = opcodes.iter().skip(1)
1206        .take_while(|op| match **op { Opcode::Else => false, _ => true }).count();
1207    let after_else = opcodes.iter().skip(1)
1208        .skip_while(|op| match **op { Opcode::Else => false, _ => true })
1209        .take_while(|op| match **op { Opcode::End => false, _ => true })
1210        .count()
1211        - 1; // minus Opcode::Else itself
1212    assert_eq!(before_else, after_else);
1213}
1214
1215#[test]
1216fn display() {
1217    let opcode = Opcode::GetLocal(0);
1218    assert_eq!("get_local 0", format!("{}", opcode));
1219
1220    let opcode = Opcode::F64Store(0, 24);
1221    assert_eq!("f64.store offset=24", format!("{}", opcode));
1222
1223    let opcode = Opcode::I64Store(0, 0);
1224    assert_eq!("i64.store", format!("{}", opcode));
1225}