1use alloc::vec::Vec;
13
14use crate::binary::leb128::{self, Cursor};
15use crate::binary::typeparser::{
16 parse_heap_type, parse_val_type as parse_binary_val_type, parse_val_type_with_first_byte,
17};
18use crate::error::{ByteOffset, DecodeContext, DecodeError, DecodeErrorKind};
19use crate::types::{
20 BlockType, CodeBody, ElemIdx, FuncIdx, GlobalIdx, LabelIdx, LocalIdx, MemArg, MemIdx, RefType,
21 TableIdx, TypeIdx, ValType,
22};
23
24#[derive(Debug, Clone, PartialEq)]
26pub struct DecodedInstr {
27 pub offset: ByteOffset,
28 pub instr: Instr,
29}
30
31#[derive(Debug, Clone, PartialEq)]
33pub enum Instr {
34 Unreachable,
35 Nop,
36 Block(BlockType),
37 Loop(BlockType),
38 If(BlockType),
39 Else,
40 End,
41 Br(LabelIdx),
42 BrIf(LabelIdx),
43 BrOnNull(LabelIdx),
44 BrOnNonNull(LabelIdx),
45 BrTable {
46 targets: Vec<LabelIdx>,
47 default: LabelIdx,
48 },
49 Return,
50 Call(FuncIdx),
51 ReturnCall(FuncIdx),
52 CallRef(TypeIdx),
53 ReturnCallRef(TypeIdx),
54 CallIndirect {
55 type_idx: TypeIdx,
56 table_idx: TableIdx,
57 },
58 ReturnCallIndirect {
59 type_idx: TypeIdx,
60 table_idx: TableIdx,
61 },
62 Drop,
63 Select,
64 SelectTyped(Vec<ValType>),
65 LocalGet(LocalIdx),
66 LocalSet(LocalIdx),
67 LocalTee(LocalIdx),
68 GlobalGet(GlobalIdx),
69 GlobalSet(GlobalIdx),
70 TableGet(TableIdx),
71 TableSet(TableIdx),
72 V128Load(MemArg),
73 V128Load8x8S(MemArg),
74 V128Load8x8U(MemArg),
75 V128Load16x4S(MemArg),
76 V128Load16x4U(MemArg),
77 V128Load32x2S(MemArg),
78 V128Load32x2U(MemArg),
79 V128Load8Splat(MemArg),
80 V128Load16Splat(MemArg),
81 V128Load32Splat(MemArg),
82 V128Load64Splat(MemArg),
83 V128Load32Zero(MemArg),
84 V128Load64Zero(MemArg),
85 V128Store(MemArg),
86 V128Load8Lane {
87 memarg: MemArg,
88 lane: u8,
89 },
90 V128Load16Lane {
91 memarg: MemArg,
92 lane: u8,
93 },
94 V128Load32Lane {
95 memarg: MemArg,
96 lane: u8,
97 },
98 V128Load64Lane {
99 memarg: MemArg,
100 lane: u8,
101 },
102 V128Store8Lane {
103 memarg: MemArg,
104 lane: u8,
105 },
106 V128Store16Lane {
107 memarg: MemArg,
108 lane: u8,
109 },
110 V128Store32Lane {
111 memarg: MemArg,
112 lane: u8,
113 },
114 V128Store64Lane {
115 memarg: MemArg,
116 lane: u8,
117 },
118 I32Load(MemArg),
119 I64Load(MemArg),
120 F32Load(MemArg),
121 F64Load(MemArg),
122 I32Load8S(MemArg),
123 I32Load8U(MemArg),
124 I32Load16S(MemArg),
125 I32Load16U(MemArg),
126 I64Load8S(MemArg),
127 I64Load8U(MemArg),
128 I64Load16S(MemArg),
129 I64Load16U(MemArg),
130 I64Load32S(MemArg),
131 I64Load32U(MemArg),
132 I32Store(MemArg),
133 I64Store(MemArg),
134 F32Store(MemArg),
135 F64Store(MemArg),
136 I32Store8(MemArg),
137 I32Store16(MemArg),
138 I64Store8(MemArg),
139 I64Store16(MemArg),
140 I64Store32(MemArg),
141 MemoryInit(crate::types::DataIdx, MemIdx),
142 DataDrop(crate::types::DataIdx),
143 MemoryCopy {
144 dst: MemIdx,
145 src: MemIdx,
146 },
147 MemoryFill(MemIdx),
148 TableInit {
149 elem_idx: ElemIdx,
150 table_idx: TableIdx,
151 },
152 ElemDrop(ElemIdx),
153 TableCopy {
154 dst: TableIdx,
155 src: TableIdx,
156 },
157 TableGrow(TableIdx),
158 TableSize(TableIdx),
159 TableFill(TableIdx),
160 MemorySize(MemIdx),
161 MemoryGrow(MemIdx),
162 I32Const(i32),
163 I64Const(i64),
164 F32Const(f32),
165 F64Const(f64),
166 RefNull(RefType),
167 RefIsNull,
168 RefFunc(FuncIdx),
169 RefAsNonNull,
170 V128Const([u8; 16]),
171 I8x16Splat,
172 I16x8Splat,
173 I32x4Splat,
174 I64x2Splat,
175 F32x4Splat,
176 F64x2Splat,
177 I32x4ExtractLane(u8),
178 I32x4ReplaceLane(u8),
179 F32x4ExtractLane(u8),
180 F32x4ReplaceLane(u8),
181 V128Not,
182 V128And,
183 V128Or,
184 V128Xor,
185 I8x16Add,
186 I8x16Sub,
187 I16x8Add,
188 I16x8Sub,
189 I32x4Add,
190 I32x4Sub,
191 I32x4Mul,
192 I64x2Add,
193 I64x2Sub,
194 F32x4Add,
195 F32x4Sub,
196 F32x4Mul,
197 F32x4Div,
198 F64x2Add,
199 F64x2Sub,
200 F64x2Mul,
201 F64x2Div,
202 I32Eqz,
203 I32Eq,
204 I32Ne,
205 I32LtS,
206 I32LtU,
207 I32GtS,
208 I32GtU,
209 I32LeS,
210 I32LeU,
211 I32GeS,
212 I32GeU,
213 I64Eqz,
214 I64Eq,
215 I64Ne,
216 I64LtS,
217 I64LtU,
218 I64GtS,
219 I64GtU,
220 I64LeS,
221 I64LeU,
222 I64GeS,
223 I64GeU,
224 F32Eq,
225 F32Ne,
226 F32Lt,
227 F32Gt,
228 F32Le,
229 F32Ge,
230 F64Eq,
231 F64Ne,
232 F64Lt,
233 F64Gt,
234 F64Le,
235 F64Ge,
236 I32Clz,
237 I32Ctz,
238 I32Popcnt,
239 I32Add,
240 I32Sub,
241 I32Mul,
242 I32DivS,
243 I32DivU,
244 I32RemS,
245 I32RemU,
246 I32And,
247 I32Or,
248 I32Xor,
249 I32Shl,
250 I32ShrS,
251 I32ShrU,
252 I32Rotl,
253 I32Rotr,
254 I64Clz,
255 I64Ctz,
256 I64Popcnt,
257 I64Add,
258 I64Sub,
259 I64Mul,
260 I64DivS,
261 I64DivU,
262 I64RemS,
263 I64RemU,
264 I64And,
265 I64Or,
266 I64Xor,
267 I64Shl,
268 I64ShrS,
269 I64ShrU,
270 I64Rotl,
271 I64Rotr,
272 F32Abs,
273 F32Neg,
274 F32Ceil,
275 F32Floor,
276 F32Trunc,
277 F32Nearest,
278 F32Sqrt,
279 F32Add,
280 F32Sub,
281 F32Mul,
282 F32Div,
283 F32Min,
284 F32Max,
285 F32Copysign,
286 F64Abs,
287 F64Neg,
288 F64Ceil,
289 F64Floor,
290 F64Trunc,
291 F64Nearest,
292 F64Sqrt,
293 F64Add,
294 F64Sub,
295 F64Mul,
296 F64Div,
297 F64Min,
298 F64Max,
299 F64Copysign,
300 I32WrapI64,
301 I32TruncF32S,
302 I32TruncF32U,
303 I32TruncF64S,
304 I32TruncF64U,
305 I64ExtendI32S,
306 I64ExtendI32U,
307 I64TruncF32S,
308 I64TruncF32U,
309 I64TruncF64S,
310 I64TruncF64U,
311 F32ConvertI32S,
312 F32ConvertI32U,
313 F32ConvertI64S,
314 F32ConvertI64U,
315 F32DemoteF64,
316 F64ConvertI32S,
317 F64ConvertI32U,
318 F64ConvertI64S,
319 F64ConvertI64U,
320 F64PromoteF32,
321 I32ReinterpretF32,
322 I64ReinterpretF64,
323 F32ReinterpretI32,
324 F64ReinterpretI64,
325 I32Extend8S,
326 I32Extend16S,
327 I64Extend8S,
328 I64Extend16S,
329 I64Extend32S,
330 I32TruncSatF32S,
331 I32TruncSatF32U,
332 I32TruncSatF64S,
333 I32TruncSatF64U,
334 I64TruncSatF32S,
335 I64TruncSatF32U,
336 I64TruncSatF64S,
337 I64TruncSatF64U,
338}
339
340impl<'a> CodeBody<'a> {
341 pub fn instructions(&self) -> Result<Vec<Instr>, DecodeError> {
343 self.instructions_with_offsets()
344 .map(|instrs| instrs.into_iter().map(|decoded| decoded.instr).collect())
345 }
346
347 pub fn instructions_with_offsets(&self) -> Result<Vec<DecodedInstr>, DecodeError> {
349 decode_instr_sequence_with_offsets(self.body, self.body_offset)
350 }
351}
352
353pub fn decode_instr_sequence(bytes: &[u8], base_offset: usize) -> Result<Vec<Instr>, DecodeError> {
355 decode_instr_sequence_with_offsets(bytes, base_offset)
356 .map(|instrs| instrs.into_iter().map(|decoded| decoded.instr).collect())
357}
358
359pub fn decode_instr_sequence_with_offsets(
361 bytes: &[u8],
362 base_offset: usize,
363) -> Result<Vec<DecodedInstr>, DecodeError> {
364 let mut cursor = Cursor::new(bytes);
365 let mut instrs = Vec::new();
366 let mut block_depth = 0usize;
367
368 loop {
369 let decoded = decode_instr_with_offset(&mut cursor, base_offset)?;
370 match decoded.instr {
371 Instr::Block(_) | Instr::Loop(_) | Instr::If(_) => block_depth += 1,
372 Instr::End => {
373 if block_depth == 0 {
374 instrs.push(decoded);
375 return Ok(instrs);
376 }
377 block_depth -= 1;
378 }
379 _ => {}
380 }
381
382 instrs.push(decoded);
383
384 if cursor.is_empty() {
385 return Err(DecodeError {
386 offset: ByteOffset(base_offset + cursor.position()),
387 context: DecodeContext::CodeSection,
388 kind: DecodeErrorKind::UnexpectedEof,
389 });
390 }
391 }
392}
393
394pub fn decode_instr(cursor: &mut Cursor<'_>, base_offset: usize) -> Result<Instr, DecodeError> {
396 decode_instr_with_offset(cursor, base_offset).map(|decoded| decoded.instr)
397}
398
399pub fn decode_instr_with_offset(
401 cursor: &mut Cursor<'_>,
402 base_offset: usize,
403) -> Result<DecodedInstr, DecodeError> {
404 let opcode_offset = cursor.position();
405 let opcode = cursor.read_byte().map_err(|_| DecodeError {
406 offset: ByteOffset(base_offset + opcode_offset),
407 context: DecodeContext::CodeSection,
408 kind: DecodeErrorKind::UnexpectedEof,
409 })?;
410
411 let instr = match opcode {
412 0x00 => Instr::Unreachable,
413 0x01 => Instr::Nop,
414 0x02 => Instr::Block(parse_block_type(cursor, base_offset)?),
415 0x03 => Instr::Loop(parse_block_type(cursor, base_offset)?),
416 0x04 => Instr::If(parse_block_type(cursor, base_offset)?),
417 0x05 => Instr::Else,
418 0x0B => Instr::End,
419 0x0C => Instr::Br(LabelIdx(decode_u32(cursor, base_offset)?)),
420 0x0D => Instr::BrIf(LabelIdx(decode_u32(cursor, base_offset)?)),
421 0x0E => {
422 let target_count = decode_u32(cursor, base_offset)?;
423 let mut targets = Vec::with_capacity(cursor.capacity_hint(target_count));
424 for _ in 0..target_count {
425 targets.push(LabelIdx(decode_u32(cursor, base_offset)?));
426 }
427 let default = LabelIdx(decode_u32(cursor, base_offset)?);
428 Instr::BrTable { targets, default }
429 }
430 0x0F => Instr::Return,
431 0x10 => Instr::Call(FuncIdx(decode_u32(cursor, base_offset)?)),
432 0x12 => Instr::ReturnCall(FuncIdx(decode_u32(cursor, base_offset)?)),
433 0x14 => Instr::CallRef(TypeIdx(decode_u32(cursor, base_offset)?)),
434 0x15 => Instr::ReturnCallRef(TypeIdx(decode_u32(cursor, base_offset)?)),
435 0x11 => Instr::CallIndirect {
436 type_idx: TypeIdx(decode_u32(cursor, base_offset)?),
437 table_idx: parse_table_idx(cursor, base_offset)?,
438 },
439 0x13 => Instr::ReturnCallIndirect {
440 type_idx: TypeIdx(decode_u32(cursor, base_offset)?),
441 table_idx: parse_table_idx(cursor, base_offset)?,
442 },
443 0x1A => Instr::Drop,
444 0x1B => Instr::Select,
445 0x1C => Instr::SelectTyped(parse_result_types(cursor, base_offset)?),
446 0x20 => Instr::LocalGet(LocalIdx(decode_u32(cursor, base_offset)?)),
447 0x21 => Instr::LocalSet(LocalIdx(decode_u32(cursor, base_offset)?)),
448 0x22 => Instr::LocalTee(LocalIdx(decode_u32(cursor, base_offset)?)),
449 0x23 => Instr::GlobalGet(GlobalIdx(decode_u32(cursor, base_offset)?)),
450 0x24 => Instr::GlobalSet(GlobalIdx(decode_u32(cursor, base_offset)?)),
451 0x25 => Instr::TableGet(parse_table_idx(cursor, base_offset)?),
452 0x26 => Instr::TableSet(parse_table_idx(cursor, base_offset)?),
453 0xFC => decode_bulk_memory_instr(cursor, base_offset)?,
454 0xFD => decode_simd_instr(cursor, base_offset)?,
455 0x28 => Instr::I32Load(parse_memarg(cursor, base_offset)?),
456 0x29 => Instr::I64Load(parse_memarg(cursor, base_offset)?),
457 0x2A => Instr::F32Load(parse_memarg(cursor, base_offset)?),
458 0x2B => Instr::F64Load(parse_memarg(cursor, base_offset)?),
459 0x2C => Instr::I32Load8S(parse_memarg(cursor, base_offset)?),
460 0x2D => Instr::I32Load8U(parse_memarg(cursor, base_offset)?),
461 0x2E => Instr::I32Load16S(parse_memarg(cursor, base_offset)?),
462 0x2F => Instr::I32Load16U(parse_memarg(cursor, base_offset)?),
463 0x30 => Instr::I64Load8S(parse_memarg(cursor, base_offset)?),
464 0x31 => Instr::I64Load8U(parse_memarg(cursor, base_offset)?),
465 0x32 => Instr::I64Load16S(parse_memarg(cursor, base_offset)?),
466 0x33 => Instr::I64Load16U(parse_memarg(cursor, base_offset)?),
467 0x34 => Instr::I64Load32S(parse_memarg(cursor, base_offset)?),
468 0x35 => Instr::I64Load32U(parse_memarg(cursor, base_offset)?),
469 0x36 => Instr::I32Store(parse_memarg(cursor, base_offset)?),
470 0x37 => Instr::I64Store(parse_memarg(cursor, base_offset)?),
471 0x38 => Instr::F32Store(parse_memarg(cursor, base_offset)?),
472 0x39 => Instr::F64Store(parse_memarg(cursor, base_offset)?),
473 0x3A => Instr::I32Store8(parse_memarg(cursor, base_offset)?),
474 0x3B => Instr::I32Store16(parse_memarg(cursor, base_offset)?),
475 0x3C => Instr::I64Store8(parse_memarg(cursor, base_offset)?),
476 0x3D => Instr::I64Store16(parse_memarg(cursor, base_offset)?),
477 0x3E => Instr::I64Store32(parse_memarg(cursor, base_offset)?),
478 0x3F => Instr::MemorySize(parse_mem_idx(cursor, base_offset)?),
479 0x40 => Instr::MemoryGrow(parse_mem_idx(cursor, base_offset)?),
480 0x41 => Instr::I32Const(decode_i32(cursor, base_offset)?),
481 0x42 => Instr::I64Const(decode_i64(cursor, base_offset)?),
482 0x43 => Instr::F32Const(decode_f32(cursor, base_offset)?),
483 0x44 => Instr::F64Const(decode_f64(cursor, base_offset)?),
484 0xD0 => Instr::RefNull(RefType::from_parts(
485 true,
486 parse_heap_type(cursor, base_offset, DecodeContext::CodeSection)?,
487 )),
488 0xD1 => Instr::RefIsNull,
489 0xD2 => Instr::RefFunc(FuncIdx(decode_u32(cursor, base_offset)?)),
490 0xD4 => Instr::RefAsNonNull,
491 0xD5 => Instr::BrOnNull(LabelIdx(decode_u32(cursor, base_offset)?)),
492 0xD6 => Instr::BrOnNonNull(LabelIdx(decode_u32(cursor, base_offset)?)),
493 0x45 => Instr::I32Eqz,
494 0x46 => Instr::I32Eq,
495 0x47 => Instr::I32Ne,
496 0x48 => Instr::I32LtS,
497 0x49 => Instr::I32LtU,
498 0x4A => Instr::I32GtS,
499 0x4B => Instr::I32GtU,
500 0x4C => Instr::I32LeS,
501 0x4D => Instr::I32LeU,
502 0x4E => Instr::I32GeS,
503 0x4F => Instr::I32GeU,
504 0x50 => Instr::I64Eqz,
505 0x51 => Instr::I64Eq,
506 0x52 => Instr::I64Ne,
507 0x53 => Instr::I64LtS,
508 0x54 => Instr::I64LtU,
509 0x55 => Instr::I64GtS,
510 0x56 => Instr::I64GtU,
511 0x57 => Instr::I64LeS,
512 0x58 => Instr::I64LeU,
513 0x59 => Instr::I64GeS,
514 0x5A => Instr::I64GeU,
515 0x5B => Instr::F32Eq,
516 0x5C => Instr::F32Ne,
517 0x5D => Instr::F32Lt,
518 0x5E => Instr::F32Gt,
519 0x5F => Instr::F32Le,
520 0x60 => Instr::F32Ge,
521 0x61 => Instr::F64Eq,
522 0x62 => Instr::F64Ne,
523 0x63 => Instr::F64Lt,
524 0x64 => Instr::F64Gt,
525 0x65 => Instr::F64Le,
526 0x66 => Instr::F64Ge,
527 0x67 => Instr::I32Clz,
528 0x68 => Instr::I32Ctz,
529 0x69 => Instr::I32Popcnt,
530 0x6A => Instr::I32Add,
531 0x6B => Instr::I32Sub,
532 0x6C => Instr::I32Mul,
533 0x6D => Instr::I32DivS,
534 0x6E => Instr::I32DivU,
535 0x6F => Instr::I32RemS,
536 0x70 => Instr::I32RemU,
537 0x71 => Instr::I32And,
538 0x72 => Instr::I32Or,
539 0x73 => Instr::I32Xor,
540 0x74 => Instr::I32Shl,
541 0x75 => Instr::I32ShrS,
542 0x76 => Instr::I32ShrU,
543 0x77 => Instr::I32Rotl,
544 0x78 => Instr::I32Rotr,
545 0x79 => Instr::I64Clz,
546 0x7A => Instr::I64Ctz,
547 0x7B => Instr::I64Popcnt,
548 0x7C => Instr::I64Add,
549 0x7D => Instr::I64Sub,
550 0x7E => Instr::I64Mul,
551 0x7F => Instr::I64DivS,
552 0x80 => Instr::I64DivU,
553 0x81 => Instr::I64RemS,
554 0x82 => Instr::I64RemU,
555 0x83 => Instr::I64And,
556 0x84 => Instr::I64Or,
557 0x85 => Instr::I64Xor,
558 0x86 => Instr::I64Shl,
559 0x87 => Instr::I64ShrS,
560 0x88 => Instr::I64ShrU,
561 0x89 => Instr::I64Rotl,
562 0x8A => Instr::I64Rotr,
563 0x8B => Instr::F32Abs,
564 0x8C => Instr::F32Neg,
565 0x8D => Instr::F32Ceil,
566 0x8E => Instr::F32Floor,
567 0x8F => Instr::F32Trunc,
568 0x90 => Instr::F32Nearest,
569 0x91 => Instr::F32Sqrt,
570 0x92 => Instr::F32Add,
571 0x93 => Instr::F32Sub,
572 0x94 => Instr::F32Mul,
573 0x95 => Instr::F32Div,
574 0x96 => Instr::F32Min,
575 0x97 => Instr::F32Max,
576 0x98 => Instr::F32Copysign,
577 0x99 => Instr::F64Abs,
578 0x9A => Instr::F64Neg,
579 0x9B => Instr::F64Ceil,
580 0x9C => Instr::F64Floor,
581 0x9D => Instr::F64Trunc,
582 0x9E => Instr::F64Nearest,
583 0x9F => Instr::F64Sqrt,
584 0xA0 => Instr::F64Add,
585 0xA1 => Instr::F64Sub,
586 0xA2 => Instr::F64Mul,
587 0xA3 => Instr::F64Div,
588 0xA4 => Instr::F64Min,
589 0xA5 => Instr::F64Max,
590 0xA6 => Instr::F64Copysign,
591 0xA7 => Instr::I32WrapI64,
592 0xA8 => Instr::I32TruncF32S,
593 0xA9 => Instr::I32TruncF32U,
594 0xAA => Instr::I32TruncF64S,
595 0xAB => Instr::I32TruncF64U,
596 0xAC => Instr::I64ExtendI32S,
597 0xAD => Instr::I64ExtendI32U,
598 0xAE => Instr::I64TruncF32S,
599 0xAF => Instr::I64TruncF32U,
600 0xB0 => Instr::I64TruncF64S,
601 0xB1 => Instr::I64TruncF64U,
602 0xB2 => Instr::F32ConvertI32S,
603 0xB3 => Instr::F32ConvertI32U,
604 0xB4 => Instr::F32ConvertI64S,
605 0xB5 => Instr::F32ConvertI64U,
606 0xB6 => Instr::F32DemoteF64,
607 0xB7 => Instr::F64ConvertI32S,
608 0xB8 => Instr::F64ConvertI32U,
609 0xB9 => Instr::F64ConvertI64S,
610 0xBA => Instr::F64ConvertI64U,
611 0xBB => Instr::F64PromoteF32,
612 0xBC => Instr::I32ReinterpretF32,
613 0xBD => Instr::I64ReinterpretF64,
614 0xBE => Instr::F32ReinterpretI32,
615 0xBF => Instr::F64ReinterpretI64,
616 0xC0 => Instr::I32Extend8S,
617 0xC1 => Instr::I32Extend16S,
618 0xC2 => Instr::I64Extend8S,
619 0xC3 => Instr::I64Extend16S,
620 0xC4 => Instr::I64Extend32S,
621 _ => {
622 return Err(DecodeError {
623 offset: ByteOffset(base_offset + opcode_offset),
624 context: DecodeContext::CodeSection,
625 kind: DecodeErrorKind::UnknownOpcode { byte: opcode },
626 });
627 }
628 };
629
630 Ok(DecodedInstr {
631 offset: ByteOffset(base_offset + opcode_offset),
632 instr,
633 })
634}
635
636fn decode_bulk_memory_instr(
637 cursor: &mut Cursor<'_>,
638 base_offset: usize,
639) -> Result<Instr, DecodeError> {
640 let opcode = decode_u32(cursor, base_offset)?;
641 match opcode {
642 0 => Ok(Instr::I32TruncSatF32S),
643 1 => Ok(Instr::I32TruncSatF32U),
644 2 => Ok(Instr::I32TruncSatF64S),
645 3 => Ok(Instr::I32TruncSatF64U),
646 4 => Ok(Instr::I64TruncSatF32S),
647 5 => Ok(Instr::I64TruncSatF32U),
648 6 => Ok(Instr::I64TruncSatF64S),
649 7 => Ok(Instr::I64TruncSatF64U),
650 8 => {
651 let data = crate::types::DataIdx(decode_u32(cursor, base_offset)?);
652 let mem = parse_mem_idx(cursor, base_offset)?;
653 Ok(Instr::MemoryInit(data, mem))
654 }
655 9 => Ok(Instr::DataDrop(crate::types::DataIdx(decode_u32(
656 cursor,
657 base_offset,
658 )?))),
659 10 => {
660 let dst = parse_mem_idx(cursor, base_offset)?;
661 let src = parse_mem_idx(cursor, base_offset)?;
662 Ok(Instr::MemoryCopy { dst, src })
663 }
664 11 => Ok(Instr::MemoryFill(parse_mem_idx(cursor, base_offset)?)),
665 12 => Ok(Instr::TableInit {
666 elem_idx: ElemIdx(decode_u32(cursor, base_offset)?),
667 table_idx: parse_table_idx(cursor, base_offset)?,
668 }),
669 13 => Ok(Instr::ElemDrop(ElemIdx(decode_u32(cursor, base_offset)?))),
670 14 => {
671 let dst = parse_table_idx(cursor, base_offset)?;
672 let src = parse_table_idx(cursor, base_offset)?;
673 Ok(Instr::TableCopy { dst, src })
674 }
675 15 => Ok(Instr::TableGrow(parse_table_idx(cursor, base_offset)?)),
676 16 => Ok(Instr::TableSize(parse_table_idx(cursor, base_offset)?)),
677 17 => Ok(Instr::TableFill(parse_table_idx(cursor, base_offset)?)),
678 _ => Err(DecodeError {
679 offset: ByteOffset(base_offset),
680 context: DecodeContext::CodeSection,
681 kind: DecodeErrorKind::UnknownOpcode { byte: 0xFC },
682 }),
683 }
684}
685
686fn decode_simd_instr(cursor: &mut Cursor<'_>, base_offset: usize) -> Result<Instr, DecodeError> {
687 let opcode = decode_u32(cursor, base_offset)?;
688 match opcode {
689 0 => Ok(Instr::V128Load(parse_memarg(cursor, base_offset)?)),
690 1 => Ok(Instr::V128Load8x8S(parse_memarg(cursor, base_offset)?)),
691 2 => Ok(Instr::V128Load8x8U(parse_memarg(cursor, base_offset)?)),
692 3 => Ok(Instr::V128Load16x4S(parse_memarg(cursor, base_offset)?)),
693 4 => Ok(Instr::V128Load16x4U(parse_memarg(cursor, base_offset)?)),
694 5 => Ok(Instr::V128Load32x2S(parse_memarg(cursor, base_offset)?)),
695 6 => Ok(Instr::V128Load32x2U(parse_memarg(cursor, base_offset)?)),
696 7 => Ok(Instr::V128Load8Splat(parse_memarg(cursor, base_offset)?)),
697 8 => Ok(Instr::V128Load16Splat(parse_memarg(cursor, base_offset)?)),
698 9 => Ok(Instr::V128Load32Splat(parse_memarg(cursor, base_offset)?)),
699 10 => Ok(Instr::V128Load64Splat(parse_memarg(cursor, base_offset)?)),
700 11 => Ok(Instr::V128Store(parse_memarg(cursor, base_offset)?)),
701 12 => Ok(Instr::V128Const(parse_v128_const(cursor, base_offset)?)),
702 15 => Ok(Instr::I8x16Splat),
703 16 => Ok(Instr::I16x8Splat),
704 17 => Ok(Instr::I32x4Splat),
705 18 => Ok(Instr::I64x2Splat),
706 19 => Ok(Instr::F32x4Splat),
707 20 => Ok(Instr::F64x2Splat),
708 27 => Ok(Instr::I32x4ExtractLane(parse_lane_idx(
709 cursor,
710 base_offset,
711 )?)),
712 28 => Ok(Instr::I32x4ReplaceLane(parse_lane_idx(
713 cursor,
714 base_offset,
715 )?)),
716 31 => Ok(Instr::F32x4ExtractLane(parse_lane_idx(
717 cursor,
718 base_offset,
719 )?)),
720 32 => Ok(Instr::F32x4ReplaceLane(parse_lane_idx(
721 cursor,
722 base_offset,
723 )?)),
724 77 => Ok(Instr::V128Not),
725 78 => Ok(Instr::V128And),
726 80 => Ok(Instr::V128Or),
727 81 => Ok(Instr::V128Xor),
728 110 => Ok(Instr::I8x16Add),
729 113 => Ok(Instr::I8x16Sub),
730 142 => Ok(Instr::I16x8Add),
731 145 => Ok(Instr::I16x8Sub),
732 174 => Ok(Instr::I32x4Add),
733 177 => Ok(Instr::I32x4Sub),
734 181 => Ok(Instr::I32x4Mul),
735 206 => Ok(Instr::I64x2Add),
736 209 => Ok(Instr::I64x2Sub),
737 228 => Ok(Instr::F32x4Add),
738 229 => Ok(Instr::F32x4Sub),
739 230 => Ok(Instr::F32x4Mul),
740 231 => Ok(Instr::F32x4Div),
741 240 => Ok(Instr::F64x2Add),
742 241 => Ok(Instr::F64x2Sub),
743 242 => Ok(Instr::F64x2Mul),
744 243 => Ok(Instr::F64x2Div),
745 84 => {
746 let (memarg, lane) = parse_memarg_lane(cursor, base_offset)?;
747 Ok(Instr::V128Load8Lane { memarg, lane })
748 }
749 85 => {
750 let (memarg, lane) = parse_memarg_lane(cursor, base_offset)?;
751 Ok(Instr::V128Load16Lane { memarg, lane })
752 }
753 86 => {
754 let (memarg, lane) = parse_memarg_lane(cursor, base_offset)?;
755 Ok(Instr::V128Load32Lane { memarg, lane })
756 }
757 87 => {
758 let (memarg, lane) = parse_memarg_lane(cursor, base_offset)?;
759 Ok(Instr::V128Load64Lane { memarg, lane })
760 }
761 88 => {
762 let (memarg, lane) = parse_memarg_lane(cursor, base_offset)?;
763 Ok(Instr::V128Store8Lane { memarg, lane })
764 }
765 89 => {
766 let (memarg, lane) = parse_memarg_lane(cursor, base_offset)?;
767 Ok(Instr::V128Store16Lane { memarg, lane })
768 }
769 90 => {
770 let (memarg, lane) = parse_memarg_lane(cursor, base_offset)?;
771 Ok(Instr::V128Store32Lane { memarg, lane })
772 }
773 91 => {
774 let (memarg, lane) = parse_memarg_lane(cursor, base_offset)?;
775 Ok(Instr::V128Store64Lane { memarg, lane })
776 }
777 92 => Ok(Instr::V128Load32Zero(parse_memarg(cursor, base_offset)?)),
778 93 => Ok(Instr::V128Load64Zero(parse_memarg(cursor, base_offset)?)),
779 _ => Err(DecodeError {
780 offset: ByteOffset(base_offset),
781 context: DecodeContext::CodeSection,
782 kind: DecodeErrorKind::UnknownSimdOpcode { opcode },
783 }),
784 }
785}
786
787fn parse_memarg(cursor: &mut Cursor<'_>, base_offset: usize) -> Result<MemArg, DecodeError> {
788 let flags = decode_u32(cursor, base_offset)?;
789 let (align, memory) = if flags & (1 << 6) != 0 {
790 (flags ^ (1 << 6), MemIdx(decode_u32(cursor, base_offset)?))
791 } else {
792 (flags, MemIdx(0))
793 };
794 let offset = decode_u32(cursor, base_offset)?;
795 Ok(MemArg {
796 align,
797 offset,
798 memory,
799 })
800}
801
802fn parse_memarg_lane(
803 cursor: &mut Cursor<'_>,
804 base_offset: usize,
805) -> Result<(MemArg, u8), DecodeError> {
806 let memarg = parse_memarg(cursor, base_offset)?;
807 let pos = cursor.position();
808 let lane = cursor.read_byte().map_err(|_| DecodeError {
809 offset: ByteOffset(base_offset + pos),
810 context: DecodeContext::CodeSection,
811 kind: DecodeErrorKind::UnexpectedEof,
812 })?;
813 Ok((memarg, lane))
814}
815
816fn parse_lane_idx(cursor: &mut Cursor<'_>, base_offset: usize) -> Result<u8, DecodeError> {
817 let pos = cursor.position();
818 cursor.read_byte().map_err(|_| DecodeError {
819 offset: ByteOffset(base_offset + pos),
820 context: DecodeContext::CodeSection,
821 kind: DecodeErrorKind::UnexpectedEof,
822 })
823}
824
825fn parse_v128_const(cursor: &mut Cursor<'_>, base_offset: usize) -> Result<[u8; 16], DecodeError> {
826 let pos = cursor.position();
827 let bytes = cursor.read_bytes(16).map_err(|_| DecodeError {
828 offset: ByteOffset(base_offset + pos),
829 context: DecodeContext::CodeSection,
830 kind: DecodeErrorKind::UnexpectedEof,
831 })?;
832 Ok(bytes.try_into().expect("16 bytes"))
833}
834
835fn parse_mem_idx(cursor: &mut Cursor<'_>, base_offset: usize) -> Result<MemIdx, DecodeError> {
836 Ok(MemIdx(decode_u32(cursor, base_offset)?))
837}
838
839fn parse_table_idx(cursor: &mut Cursor<'_>, base_offset: usize) -> Result<TableIdx, DecodeError> {
840 Ok(TableIdx(decode_u32(cursor, base_offset)?))
841}
842
843fn parse_result_types(
844 cursor: &mut Cursor<'_>,
845 base_offset: usize,
846) -> Result<Vec<ValType>, DecodeError> {
847 let count = decode_u32(cursor, base_offset)?;
848 let mut types = Vec::with_capacity(cursor.capacity_hint(count));
849 for _ in 0..count {
850 types.push(parse_binary_val_type(
851 cursor,
852 base_offset,
853 DecodeContext::CodeSection,
854 )?);
855 }
856 Ok(types)
857}
858
859fn parse_block_type(cursor: &mut Cursor<'_>, base_offset: usize) -> Result<BlockType, DecodeError> {
860 let start = cursor.position();
861 let first = cursor.read_byte().map_err(|_| DecodeError {
862 offset: ByteOffset(base_offset + start),
863 context: DecodeContext::CodeSection,
864 kind: DecodeErrorKind::UnexpectedEof,
865 })?;
866
867 if first == 0x40 {
868 return Ok(BlockType::Empty);
869 }
870
871 if matches!(first, 0x7B..=0x7F | 0x70 | 0x6F | 0x63 | 0x64) {
872 return Ok(BlockType::Val(parse_val_type_with_first_byte(
873 cursor,
874 first,
875 base_offset + start,
876 DecodeContext::CodeSection,
877 )?));
878 }
879
880 let type_idx = decode_block_type_idx(cursor, first, base_offset + start)?;
881 Ok(BlockType::TypeIdx(type_idx))
882}
883
884fn decode_block_type_idx(
885 cursor: &mut Cursor<'_>,
886 first: u8,
887 absolute_offset: usize,
888) -> Result<u32, DecodeError> {
889 let mut result = i64::from(first & 0x7F);
890 let mut shift = 7u32;
891 let mut byte = first;
892 let mut i = 0;
893
894 while byte & 0x80 != 0 {
895 i += 1;
896 if i >= 5 {
897 return Err(DecodeError {
898 offset: ByteOffset(absolute_offset),
899 context: DecodeContext::CodeSection,
900 kind: DecodeErrorKind::Leb128TooLong,
901 });
902 }
903
904 byte = cursor.read_byte().map_err(|_| DecodeError {
905 offset: ByteOffset(absolute_offset),
906 context: DecodeContext::CodeSection,
907 kind: DecodeErrorKind::UnexpectedEof,
908 })?;
909 result |= i64::from(byte & 0x7F) << shift;
910 shift += 7;
911 }
912
913 if shift < 33 && (byte & 0x40) != 0 {
914 result |= (!0i64) << shift;
915 }
916
917 if result < 0 {
918 return Err(DecodeError {
919 offset: ByteOffset(absolute_offset),
920 context: DecodeContext::CodeSection,
921 kind: DecodeErrorKind::Leb128Overflow,
922 });
923 }
924
925 Ok(result as u32)
926}
927
928fn decode_u32(cursor: &mut Cursor<'_>, base_offset: usize) -> Result<u32, DecodeError> {
929 leb128::decode_u32(cursor).map_err(|mut e| {
930 e.context = DecodeContext::CodeSection;
931 e.offset = ByteOffset(base_offset + e.offset.0);
932 e
933 })
934}
935
936fn decode_i32(cursor: &mut Cursor<'_>, base_offset: usize) -> Result<i32, DecodeError> {
937 leb128::decode_i32(cursor).map_err(|mut e| {
938 e.context = DecodeContext::CodeSection;
939 e.offset = ByteOffset(base_offset + e.offset.0);
940 e
941 })
942}
943
944fn decode_i64(cursor: &mut Cursor<'_>, base_offset: usize) -> Result<i64, DecodeError> {
945 leb128::decode_i64(cursor).map_err(|mut e| {
946 e.context = DecodeContext::CodeSection;
947 e.offset = ByteOffset(base_offset + e.offset.0);
948 e
949 })
950}
951
952fn decode_f32(cursor: &mut Cursor<'_>, base_offset: usize) -> Result<f32, DecodeError> {
953 let offset = cursor.position();
954 let bytes = cursor.read_bytes(4).map_err(|_| DecodeError {
955 offset: ByteOffset(base_offset + offset),
956 context: DecodeContext::CodeSection,
957 kind: DecodeErrorKind::UnexpectedEof,
958 })?;
959 Ok(f32::from_le_bytes(bytes.try_into().expect("4 bytes")))
960}
961
962fn decode_f64(cursor: &mut Cursor<'_>, base_offset: usize) -> Result<f64, DecodeError> {
963 let offset = cursor.position();
964 let bytes = cursor.read_bytes(8).map_err(|_| DecodeError {
965 offset: ByteOffset(base_offset + offset),
966 context: DecodeContext::CodeSection,
967 kind: DecodeErrorKind::UnexpectedEof,
968 })?;
969 Ok(f64::from_le_bytes(bytes.try_into().expect("8 bytes")))
970}
971
972#[cfg(test)]
973mod tests {
974 use alloc::vec;
975
976 use super::*;
977 use crate::types::{CodeBody, NumType};
978
979 #[test]
980 fn decode_simple_add_body() {
981 let body = CodeBody {
982 locals: Vec::new(),
983 body: &[0x20, 0x00, 0x20, 0x01, 0x6A, 0x0B],
984 body_offset: 100,
985 };
986
987 let instrs = body.instructions().unwrap();
988 assert_eq!(
989 instrs,
990 vec![
991 Instr::LocalGet(LocalIdx(0)),
992 Instr::LocalGet(LocalIdx(1)),
993 Instr::I32Add,
994 Instr::End,
995 ]
996 );
997 }
998
999 #[test]
1000 fn decode_block_with_branch() {
1001 let instrs = decode_instr_sequence(&[0x02, 0x40, 0x0C, 0x00, 0x0B, 0x0B], 200).unwrap();
1002 assert_eq!(
1003 instrs,
1004 vec![
1005 Instr::Block(BlockType::Empty),
1006 Instr::Br(LabelIdx(0)),
1007 Instr::End,
1008 Instr::End,
1009 ]
1010 );
1011 }
1012
1013 #[test]
1014 fn decode_br_table() {
1015 let instrs = decode_instr_sequence(&[0x0E, 0x02, 0x00, 0x01, 0x02, 0x0B], 220).unwrap();
1016 assert_eq!(
1017 instrs,
1018 vec![
1019 Instr::BrTable {
1020 targets: vec![LabelIdx(0), LabelIdx(1)],
1021 default: LabelIdx(2),
1022 },
1023 Instr::End,
1024 ]
1025 );
1026 }
1027
1028 #[test]
1029 fn decode_typed_select() {
1030 let instrs = decode_instr_sequence(&[0x1C, 0x01, 0x7E, 0x0B], 230).unwrap();
1031 assert_eq!(
1032 instrs,
1033 vec![
1034 Instr::SelectTyped(vec![ValType::Num(NumType::I64)]),
1035 Instr::End,
1036 ]
1037 );
1038 }
1039
1040 #[test]
1041 fn decode_globals_and_memory_ops() {
1042 let instrs = decode_instr_sequence(
1043 &[
1044 0x23, 0x00, 0x24, 0x01, 0x28, 0x02, 0x00, 0x2C, 0x00, 0x01, 0x35, 0x02, 0x02, 0x36,
1045 0x02, 0x04, 0x3A, 0x00, 0x08, 0x3E, 0x02, 0x0C, 0x3F, 0x00, 0x40, 0x00, 0x0B,
1046 ],
1047 240,
1048 )
1049 .unwrap();
1050 assert_eq!(
1051 instrs,
1052 vec![
1053 Instr::GlobalGet(GlobalIdx(0)),
1054 Instr::GlobalSet(GlobalIdx(1)),
1055 Instr::I32Load(MemArg {
1056 align: 2,
1057 offset: 0,
1058 memory: MemIdx(0),
1059 }),
1060 Instr::I32Load8S(MemArg {
1061 align: 0,
1062 offset: 1,
1063 memory: MemIdx(0),
1064 }),
1065 Instr::I64Load32U(MemArg {
1066 align: 2,
1067 offset: 2,
1068 memory: MemIdx(0),
1069 }),
1070 Instr::I32Store(MemArg {
1071 align: 2,
1072 offset: 4,
1073 memory: MemIdx(0),
1074 }),
1075 Instr::I32Store8(MemArg {
1076 align: 0,
1077 offset: 8,
1078 memory: MemIdx(0),
1079 }),
1080 Instr::I64Store32(MemArg {
1081 align: 2,
1082 offset: 12,
1083 memory: MemIdx(0),
1084 }),
1085 Instr::MemorySize(MemIdx(0)),
1086 Instr::MemoryGrow(MemIdx(0)),
1087 Instr::End,
1088 ]
1089 );
1090 }
1091
1092 #[test]
1093 fn decode_all_scalar_memory_opcodes() {
1094 let instrs = decode_instr_sequence(
1095 &[
1096 0x28, 0x02, 0x00, 0x29, 0x03, 0x00, 0x2A, 0x02, 0x00, 0x2B, 0x03, 0x00, 0x2C, 0x00,
1097 0x00, 0x2D, 0x00, 0x00, 0x2E, 0x01, 0x00, 0x2F, 0x01, 0x00, 0x30, 0x00, 0x00, 0x31,
1098 0x00, 0x00, 0x32, 0x01, 0x00, 0x33, 0x01, 0x00, 0x34, 0x02, 0x00, 0x35, 0x02, 0x00,
1099 0x36, 0x02, 0x00, 0x37, 0x03, 0x00, 0x38, 0x02, 0x00, 0x39, 0x03, 0x00, 0x3A, 0x00,
1100 0x00, 0x3B, 0x01, 0x00, 0x3C, 0x00, 0x00, 0x3D, 0x01, 0x00, 0x3E, 0x02, 0x00, 0x0B,
1101 ],
1102 280,
1103 )
1104 .unwrap();
1105
1106 assert_eq!(instrs.len(), 24);
1107 assert!(matches!(instrs[0], Instr::I32Load(_)));
1108 assert!(matches!(instrs[1], Instr::I64Load(_)));
1109 assert!(matches!(instrs[2], Instr::F32Load(_)));
1110 assert!(matches!(instrs[3], Instr::F64Load(_)));
1111 assert!(matches!(instrs[4], Instr::I32Load8S(_)));
1112 assert!(matches!(instrs[5], Instr::I32Load8U(_)));
1113 assert!(matches!(instrs[6], Instr::I32Load16S(_)));
1114 assert!(matches!(instrs[7], Instr::I32Load16U(_)));
1115 assert!(matches!(instrs[8], Instr::I64Load8S(_)));
1116 assert!(matches!(instrs[9], Instr::I64Load8U(_)));
1117 assert!(matches!(instrs[10], Instr::I64Load16S(_)));
1118 assert!(matches!(instrs[11], Instr::I64Load16U(_)));
1119 assert!(matches!(instrs[12], Instr::I64Load32S(_)));
1120 assert!(matches!(instrs[13], Instr::I64Load32U(_)));
1121 assert!(matches!(instrs[14], Instr::I32Store(_)));
1122 assert!(matches!(instrs[15], Instr::I64Store(_)));
1123 assert!(matches!(instrs[16], Instr::F32Store(_)));
1124 assert!(matches!(instrs[17], Instr::F64Store(_)));
1125 assert!(matches!(instrs[18], Instr::I32Store8(_)));
1126 assert!(matches!(instrs[19], Instr::I32Store16(_)));
1127 assert!(matches!(instrs[20], Instr::I64Store8(_)));
1128 assert!(matches!(instrs[21], Instr::I64Store16(_)));
1129 assert!(matches!(instrs[22], Instr::I64Store32(_)));
1130 assert!(matches!(instrs[23], Instr::End));
1131 }
1132
1133 #[test]
1134 fn decode_ref_instructions() {
1135 let instrs = decode_instr_sequence(
1136 &[
1137 0xD0, 0x70, 0xD1, 0xD2, 0x00, 0xD4, 0xD5, 0x01, 0xD6, 0x02, 0x0B,
1138 ],
1139 90,
1140 )
1141 .unwrap();
1142 assert_eq!(
1143 instrs,
1144 vec![
1145 Instr::RefNull(RefType::FuncRef),
1146 Instr::RefIsNull,
1147 Instr::RefFunc(FuncIdx(0)),
1148 Instr::RefAsNonNull,
1149 Instr::BrOnNull(LabelIdx(1)),
1150 Instr::BrOnNonNull(LabelIdx(2)),
1151 Instr::End
1152 ]
1153 );
1154 }
1155
1156 #[test]
1157 fn decode_typed_ref_null_instruction() {
1158 let instrs = decode_instr_sequence(&[0xD0, 0x00, 0x0B], 92).unwrap();
1159 assert_eq!(
1160 instrs,
1161 vec![
1162 Instr::RefNull(RefType::concrete(true, TypeIdx(0))),
1163 Instr::End
1164 ]
1165 );
1166 }
1167
1168 #[test]
1169 fn decode_call_indirect_and_table_ops() {
1170 let instrs = decode_instr_sequence(
1171 &[
1172 0x12, 0x00, 0x14, 0x03, 0x15, 0x04, 0x11, 0x01, 0x00, 0x13, 0x02, 0x00, 0x25, 0x00,
1173 0x26, 0x00, 0x0B,
1174 ],
1175 95,
1176 )
1177 .unwrap();
1178 assert_eq!(
1179 instrs,
1180 vec![
1181 Instr::ReturnCall(FuncIdx(0)),
1182 Instr::CallRef(TypeIdx(3)),
1183 Instr::ReturnCallRef(TypeIdx(4)),
1184 Instr::CallIndirect {
1185 type_idx: TypeIdx(1),
1186 table_idx: TableIdx(0),
1187 },
1188 Instr::ReturnCallIndirect {
1189 type_idx: TypeIdx(2),
1190 table_idx: TableIdx(0),
1191 },
1192 Instr::TableGet(TableIdx(0)),
1193 Instr::TableSet(TableIdx(0)),
1194 Instr::End,
1195 ]
1196 );
1197 }
1198
1199 #[test]
1200 fn decode_broader_numeric_ops() {
1201 let instrs = decode_instr_sequence(
1202 &[
1203 0x50, 0x51, 0x5B, 0x61, 0x67, 0x6B, 0x76, 0x79, 0x7D, 0x88, 0x8B, 0x92, 0x98, 0x99,
1204 0xA0, 0xA6, 0x0B,
1205 ],
1206 140,
1207 )
1208 .unwrap();
1209 assert_eq!(
1210 instrs,
1211 vec![
1212 Instr::I64Eqz,
1213 Instr::I64Eq,
1214 Instr::F32Eq,
1215 Instr::F64Eq,
1216 Instr::I32Clz,
1217 Instr::I32Sub,
1218 Instr::I32ShrU,
1219 Instr::I64Clz,
1220 Instr::I64Sub,
1221 Instr::I64ShrU,
1222 Instr::F32Abs,
1223 Instr::F32Add,
1224 Instr::F32Copysign,
1225 Instr::F64Abs,
1226 Instr::F64Add,
1227 Instr::F64Copysign,
1228 Instr::End,
1229 ]
1230 );
1231 }
1232
1233 #[test]
1234 fn decode_conversions_and_reinterpretations() {
1235 let instrs = decode_instr_sequence(
1236 &[
1237 0xA7, 0xA8, 0xAB, 0xAC, 0xB1, 0xB2, 0xB5, 0xB6, 0xB7, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE,
1238 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xFC, 0x00, 0xFC, 0x03, 0xFC, 0x04, 0xFC, 0x07,
1239 0x0B,
1240 ],
1241 180,
1242 )
1243 .unwrap();
1244 assert_eq!(
1245 instrs,
1246 vec![
1247 Instr::I32WrapI64,
1248 Instr::I32TruncF32S,
1249 Instr::I32TruncF64U,
1250 Instr::I64ExtendI32S,
1251 Instr::I64TruncF64U,
1252 Instr::F32ConvertI32S,
1253 Instr::F32ConvertI64U,
1254 Instr::F32DemoteF64,
1255 Instr::F64ConvertI32S,
1256 Instr::F64ConvertI64U,
1257 Instr::F64PromoteF32,
1258 Instr::I32ReinterpretF32,
1259 Instr::I64ReinterpretF64,
1260 Instr::F32ReinterpretI32,
1261 Instr::F64ReinterpretI64,
1262 Instr::I32Extend8S,
1263 Instr::I32Extend16S,
1264 Instr::I64Extend8S,
1265 Instr::I64Extend16S,
1266 Instr::I64Extend32S,
1267 Instr::I32TruncSatF32S,
1268 Instr::I32TruncSatF64U,
1269 Instr::I64TruncSatF32S,
1270 Instr::I64TruncSatF64U,
1271 Instr::End,
1272 ]
1273 );
1274 }
1275
1276 #[test]
1277 fn decode_bulk_memory_ops() {
1278 let instrs = decode_instr_sequence(
1279 &[
1280 0xFC, 0x08, 0x00, 0x00, 0xFC, 0x09, 0x00, 0xFC, 0x0A, 0x00, 0x00, 0xFC, 0x0B, 0x00,
1281 0xFC, 0x0C, 0x00, 0x00, 0xFC, 0x0D, 0x00, 0xFC, 0x0E, 0x00, 0x00, 0xFC, 0x0F, 0x00,
1282 0xFC, 0x10, 0x00, 0xFC, 0x11, 0x00, 0x0B,
1283 ],
1284 315,
1285 )
1286 .unwrap();
1287 assert_eq!(
1288 instrs,
1289 vec![
1290 Instr::MemoryInit(crate::types::DataIdx(0), MemIdx(0)),
1291 Instr::DataDrop(crate::types::DataIdx(0)),
1292 Instr::MemoryCopy {
1293 dst: MemIdx(0),
1294 src: MemIdx(0)
1295 },
1296 Instr::MemoryFill(MemIdx(0)),
1297 Instr::TableInit {
1298 elem_idx: ElemIdx(0),
1299 table_idx: TableIdx(0),
1300 },
1301 Instr::ElemDrop(ElemIdx(0)),
1302 Instr::TableCopy {
1303 dst: TableIdx(0),
1304 src: TableIdx(0),
1305 },
1306 Instr::TableGrow(TableIdx(0)),
1307 Instr::TableSize(TableIdx(0)),
1308 Instr::TableFill(TableIdx(0)),
1309 Instr::End,
1310 ]
1311 );
1312 }
1313
1314 #[test]
1315 fn decode_nonzero_memory_indices() {
1316 let instrs = decode_instr_sequence(
1317 &[
1318 0x3F, 0x01, 0x40, 0x02, 0xFC, 0x08, 0x00, 0x03, 0xFC, 0x0A, 0x01, 0x02, 0xFC, 0x0B,
1319 0x04, 0x0B,
1320 ],
1321 402,
1322 )
1323 .unwrap();
1324 assert_eq!(
1325 instrs,
1326 vec![
1327 Instr::MemorySize(MemIdx(1)),
1328 Instr::MemoryGrow(MemIdx(2)),
1329 Instr::MemoryInit(crate::types::DataIdx(0), MemIdx(3)),
1330 Instr::MemoryCopy {
1331 dst: MemIdx(1),
1332 src: MemIdx(2),
1333 },
1334 Instr::MemoryFill(MemIdx(4)),
1335 Instr::End,
1336 ]
1337 );
1338 }
1339
1340 #[test]
1341 fn decode_nonzero_memargs() {
1342 let instrs = decode_instr_sequence(
1343 &[
1344 0x28, 0x42, 0x01, 0x05, 0x36, 0x42, 0x02, 0x00, 0xFD, 0x00, 0x44, 0x03, 0x00, 0xFD,
1345 0x54, 0x40, 0x04, 0x01, 0x07, 0x0B,
1346 ],
1347 427,
1348 )
1349 .unwrap();
1350 assert_eq!(
1351 instrs,
1352 vec![
1353 Instr::I32Load(MemArg {
1354 align: 2,
1355 offset: 5,
1356 memory: MemIdx(1),
1357 }),
1358 Instr::I32Store(MemArg {
1359 align: 2,
1360 offset: 0,
1361 memory: MemIdx(2),
1362 }),
1363 Instr::V128Load(MemArg {
1364 align: 4,
1365 offset: 0,
1366 memory: MemIdx(3),
1367 }),
1368 Instr::V128Load8Lane {
1369 memarg: MemArg {
1370 align: 0,
1371 offset: 1,
1372 memory: MemIdx(4),
1373 },
1374 lane: 7,
1375 },
1376 Instr::End,
1377 ]
1378 );
1379 }
1380
1381 #[test]
1382 fn decode_vector_memory_ops() {
1383 let instrs = decode_instr_sequence(
1384 &[
1385 0xFD, 0x00, 0x04, 0x00, 0xFD, 0x0B, 0x04, 0x00, 0xFD, 0x54, 0x00, 0x00, 0x0F, 0xFD,
1386 0x58, 0x00, 0x00, 0x0F, 0xFD, 0x5C, 0x02, 0x00, 0xFD, 0x0C, 0x00, 0x01, 0x02, 0x03,
1387 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x0B,
1388 ],
1389 320,
1390 )
1391 .unwrap();
1392 assert_eq!(
1393 instrs,
1394 vec![
1395 Instr::V128Load(MemArg {
1396 align: 4,
1397 offset: 0,
1398 memory: MemIdx(0),
1399 }),
1400 Instr::V128Store(MemArg {
1401 align: 4,
1402 offset: 0,
1403 memory: MemIdx(0),
1404 }),
1405 Instr::V128Load8Lane {
1406 memarg: MemArg {
1407 align: 0,
1408 offset: 0,
1409 memory: MemIdx(0),
1410 },
1411 lane: 15,
1412 },
1413 Instr::V128Store8Lane {
1414 memarg: MemArg {
1415 align: 0,
1416 offset: 0,
1417 memory: MemIdx(0),
1418 },
1419 lane: 15,
1420 },
1421 Instr::V128Load32Zero(MemArg {
1422 align: 2,
1423 offset: 0,
1424 memory: MemIdx(0),
1425 }),
1426 Instr::V128Const([
1427 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
1428 0x0D, 0x0E, 0x0F,
1429 ]),
1430 Instr::End,
1431 ]
1432 );
1433 }
1434
1435 #[test]
1436 fn reject_unknown_simd_opcode() {
1437 let err = decode_instr_sequence(&[0xFD, 0xC8, 0x01, 0x0B], 410).unwrap_err();
1438 assert_eq!(err.kind, DecodeErrorKind::UnknownSimdOpcode { opcode: 200 });
1439 }
1440
1441 #[test]
1442 fn decode_value_block_type() {
1443 let instrs = decode_instr_sequence(&[0x02, 0x7F, 0x41, 0x01, 0x0B, 0x0B], 300).unwrap();
1444 assert_eq!(
1445 instrs[0],
1446 Instr::Block(BlockType::Val(ValType::Num(NumType::I32)))
1447 );
1448 }
1449
1450 #[test]
1451 fn decode_instruction_offsets() {
1452 let body = CodeBody {
1453 locals: Vec::new(),
1454 body: &[0x20, 0x00, 0x20, 0x01, 0x6A, 0x0B],
1455 body_offset: 100,
1456 };
1457
1458 let instrs = body.instructions_with_offsets().unwrap();
1459 assert_eq!(instrs[0].offset, ByteOffset(100));
1460 assert_eq!(instrs[1].offset, ByteOffset(102));
1461 assert_eq!(instrs[2].offset, ByteOffset(104));
1462 assert_eq!(instrs[3].offset, ByteOffset(105));
1463 }
1464
1465 #[test]
1466 fn reject_unknown_opcode() {
1467 let err = decode_instr_sequence(&[0xFF, 0x0B], 400).unwrap_err();
1468 assert_eq!(err.kind, DecodeErrorKind::UnknownOpcode { byte: 0xFF });
1469 }
1470
1471 #[test]
1472 fn reject_unterminated_sequence() {
1473 let err = decode_instr_sequence(&[0x20, 0x00], 500).unwrap_err();
1474 assert_eq!(err.kind, DecodeErrorKind::UnexpectedEof);
1475 }
1476}