swasm/elements/
ops.rs

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