1use alloc::vec::Vec;
26
27use crate::std::ops::{Deref, DerefMut};
28use crate::{
29 limits::MAX_WASM_FUNCTION_LOCALS, ArrayType, BinaryReaderError, BlockType, BrTable, Catch,
30 CompositeType, FieldType, FuncType, HeapType, Ieee32, Ieee64, MemArg, RefType, Result,
31 StorageType, StructType, SubType, TryTable, UnpackedIndex, ValType, VisitOperator,
32 WasmFeatures, WasmModuleResources, V128,
33};
34
35pub(crate) struct OperatorValidator {
36 pub(super) locals: Locals,
37 pub(super) local_inits: Vec<bool>,
38
39 pub(crate) features: WasmFeatures,
42
43 popped_types_tmp: Vec<MaybeType>,
46
47 control: Vec<Frame>,
49 operands: Vec<MaybeType>,
51 inits: Vec<u32>,
54
55 end_which_emptied_control: Option<usize>,
58}
59
60const MAX_LOCALS_TO_TRACK: usize = 50;
63
64pub(super) struct Locals {
65 num_locals: u32,
67
68 first: Vec<ValType>,
73
74 all: Vec<(u32, ValType)>,
85}
86
87#[derive(Debug, Copy, Clone)]
94pub struct Frame {
95 pub kind: FrameKind,
97 pub block_type: BlockType,
100 pub height: usize,
102 pub unreachable: bool,
104 pub init_height: usize,
106}
107
108#[derive(Copy, Clone, Debug, PartialEq, Eq)]
110pub enum FrameKind {
111 Block,
113 If,
115 Else,
117 Loop,
119 TryTable,
125}
126
127struct OperatorValidatorTemp<'validator, 'resources, T> {
128 offset: usize,
129 inner: &'validator mut OperatorValidator,
130 resources: &'resources T,
131}
132
133#[derive(Default)]
134pub struct OperatorValidatorAllocations {
135 popped_types_tmp: Vec<MaybeType>,
136 control: Vec<Frame>,
137 operands: Vec<MaybeType>,
138 local_inits: Vec<bool>,
139 inits: Vec<u32>,
140 locals_first: Vec<ValType>,
141 locals_all: Vec<(u32, ValType)>,
142}
143
144#[derive(Debug, Copy, Clone)]
149enum MaybeType {
150 Bot,
151 HeapBot,
152 Type(ValType),
153}
154
155const _: () = {
159 assert!(crate::std::mem::size_of::<MaybeType>() == 4);
160};
161
162impl crate::std::fmt::Display for MaybeType {
163 fn fmt(&self, f: &mut crate::std::fmt::Formatter<'_>) -> crate::std::fmt::Result {
164 match self {
165 MaybeType::Bot => write!(f, "bot"),
166 MaybeType::HeapBot => write!(f, "heap-bot"),
167 MaybeType::Type(ty) => crate::std::fmt::Display::fmt(ty, f),
168 }
169 }
170}
171
172impl From<ValType> for MaybeType {
173 fn from(ty: ValType) -> MaybeType {
174 MaybeType::Type(ty)
175 }
176}
177
178impl From<RefType> for MaybeType {
179 fn from(ty: RefType) -> MaybeType {
180 let ty: ValType = ty.into();
181 ty.into()
182 }
183}
184
185impl MaybeType {
186 fn as_type(&self) -> Option<ValType> {
187 match *self {
188 Self::Type(ty) => Some(ty),
189 Self::Bot | Self::HeapBot => None,
190 }
191 }
192}
193
194impl OperatorValidator {
195 fn new(features: &WasmFeatures, allocs: OperatorValidatorAllocations) -> Self {
196 let OperatorValidatorAllocations {
197 popped_types_tmp,
198 control,
199 operands,
200 local_inits,
201 inits,
202 locals_first,
203 locals_all,
204 } = allocs;
205 debug_assert!(popped_types_tmp.is_empty());
206 debug_assert!(control.is_empty());
207 debug_assert!(operands.is_empty());
208 debug_assert!(local_inits.is_empty());
209 debug_assert!(inits.is_empty());
210 debug_assert!(locals_first.is_empty());
211 debug_assert!(locals_all.is_empty());
212 OperatorValidator {
213 locals: Locals {
214 num_locals: 0,
215 first: locals_first,
216 all: locals_all,
217 },
218 local_inits,
219 inits,
220 features: *features,
221 popped_types_tmp,
222 operands,
223 control,
224 end_which_emptied_control: None,
225 }
226 }
227
228 pub fn new_func<T>(
234 ty: u32,
235 offset: usize,
236 features: &WasmFeatures,
237 resources: &T,
238 allocs: OperatorValidatorAllocations,
239 ) -> Result<Self>
240 where
241 T: WasmModuleResources,
242 {
243 let mut ret = OperatorValidator::new(features, allocs);
244 ret.control.push(Frame {
245 kind: FrameKind::Block,
246 block_type: BlockType::FuncType(ty),
247 height: 0,
248 unreachable: false,
249 init_height: 0,
250 });
251 let params = OperatorValidatorTemp {
252 offset,
254 inner: &mut ret,
255 resources,
256 }
257 .func_type_at(ty)?
258 .params();
259 for ty in params {
260 ret.locals.define(1, *ty);
261 ret.local_inits.push(true);
262 }
263 Ok(ret)
264 }
265
266 pub fn new_const_expr(
270 features: &WasmFeatures,
271 ty: ValType,
272 allocs: OperatorValidatorAllocations,
273 ) -> Self {
274 let mut ret = OperatorValidator::new(features, allocs);
275 ret.control.push(Frame {
276 kind: FrameKind::Block,
277 block_type: BlockType::Type(ty),
278 height: 0,
279 unreachable: false,
280 init_height: 0,
281 });
282 ret
283 }
284
285 pub fn define_locals(
286 &mut self,
287 offset: usize,
288 count: u32,
289 mut ty: ValType,
290 resources: &impl WasmModuleResources,
291 ) -> Result<()> {
292 resources.check_value_type(&mut ty, &self.features, offset)?;
293 if count == 0 {
294 return Ok(());
295 }
296 if !self.locals.define(count, ty) {
297 return Err(BinaryReaderError::new(
298 "too many locals: locals exceed maximum",
299 offset,
300 ));
301 }
302 self.local_inits
303 .resize(self.local_inits.len() + count as usize, ty.is_defaultable());
304 Ok(())
305 }
306
307 pub fn operand_stack_height(&self) -> usize {
309 self.operands.len()
310 }
311
312 pub fn peek_operand_at(&self, depth: usize) -> Option<Option<ValType>> {
323 Some(match self.operands.iter().rev().nth(depth)? {
324 MaybeType::Type(t) => Some(*t),
325 MaybeType::Bot | MaybeType::HeapBot => None,
326 })
327 }
328
329 pub fn control_stack_height(&self) -> usize {
331 self.control.len()
332 }
333
334 pub fn get_frame(&self, depth: usize) -> Option<&Frame> {
335 self.control.iter().rev().nth(depth)
336 }
337
338 pub fn with_resources<'a, 'validator, 'resources, T>(
340 &'validator mut self,
341 resources: &'resources T,
342 offset: usize,
343 ) -> impl VisitOperator<'a, Output = Result<()>> + 'validator
344 where
345 T: WasmModuleResources,
346 'resources: 'validator,
347 {
348 WasmProposalValidator(OperatorValidatorTemp {
349 offset,
350 inner: self,
351 resources,
352 })
353 }
354
355 pub fn finish(&mut self, offset: usize) -> Result<()> {
356 if self.control.last().is_some() {
357 bail!(
358 offset,
359 "control frames remain at end of function: END opcode expected"
360 );
361 }
362
363 if offset != self.end_which_emptied_control.unwrap() + 1 {
368 return Err(self.err_beyond_end(offset));
369 }
370 Ok(())
371 }
372
373 fn err_beyond_end(&self, offset: usize) -> BinaryReaderError {
374 format_err!(offset, "operators remaining after end of function")
375 }
376
377 pub fn into_allocations(self) -> OperatorValidatorAllocations {
378 fn clear<T>(mut tmp: Vec<T>) -> Vec<T> {
379 tmp.clear();
380 tmp
381 }
382 OperatorValidatorAllocations {
383 popped_types_tmp: clear(self.popped_types_tmp),
384 control: clear(self.control),
385 operands: clear(self.operands),
386 local_inits: clear(self.local_inits),
387 inits: clear(self.inits),
388 locals_first: clear(self.locals.first),
389 locals_all: clear(self.locals.all),
390 }
391 }
392}
393
394impl<R> Deref for OperatorValidatorTemp<'_, '_, R> {
395 type Target = OperatorValidator;
396 fn deref(&self) -> &OperatorValidator {
397 self.inner
398 }
399}
400
401impl<R> DerefMut for OperatorValidatorTemp<'_, '_, R> {
402 fn deref_mut(&mut self) -> &mut OperatorValidator {
403 self.inner
404 }
405}
406
407impl<'resources, R> OperatorValidatorTemp<'_, 'resources, R>
408where
409 R: WasmModuleResources,
410{
411 fn push_operand<T>(&mut self, ty: T) -> Result<()>
417 where
418 T: Into<MaybeType>,
419 {
420 let maybe_ty = ty.into();
421
422 if cfg!(debug_assertions) {
423 match maybe_ty {
424 MaybeType::Type(ValType::Ref(r)) => match r.heap_type() {
425 HeapType::Concrete(index) => {
426 debug_assert!(
427 matches!(index, UnpackedIndex::Id(_)),
428 "only ref types referencing `CoreTypeId`s can \
429 be pushed to the operand stack"
430 );
431 }
432 _ => {}
433 },
434 _ => {}
435 }
436 }
437
438 self.operands.push(maybe_ty);
439 Ok(())
440 }
441
442 fn push_concrete_ref(&mut self, nullable: bool, type_index: u32) -> Result<()> {
443 let mut heap_ty = HeapType::Concrete(UnpackedIndex::Module(type_index));
444
445 self.resources.check_heap_type(&mut heap_ty, self.offset)?;
447 debug_assert!(matches!(heap_ty, HeapType::Concrete(UnpackedIndex::Id(_))));
448
449 let ref_ty = RefType::new(nullable, heap_ty).ok_or_else(|| {
450 format_err!(self.offset, "implementation limit: type index too large")
451 })?;
452
453 self.push_operand(ref_ty)
454 }
455
456 fn pop_concrete_ref(&mut self, nullable: bool, type_index: u32) -> Result<MaybeType> {
457 let mut heap_ty = HeapType::Concrete(UnpackedIndex::Module(type_index));
458
459 self.resources.check_heap_type(&mut heap_ty, self.offset)?;
461 debug_assert!(matches!(heap_ty, HeapType::Concrete(UnpackedIndex::Id(_))));
462
463 let ref_ty = RefType::new(nullable, heap_ty).ok_or_else(|| {
464 format_err!(self.offset, "implementation limit: type index too large")
465 })?;
466
467 self.pop_operand(Some(ref_ty.into()))
468 }
469
470 fn pop_push_label_types(
473 &mut self,
474 label_types: impl PreciseIterator<Item = ValType>,
475 ) -> Result<()> {
476 for ty in label_types.clone().rev() {
477 self.pop_operand(Some(ty))?;
478 }
479 for ty in label_types {
480 self.push_operand(ty)?;
481 }
482 Ok(())
483 }
484
485 fn pop_operand(&mut self, expected: Option<ValType>) -> Result<MaybeType> {
504 let popped = match self.operands.pop() {
516 Some(MaybeType::Type(actual_ty)) => {
517 if Some(actual_ty) == expected {
518 if let Some(control) = self.control.last() {
519 if self.operands.len() >= control.height {
520 return Ok(MaybeType::Type(actual_ty));
521 }
522 }
523 }
524 Some(MaybeType::Type(actual_ty))
525 }
526 other => other,
527 };
528
529 self._pop_operand(expected, popped)
530 }
531
532 #[cold]
536 fn _pop_operand(
537 &mut self,
538 expected: Option<ValType>,
539 popped: Option<MaybeType>,
540 ) -> Result<MaybeType> {
541 self.operands.extend(popped);
542 let control = match self.control.last() {
543 Some(c) => c,
544 None => return Err(self.err_beyond_end(self.offset)),
545 };
546 let actual = if self.operands.len() == control.height && control.unreachable {
547 MaybeType::Bot
548 } else {
549 if self.operands.len() == control.height {
550 let desc = match expected {
551 Some(ty) => ty_to_str(ty),
552 None => "a type".into(),
553 };
554 bail!(
555 self.offset,
556 "type mismatch: expected {desc} but nothing on stack"
557 )
558 } else {
559 self.operands.pop().unwrap()
560 }
561 };
562 if let Some(expected) = expected {
563 match (actual, expected) {
564 (MaybeType::Bot, _)
566 | (MaybeType::HeapBot, ValType::Ref(_)) => {}
569
570 (MaybeType::Type(actual), expected) => {
573 if !self.resources.is_subtype(actual, expected) {
574 bail!(
575 self.offset,
576 "type mismatch: expected {}, found {}",
577 ty_to_str(expected),
578 ty_to_str(actual)
579 );
580 }
581 }
582
583 (
585 MaybeType::HeapBot,
586 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128,
587 ) => {
588 bail!(
589 self.offset,
590 "type mismatch: expected {}, found heap type",
591 ty_to_str(expected)
592 )
593 }
594 }
595 }
596 Ok(actual)
597 }
598
599 fn pop_ref(&mut self) -> Result<Option<RefType>> {
600 match self.pop_operand(None)? {
601 MaybeType::Bot | MaybeType::HeapBot => Ok(None),
602 MaybeType::Type(ValType::Ref(rt)) => Ok(Some(rt)),
603 MaybeType::Type(ty) => bail!(
604 self.offset,
605 "type mismatch: expected ref but found {}",
606 ty_to_str(ty)
607 ),
608 }
609 }
610
611 fn local(&self, idx: u32) -> Result<ValType> {
614 match self.locals.get(idx) {
615 Some(ty) => Ok(ty),
616 None => bail!(
617 self.offset,
618 "unknown local {}: local index out of bounds",
619 idx
620 ),
621 }
622 }
623
624 fn unreachable(&mut self) -> Result<()> {
627 let control = match self.control.last_mut() {
628 Some(frame) => frame,
629 None => return Err(self.err_beyond_end(self.offset)),
630 };
631 control.unreachable = true;
632 let new_height = control.height;
633 self.operands.truncate(new_height);
634 Ok(())
635 }
636
637 fn push_ctrl(&mut self, kind: FrameKind, ty: BlockType) -> Result<()> {
644 let height = self.operands.len();
647 let init_height = self.inits.len();
648 self.control.push(Frame {
649 kind,
650 block_type: ty,
651 height,
652 unreachable: false,
653 init_height,
654 });
655 for ty in self.params(ty)? {
658 self.push_operand(ty)?;
659 }
660 Ok(())
661 }
662
663 fn pop_ctrl(&mut self) -> Result<Frame> {
668 let frame = match self.control.last() {
671 Some(f) => f,
672 None => return Err(self.err_beyond_end(self.offset)),
673 };
674 let ty = frame.block_type;
675 let height = frame.height;
676 let init_height = frame.init_height;
677
678 for init in self.inits.split_off(init_height) {
680 self.local_inits[init as usize] = false;
681 }
682
683 for ty in self.results(ty)?.rev() {
686 self.pop_operand(Some(ty))?;
687 }
688
689 if self.operands.len() != height {
692 bail!(
693 self.offset,
694 "type mismatch: values remaining on stack at end of block"
695 );
696 }
697
698 Ok(self.control.pop().unwrap())
700 }
701
702 fn jump(&self, depth: u32) -> Result<(BlockType, FrameKind)> {
707 if self.control.is_empty() {
708 return Err(self.err_beyond_end(self.offset));
709 }
710 match (self.control.len() - 1).checked_sub(depth as usize) {
711 Some(i) => {
712 let frame = &self.control[i];
713 Ok((frame.block_type, frame.kind))
714 }
715 None => bail!(self.offset, "unknown label: branch depth too large"),
716 }
717 }
718
719 fn check_memory_index(&self, memory_index: u32) -> Result<ValType> {
722 match self.resources.memory_at(memory_index) {
723 Some(mem) => Ok(mem.index_type()),
724 None => bail!(self.offset, "unknown memory {}", memory_index),
725 }
726 }
727
728 fn check_memarg(&self, memarg: MemArg) -> Result<ValType> {
731 let index_ty = self.check_memory_index(memarg.memory)?;
732 if memarg.align > memarg.max_align {
733 bail!(self.offset, "alignment must not be larger than natural");
734 }
735 if index_ty == ValType::I32 && memarg.offset > u64::from(u32::MAX) {
736 bail!(self.offset, "offset out of range: must be <= 2**32");
737 }
738 Ok(index_ty)
739 }
740
741 fn check_floats_enabled(&self) -> Result<()> {
742 if !self.features.floats {
743 bail!(self.offset, "floating-point instruction disallowed");
744 }
745 Ok(())
746 }
747
748 fn check_shared_memarg(&self, memarg: MemArg) -> Result<ValType> {
749 if memarg.align != memarg.max_align {
750 bail!(
751 self.offset,
752 "atomic instructions must always specify maximum alignment"
753 );
754 }
755 self.check_memory_index(memarg.memory)
756 }
757
758 fn check_simd_lane_index(&self, index: u8, max: u8) -> Result<()> {
759 if index >= max {
760 bail!(self.offset, "SIMD index out of bounds");
761 }
762 Ok(())
763 }
764
765 fn check_block_type(&self, ty: &mut BlockType) -> Result<()> {
767 match ty {
768 BlockType::Empty => Ok(()),
769 BlockType::Type(t) => self
770 .resources
771 .check_value_type(t, &self.features, self.offset),
772 BlockType::FuncType(idx) => {
773 if !self.features.multi_value {
774 bail!(
775 self.offset,
776 "blocks, loops, and ifs may only produce a resulttype \
777 when multi-value is not enabled",
778 );
779 }
780 self.func_type_at(*idx)?;
781 Ok(())
782 }
783 }
784 }
785
786 fn check_call(&mut self, function_index: u32) -> Result<()> {
789 let ty = match self.resources.type_of_function(function_index) {
790 Some(i) => i,
791 None => {
792 bail!(
793 self.offset,
794 "unknown function {function_index}: function index out of bounds",
795 );
796 }
797 };
798 self.check_call_ty(ty)
799 }
800
801 fn check_call_type_index(&mut self, type_index: u32) -> Result<()> {
802 let ty = self.func_type_at(type_index)?;
803 self.check_call_ty(ty)
804 }
805
806 fn check_call_ty(&mut self, ty: &FuncType) -> Result<()> {
807 for &ty in ty.params().iter().rev() {
808 debug_assert_type_indices_are_ids(ty);
809 self.pop_operand(Some(ty))?;
810 }
811 for &ty in ty.results() {
812 debug_assert_type_indices_are_ids(ty);
813 self.push_operand(ty)?;
814 }
815 Ok(())
816 }
817
818 fn check_call_indirect(&mut self, index: u32, table_index: u32) -> Result<()> {
820 match self.resources.table_at(table_index) {
821 None => {
822 bail!(self.offset, "unknown table: table index out of bounds");
823 }
824 Some(tab) => {
825 if !self
826 .resources
827 .is_subtype(ValType::Ref(tab.element_type), ValType::FUNCREF)
828 {
829 bail!(
830 self.offset,
831 "indirect calls must go through a table with type <= funcref",
832 );
833 }
834 }
835 }
836 let ty = self.func_type_at(index)?;
837 self.pop_operand(Some(ValType::I32))?;
838 for ty in ty.clone().params().iter().rev() {
839 self.pop_operand(Some(*ty))?;
840 }
841 for ty in ty.results() {
842 self.push_operand(*ty)?;
843 }
844 Ok(())
845 }
846
847 fn check_return(&mut self) -> Result<()> {
850 if self.control.is_empty() {
851 return Err(self.err_beyond_end(self.offset));
852 }
853 for ty in self.results(self.control[0].block_type)?.rev() {
854 self.pop_operand(Some(ty))?;
855 }
856 self.unreachable()?;
857 Ok(())
858 }
859
860 fn check_cmp_op(&mut self, ty: ValType) -> Result<()> {
862 self.pop_operand(Some(ty))?;
863 self.pop_operand(Some(ty))?;
864 self.push_operand(ValType::I32)?;
865 Ok(())
866 }
867
868 fn check_fcmp_op(&mut self, ty: ValType) -> Result<()> {
870 debug_assert!(matches!(ty, ValType::F32 | ValType::F64));
871 self.check_floats_enabled()?;
872 self.check_cmp_op(ty)
873 }
874
875 fn check_unary_op(&mut self, ty: ValType) -> Result<()> {
877 self.pop_operand(Some(ty))?;
878 self.push_operand(ty)?;
879 Ok(())
880 }
881
882 fn check_funary_op(&mut self, ty: ValType) -> Result<()> {
884 debug_assert!(matches!(ty, ValType::F32 | ValType::F64));
885 self.check_floats_enabled()?;
886 self.check_unary_op(ty)
887 }
888
889 fn check_conversion_op(&mut self, into: ValType, from: ValType) -> Result<()> {
891 self.pop_operand(Some(from))?;
892 self.push_operand(into)?;
893 Ok(())
894 }
895
896 fn check_fconversion_op(&mut self, into: ValType, from: ValType) -> Result<()> {
898 debug_assert!(matches!(into, ValType::F32 | ValType::F64));
899 self.check_floats_enabled()?;
900 self.check_conversion_op(into, from)
901 }
902
903 fn check_binary_op(&mut self, ty: ValType) -> Result<()> {
905 self.pop_operand(Some(ty))?;
906 self.pop_operand(Some(ty))?;
907 self.push_operand(ty)?;
908 Ok(())
909 }
910
911 fn check_fbinary_op(&mut self, ty: ValType) -> Result<()> {
913 debug_assert!(matches!(ty, ValType::F32 | ValType::F64));
914 self.check_floats_enabled()?;
915 self.check_binary_op(ty)
916 }
917
918 fn check_atomic_load(&mut self, memarg: MemArg, load_ty: ValType) -> Result<()> {
920 let ty = self.check_shared_memarg(memarg)?;
921 self.pop_operand(Some(ty))?;
922 self.push_operand(load_ty)?;
923 Ok(())
924 }
925
926 fn check_atomic_store(&mut self, memarg: MemArg, store_ty: ValType) -> Result<()> {
928 let ty = self.check_shared_memarg(memarg)?;
929 self.pop_operand(Some(store_ty))?;
930 self.pop_operand(Some(ty))?;
931 Ok(())
932 }
933
934 fn check_atomic_binary_op(&mut self, memarg: MemArg, op_ty: ValType) -> Result<()> {
936 let ty = self.check_shared_memarg(memarg)?;
937 self.pop_operand(Some(op_ty))?;
938 self.pop_operand(Some(ty))?;
939 self.push_operand(op_ty)?;
940 Ok(())
941 }
942
943 fn check_atomic_binary_cmpxchg(&mut self, memarg: MemArg, op_ty: ValType) -> Result<()> {
945 let ty = self.check_shared_memarg(memarg)?;
946 self.pop_operand(Some(op_ty))?;
947 self.pop_operand(Some(op_ty))?;
948 self.pop_operand(Some(ty))?;
949 self.push_operand(op_ty)?;
950 Ok(())
951 }
952
953 fn check_v128_splat(&mut self, src_ty: ValType) -> Result<()> {
955 self.pop_operand(Some(src_ty))?;
956 self.push_operand(ValType::V128)?;
957 Ok(())
958 }
959
960 fn check_v128_binary_op(&mut self) -> Result<()> {
962 self.pop_operand(Some(ValType::V128))?;
963 self.pop_operand(Some(ValType::V128))?;
964 self.push_operand(ValType::V128)?;
965 Ok(())
966 }
967
968 fn check_v128_fbinary_op(&mut self) -> Result<()> {
970 self.check_floats_enabled()?;
971 self.check_v128_binary_op()
972 }
973
974 fn check_v128_unary_op(&mut self) -> Result<()> {
976 self.pop_operand(Some(ValType::V128))?;
977 self.push_operand(ValType::V128)?;
978 Ok(())
979 }
980
981 fn check_v128_funary_op(&mut self) -> Result<()> {
983 self.check_floats_enabled()?;
984 self.check_v128_unary_op()
985 }
986
987 fn check_v128_ternary_op(&mut self) -> Result<()> {
989 self.pop_operand(Some(ValType::V128))?;
990 self.pop_operand(Some(ValType::V128))?;
991 self.pop_operand(Some(ValType::V128))?;
992 self.push_operand(ValType::V128)?;
993 Ok(())
994 }
995
996 fn check_v128_bitmask_op(&mut self) -> Result<()> {
998 self.pop_operand(Some(ValType::V128))?;
999 self.push_operand(ValType::I32)?;
1000 Ok(())
1001 }
1002
1003 fn check_v128_shift_op(&mut self) -> Result<()> {
1005 self.pop_operand(Some(ValType::I32))?;
1006 self.pop_operand(Some(ValType::V128))?;
1007 self.push_operand(ValType::V128)?;
1008 Ok(())
1009 }
1010
1011 fn check_v128_load_op(&mut self, memarg: MemArg) -> Result<()> {
1013 let idx = self.check_memarg(memarg)?;
1014 self.pop_operand(Some(idx))?;
1015 self.push_operand(ValType::V128)?;
1016 Ok(())
1017 }
1018
1019 fn check_downcast(
1022 &mut self,
1023 nullable: bool,
1024 mut heap_type: HeapType,
1025 inst_name: &str,
1026 ) -> Result<ValType> {
1027 self.resources
1028 .check_heap_type(&mut heap_type, self.offset)?;
1029
1030 let sub_ty = RefType::new(nullable, heap_type)
1031 .map(ValType::from)
1032 .ok_or_else(|| {
1033 BinaryReaderError::new("implementation limit: type index too large", self.offset)
1034 })?;
1035
1036 let sup_ty = self.pop_ref()?.unwrap_or_else(|| {
1037 sub_ty
1038 .as_reference_type()
1039 .expect("we created this as a reference just above")
1040 });
1041 let sup_ty = RefType::new(true, self.resources.top_type(&sup_ty.heap_type()))
1042 .expect("can't panic with non-concrete heap types");
1043
1044 if !self.resources.is_subtype(sub_ty, sup_ty.into()) {
1045 bail!(
1046 self.offset,
1047 "{inst_name}'s heap type must be a sub type of the type on the stack: \
1048 {sub_ty} is not a sub type of {sup_ty}"
1049 );
1050 }
1051
1052 Ok(sub_ty)
1053 }
1054
1055 fn check_ref_test(&mut self, nullable: bool, heap_type: HeapType) -> Result<()> {
1058 self.check_downcast(nullable, heap_type, "ref.test")?;
1059 self.push_operand(ValType::I32)
1060 }
1061
1062 fn check_ref_cast(&mut self, nullable: bool, heap_type: HeapType) -> Result<()> {
1065 let sub_ty = self.check_downcast(nullable, heap_type, "ref.cast")?;
1066 self.push_operand(sub_ty)
1067 }
1068
1069 fn element_type_at(&self, elem_index: u32) -> Result<RefType> {
1070 match self.resources.element_type_at(elem_index) {
1071 Some(ty) => Ok(ty),
1072 None => bail!(
1073 self.offset,
1074 "unknown elem segment {}: segment index out of bounds",
1075 elem_index
1076 ),
1077 }
1078 }
1079
1080 fn sub_type_at(&self, at: u32) -> Result<&'resources SubType> {
1081 self.resources
1082 .sub_type_at(at)
1083 .ok_or_else(|| format_err!(self.offset, "unknown type: type index out of bounds"))
1084 }
1085
1086 fn struct_type_at(&self, at: u32) -> Result<&'resources StructType> {
1087 let sub_ty = self.sub_type_at(at)?;
1088 if let CompositeType::Struct(struct_ty) = &sub_ty.composite_type {
1089 Ok(struct_ty)
1090 } else {
1091 bail!(
1092 self.offset,
1093 "expected struct type at index {at}, found {sub_ty}"
1094 )
1095 }
1096 }
1097
1098 fn struct_field_at(&self, struct_type_index: u32, field_index: u32) -> Result<FieldType> {
1099 let field_index = usize::try_from(field_index).map_err(|_| {
1100 BinaryReaderError::new("unknown field: field index out of bounds", self.offset)
1101 })?;
1102 self.struct_type_at(struct_type_index)?
1103 .fields
1104 .get(field_index)
1105 .copied()
1106 .ok_or_else(|| {
1107 BinaryReaderError::new("unknown field: field index out of bounds", self.offset)
1108 })
1109 }
1110
1111 fn array_type_at(&self, at: u32) -> Result<&'resources ArrayType> {
1112 let sub_ty = self.sub_type_at(at)?;
1113 if let CompositeType::Array(array_ty) = &sub_ty.composite_type {
1114 Ok(array_ty)
1115 } else {
1116 bail!(
1117 self.offset,
1118 "expected array type at index {at}, found {sub_ty}"
1119 )
1120 }
1121 }
1122
1123 fn func_type_at(&self, at: u32) -> Result<&'resources FuncType> {
1124 let sub_ty = self.sub_type_at(at)?;
1125 if let CompositeType::Func(func_ty) = &sub_ty.composite_type {
1126 Ok(func_ty)
1127 } else {
1128 bail!(
1129 self.offset,
1130 "expected func type at index {at}, found {sub_ty}"
1131 )
1132 }
1133 }
1134
1135 fn tag_at(&self, at: u32) -> Result<&'resources FuncType> {
1136 self.resources
1137 .tag_at(at)
1138 .ok_or_else(|| format_err!(self.offset, "unknown tag {}: tag index out of bounds", at))
1139 }
1140
1141 fn params(&self, ty: BlockType) -> Result<impl PreciseIterator<Item = ValType> + 'resources> {
1142 Ok(match ty {
1143 BlockType::Empty | BlockType::Type(_) => Either::B(None.into_iter()),
1144 BlockType::FuncType(t) => Either::A(self.func_type_at(t)?.params().iter().copied()),
1145 })
1146 }
1147
1148 fn results(&self, ty: BlockType) -> Result<impl PreciseIterator<Item = ValType> + 'resources> {
1149 Ok(match ty {
1150 BlockType::Empty => Either::B(None.into_iter()),
1151 BlockType::Type(t) => Either::B(Some(t).into_iter()),
1152 BlockType::FuncType(t) => Either::A(self.func_type_at(t)?.results().iter().copied()),
1153 })
1154 }
1155
1156 fn label_types(
1157 &self,
1158 ty: BlockType,
1159 kind: FrameKind,
1160 ) -> Result<impl PreciseIterator<Item = ValType> + 'resources> {
1161 Ok(match kind {
1162 FrameKind::Loop => Either::A(self.params(ty)?),
1163 _ => Either::B(self.results(ty)?),
1164 })
1165 }
1166}
1167
1168pub fn ty_to_str(ty: ValType) -> &'static str {
1169 match ty {
1170 ValType::I32 => "i32",
1171 ValType::I64 => "i64",
1172 ValType::F32 => "f32",
1173 ValType::F64 => "f64",
1174 ValType::V128 => "v128",
1175 ValType::Ref(r) => r.wat(),
1176 }
1177}
1178
1179struct WasmProposalValidator<'validator, 'resources, T>(
1188 OperatorValidatorTemp<'validator, 'resources, T>,
1189);
1190
1191impl<T> WasmProposalValidator<'_, '_, T> {
1192 fn check_enabled(&self, flag: bool, desc: &str) -> Result<()> {
1193 if flag {
1194 return Ok(());
1195 }
1196 bail!(self.0.offset, "{desc} support is not enabled");
1197 }
1198}
1199
1200macro_rules! validate_proposal {
1201 ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => {
1202 $(
1203 fn $visit(&mut self $($(,$arg: $argty)*)?) -> Result<()> {
1204 validate_proposal!(validate self $proposal);
1205 self.0.$visit($( $($arg),* )?)
1206 }
1207 )*
1208 };
1209
1210 (validate self mvp) => {};
1211 (validate $self:ident $proposal:ident) => {
1212 $self.check_enabled($self.0.features.$proposal, validate_proposal!(desc $proposal))?
1213 };
1214
1215 (desc simd) => ("SIMD");
1216 (desc relaxed_simd) => ("relaxed SIMD");
1217 (desc threads) => ("threads");
1218 (desc saturating_float_to_int) => ("saturating float to int conversions");
1219 (desc reference_types) => ("reference types");
1220 (desc bulk_memory) => ("bulk memory");
1221 (desc sign_extension) => ("sign extension operations");
1222 (desc exceptions) => ("exceptions");
1223 (desc tail_call) => ("tail calls");
1224 (desc function_references) => ("function references");
1225 (desc memory_control) => ("memory control");
1226 (desc gc) => ("gc");
1227}
1228
1229impl<'a, T> VisitOperator<'a> for WasmProposalValidator<'_, '_, T>
1230where
1231 T: WasmModuleResources,
1232{
1233 type Output = Result<()>;
1234
1235 for_each_operator!(validate_proposal);
1236}
1237
1238#[track_caller]
1239#[inline]
1240fn debug_assert_type_indices_are_ids(ty: ValType) {
1241 if cfg!(debug_assertions) {
1242 if let ValType::Ref(r) = ty {
1243 if let HeapType::Concrete(idx) = r.heap_type() {
1244 debug_assert!(
1245 matches!(idx, UnpackedIndex::Id(_)),
1246 "type reference should be a `CoreTypeId`, found {idx:?}"
1247 );
1248 }
1249 }
1250 }
1251}
1252
1253impl<'a, T> VisitOperator<'a> for OperatorValidatorTemp<'_, '_, T>
1254where
1255 T: WasmModuleResources,
1256{
1257 type Output = Result<()>;
1258
1259 fn visit_nop(&mut self) -> Self::Output {
1260 Ok(())
1261 }
1262 fn visit_unreachable(&mut self) -> Self::Output {
1263 self.unreachable()?;
1264 Ok(())
1265 }
1266 fn visit_block(&mut self, mut ty: BlockType) -> Self::Output {
1267 self.check_block_type(&mut ty)?;
1268 for ty in self.params(ty)?.rev() {
1269 self.pop_operand(Some(ty))?;
1270 }
1271 self.push_ctrl(FrameKind::Block, ty)?;
1272 Ok(())
1273 }
1274 fn visit_loop(&mut self, mut ty: BlockType) -> Self::Output {
1275 self.check_block_type(&mut ty)?;
1276 for ty in self.params(ty)?.rev() {
1277 self.pop_operand(Some(ty))?;
1278 }
1279 self.push_ctrl(FrameKind::Loop, ty)?;
1280 Ok(())
1281 }
1282 fn visit_if(&mut self, mut ty: BlockType) -> Self::Output {
1283 self.check_block_type(&mut ty)?;
1284 self.pop_operand(Some(ValType::I32))?;
1285 for ty in self.params(ty)?.rev() {
1286 self.pop_operand(Some(ty))?;
1287 }
1288 self.push_ctrl(FrameKind::If, ty)?;
1289 Ok(())
1290 }
1291 fn visit_else(&mut self) -> Self::Output {
1292 let frame = self.pop_ctrl()?;
1293 if frame.kind != FrameKind::If {
1294 bail!(self.offset, "else found outside of an `if` block");
1295 }
1296 self.push_ctrl(FrameKind::Else, frame.block_type)?;
1297 Ok(())
1298 }
1299 fn visit_try_table(&mut self, mut ty: TryTable) -> Self::Output {
1300 self.check_block_type(&mut ty.ty)?;
1301 for ty in self.params(ty.ty)?.rev() {
1302 self.pop_operand(Some(ty))?;
1303 }
1304 for catch in ty.catches {
1305 match catch {
1306 Catch::One { tag, label } => {
1307 let tag = self.tag_at(tag)?;
1308 let (ty, kind) = self.jump(label)?;
1309 let params = tag.params();
1310 let types = self.label_types(ty, kind)?;
1311 if params.len() != types.len() {
1312 bail!(
1313 self.offset,
1314 "type mismatch: catch label must have same number of types as tag"
1315 );
1316 }
1317 for (expected, actual) in types.zip(params) {
1318 self.push_operand(*actual)?;
1319 self.pop_operand(Some(expected))?;
1320 }
1321 }
1322 Catch::OneRef { tag, label } => {
1323 let tag = self.tag_at(tag)?;
1324 let (ty, kind) = self.jump(label)?;
1325 let tag_params = tag.params().iter().copied();
1326 let label_types = self.label_types(ty, kind)?;
1327 if tag_params.len() + 1 != label_types.len() {
1328 bail!(
1329 self.offset,
1330 "type mismatch: catch_ref label must have one \
1331 more type than tag types",
1332 );
1333 }
1334 for (expected_label_tyep, actual_tag_param) in
1335 label_types.zip(tag_params.chain([ValType::EXNREF]))
1336 {
1337 self.push_operand(actual_tag_param)?;
1338 self.pop_operand(Some(expected_label_tyep))?;
1339 }
1340 }
1341
1342 Catch::All { label } => {
1343 let (ty, kind) = self.jump(label)?;
1344 if self.label_types(ty, kind)?.len() != 0 {
1345 bail!(
1346 self.offset,
1347 "type mismatch: catch_all label must have no result types"
1348 );
1349 }
1350 }
1351
1352 Catch::AllRef { label } => {
1353 let (ty, kind) = self.jump(label)?;
1354 let mut types = self.label_types(ty, kind)?;
1355 match (types.next(), types.next()) {
1356 (Some(ValType::EXNREF), None) => {}
1357 _ => {
1358 bail!(
1359 self.offset,
1360 "type mismatch: catch_all_ref label must have \
1361 one exnref result type"
1362 );
1363 }
1364 }
1365 }
1366 }
1367 }
1368 self.push_ctrl(FrameKind::TryTable, ty.ty)?;
1369 Ok(())
1370 }
1371 fn visit_throw(&mut self, index: u32) -> Self::Output {
1372 let ty = self.tag_at(index)?;
1374 for ty in ty.clone().params().iter().rev() {
1375 self.pop_operand(Some(*ty))?;
1376 }
1377 if ty.results().len() > 0 {
1378 bail!(
1379 self.offset,
1380 "result type expected to be empty for exception"
1381 );
1382 }
1383 self.unreachable()?;
1384 Ok(())
1385 }
1386 fn visit_throw_ref(&mut self) -> Self::Output {
1387 self.pop_operand(Some(ValType::EXNREF))?;
1388 self.unreachable()?;
1389 Ok(())
1390 }
1391 fn visit_try(&mut self, _: BlockType) -> Self::Output {
1392 bail!(self.offset, "unimplemented validation of deprecated opcode")
1393 }
1394 fn visit_catch(&mut self, _: u32) -> Self::Output {
1395 bail!(self.offset, "unimplemented validation of deprecated opcode")
1396 }
1397 fn visit_rethrow(&mut self, _: u32) -> Self::Output {
1398 bail!(self.offset, "unimplemented validation of deprecated opcode")
1399 }
1400 fn visit_delegate(&mut self, _: u32) -> Self::Output {
1401 bail!(self.offset, "unimplemented validation of deprecated opcode")
1402 }
1403 fn visit_catch_all(&mut self) -> Self::Output {
1404 bail!(self.offset, "unimplemented validation of deprecated opcode")
1405 }
1406 fn visit_end(&mut self) -> Self::Output {
1407 let mut frame = self.pop_ctrl()?;
1408
1409 if frame.kind == FrameKind::If {
1414 self.push_ctrl(FrameKind::Else, frame.block_type)?;
1415 frame = self.pop_ctrl()?;
1416 }
1417 for ty in self.results(frame.block_type)? {
1418 self.push_operand(ty)?;
1419 }
1420
1421 if self.control.is_empty() && self.end_which_emptied_control.is_none() {
1422 assert_ne!(self.offset, 0);
1423 self.end_which_emptied_control = Some(self.offset);
1424 }
1425 Ok(())
1426 }
1427 fn visit_br(&mut self, relative_depth: u32) -> Self::Output {
1428 let (ty, kind) = self.jump(relative_depth)?;
1429 for ty in self.label_types(ty, kind)?.rev() {
1430 self.pop_operand(Some(ty))?;
1431 }
1432 self.unreachable()?;
1433 Ok(())
1434 }
1435 fn visit_br_if(&mut self, relative_depth: u32) -> Self::Output {
1436 self.pop_operand(Some(ValType::I32))?;
1437 let (ty, kind) = self.jump(relative_depth)?;
1438 let label_types = self.label_types(ty, kind)?;
1439 self.pop_push_label_types(label_types)?;
1440 Ok(())
1441 }
1442 fn visit_br_table(&mut self, table: BrTable) -> Self::Output {
1443 self.pop_operand(Some(ValType::I32))?;
1444 let default = self.jump(table.default())?;
1445 let default_types = self.label_types(default.0, default.1)?;
1446 for element in table.targets() {
1447 let relative_depth = element?;
1448 let block = self.jump(relative_depth)?;
1449 let label_tys = self.label_types(block.0, block.1)?;
1450 if label_tys.len() != default_types.len() {
1451 bail!(
1452 self.offset,
1453 "type mismatch: br_table target labels have different number of types"
1454 );
1455 }
1456
1457 debug_assert!(self.popped_types_tmp.is_empty());
1458 self.popped_types_tmp.reserve(label_tys.len());
1459 for expected_ty in label_tys.rev() {
1460 let actual_ty = self.pop_operand(Some(expected_ty))?;
1461 self.popped_types_tmp.push(actual_ty);
1462 }
1463 for ty in self.inner.popped_types_tmp.drain(..).rev() {
1464 self.inner.operands.push(ty.into());
1465 }
1466 }
1467 for ty in default_types.rev() {
1468 self.pop_operand(Some(ty))?;
1469 }
1470 self.unreachable()?;
1471 Ok(())
1472 }
1473 fn visit_return(&mut self) -> Self::Output {
1474 self.check_return()?;
1475 Ok(())
1476 }
1477 fn visit_call(&mut self, function_index: u32) -> Self::Output {
1478 self.check_call(function_index)?;
1479 Ok(())
1480 }
1481 fn visit_return_call(&mut self, function_index: u32) -> Self::Output {
1482 self.check_call(function_index)?;
1483 self.check_return()?;
1484 Ok(())
1485 }
1486 fn visit_call_ref(&mut self, type_index: u32) -> Self::Output {
1487 let unpacked_index = UnpackedIndex::Module(type_index);
1488 let mut hty = HeapType::Concrete(unpacked_index);
1489 self.resources.check_heap_type(&mut hty, self.offset)?;
1490 if let Some(rt) = self.pop_ref()? {
1493 let expected = RefType::new(true, hty).expect("hty should be previously validated");
1494 let expected = ValType::Ref(expected);
1495 if !self.resources.is_subtype(ValType::Ref(rt), expected) {
1496 bail!(
1497 self.offset,
1498 "type mismatch: funcref on stack does not match specified type",
1499 );
1500 }
1501 }
1502 self.check_call_type_index(type_index)
1503 }
1504 fn visit_return_call_ref(&mut self, type_index: u32) -> Self::Output {
1505 self.visit_call_ref(type_index)?;
1506 self.check_return()
1507 }
1508 fn visit_call_indirect(
1509 &mut self,
1510 index: u32,
1511 table_index: u32,
1512 table_byte: u8,
1513 ) -> Self::Output {
1514 if table_byte != 0 && !self.features.reference_types {
1515 bail!(
1516 self.offset,
1517 "reference-types not enabled: zero byte expected"
1518 );
1519 }
1520 self.check_call_indirect(index, table_index)?;
1521 Ok(())
1522 }
1523 fn visit_return_call_indirect(&mut self, index: u32, table_index: u32) -> Self::Output {
1524 self.check_call_indirect(index, table_index)?;
1525 self.check_return()?;
1526 Ok(())
1527 }
1528 fn visit_drop(&mut self) -> Self::Output {
1529 self.pop_operand(None)?;
1530 Ok(())
1531 }
1532 fn visit_select(&mut self) -> Self::Output {
1533 self.pop_operand(Some(ValType::I32))?;
1534 let ty1 = self.pop_operand(None)?;
1535 let ty2 = self.pop_operand(None)?;
1536
1537 let ty = match (ty1, ty2) {
1538 (MaybeType::HeapBot, _)
1541 | (_, MaybeType::HeapBot)
1542 | (MaybeType::Type(ValType::Ref(_)), _)
1543 | (_, MaybeType::Type(ValType::Ref(_))) => {
1544 bail!(
1545 self.offset,
1546 "type mismatch: select only takes integral types"
1547 )
1548 }
1549
1550 (MaybeType::Bot, t) | (t, MaybeType::Bot) => t,
1553
1554 (t @ MaybeType::Type(t1), MaybeType::Type(t2)) => {
1557 if t1 != t2 {
1558 bail!(
1559 self.offset,
1560 "type mismatch: select operands have different types"
1561 );
1562 }
1563 t
1564 }
1565 };
1566 self.push_operand(ty)?;
1567 Ok(())
1568 }
1569 fn visit_typed_select(&mut self, mut ty: ValType) -> Self::Output {
1570 self.resources
1571 .check_value_type(&mut ty, &self.features, self.offset)?;
1572 self.pop_operand(Some(ValType::I32))?;
1573 self.pop_operand(Some(ty))?;
1574 self.pop_operand(Some(ty))?;
1575 self.push_operand(ty)?;
1576 Ok(())
1577 }
1578 fn visit_local_get(&mut self, local_index: u32) -> Self::Output {
1579 let ty = self.local(local_index)?;
1580 debug_assert_type_indices_are_ids(ty);
1581 if !self.local_inits[local_index as usize] {
1582 bail!(self.offset, "uninitialized local: {}", local_index);
1583 }
1584 self.push_operand(ty)?;
1585 Ok(())
1586 }
1587 fn visit_local_set(&mut self, local_index: u32) -> Self::Output {
1588 let ty = self.local(local_index)?;
1589 self.pop_operand(Some(ty))?;
1590 if !self.local_inits[local_index as usize] {
1591 self.local_inits[local_index as usize] = true;
1592 self.inits.push(local_index);
1593 }
1594 Ok(())
1595 }
1596 fn visit_local_tee(&mut self, local_index: u32) -> Self::Output {
1597 let expected_ty = self.local(local_index)?;
1598 let actual_ty = self.pop_operand(Some(expected_ty))?;
1599 if !self.local_inits[local_index as usize] {
1600 self.local_inits[local_index as usize] = true;
1601 self.inits.push(local_index);
1602 }
1603
1604 self.push_operand(actual_ty)?;
1605 Ok(())
1606 }
1607 fn visit_global_get(&mut self, global_index: u32) -> Self::Output {
1608 if let Some(ty) = self.resources.global_at(global_index) {
1609 let ty = ty.content_type;
1610 debug_assert_type_indices_are_ids(ty);
1611 self.push_operand(ty)?;
1612 } else {
1613 bail!(self.offset, "unknown global: global index out of bounds");
1614 };
1615 Ok(())
1616 }
1617 fn visit_global_set(&mut self, global_index: u32) -> Self::Output {
1618 if let Some(ty) = self.resources.global_at(global_index) {
1619 if !ty.mutable {
1620 bail!(
1621 self.offset,
1622 "global is immutable: cannot modify it with `global.set`"
1623 );
1624 }
1625 self.pop_operand(Some(ty.content_type))?;
1626 } else {
1627 bail!(self.offset, "unknown global: global index out of bounds");
1628 };
1629 Ok(())
1630 }
1631 fn visit_i32_load(&mut self, memarg: MemArg) -> Self::Output {
1632 let ty = self.check_memarg(memarg)?;
1633 self.pop_operand(Some(ty))?;
1634 self.push_operand(ValType::I32)?;
1635 Ok(())
1636 }
1637 fn visit_i64_load(&mut self, memarg: MemArg) -> Self::Output {
1638 let ty = self.check_memarg(memarg)?;
1639 self.pop_operand(Some(ty))?;
1640 self.push_operand(ValType::I64)?;
1641 Ok(())
1642 }
1643 fn visit_f32_load(&mut self, memarg: MemArg) -> Self::Output {
1644 self.check_floats_enabled()?;
1645 let ty = self.check_memarg(memarg)?;
1646 self.pop_operand(Some(ty))?;
1647 self.push_operand(ValType::F32)?;
1648 Ok(())
1649 }
1650 fn visit_f64_load(&mut self, memarg: MemArg) -> Self::Output {
1651 self.check_floats_enabled()?;
1652 let ty = self.check_memarg(memarg)?;
1653 self.pop_operand(Some(ty))?;
1654 self.push_operand(ValType::F64)?;
1655 Ok(())
1656 }
1657 fn visit_i32_load8_s(&mut self, memarg: MemArg) -> Self::Output {
1658 let ty = self.check_memarg(memarg)?;
1659 self.pop_operand(Some(ty))?;
1660 self.push_operand(ValType::I32)?;
1661 Ok(())
1662 }
1663 fn visit_i32_load8_u(&mut self, memarg: MemArg) -> Self::Output {
1664 self.visit_i32_load8_s(memarg)
1665 }
1666 fn visit_i32_load16_s(&mut self, memarg: MemArg) -> Self::Output {
1667 let ty = self.check_memarg(memarg)?;
1668 self.pop_operand(Some(ty))?;
1669 self.push_operand(ValType::I32)?;
1670 Ok(())
1671 }
1672 fn visit_i32_load16_u(&mut self, memarg: MemArg) -> Self::Output {
1673 self.visit_i32_load16_s(memarg)
1674 }
1675 fn visit_i64_load8_s(&mut self, memarg: MemArg) -> Self::Output {
1676 let ty = self.check_memarg(memarg)?;
1677 self.pop_operand(Some(ty))?;
1678 self.push_operand(ValType::I64)?;
1679 Ok(())
1680 }
1681 fn visit_i64_load8_u(&mut self, memarg: MemArg) -> Self::Output {
1682 self.visit_i64_load8_s(memarg)
1683 }
1684 fn visit_i64_load16_s(&mut self, memarg: MemArg) -> Self::Output {
1685 let ty = self.check_memarg(memarg)?;
1686 self.pop_operand(Some(ty))?;
1687 self.push_operand(ValType::I64)?;
1688 Ok(())
1689 }
1690 fn visit_i64_load16_u(&mut self, memarg: MemArg) -> Self::Output {
1691 self.visit_i64_load16_s(memarg)
1692 }
1693 fn visit_i64_load32_s(&mut self, memarg: MemArg) -> Self::Output {
1694 let ty = self.check_memarg(memarg)?;
1695 self.pop_operand(Some(ty))?;
1696 self.push_operand(ValType::I64)?;
1697 Ok(())
1698 }
1699 fn visit_i64_load32_u(&mut self, memarg: MemArg) -> Self::Output {
1700 self.visit_i64_load32_s(memarg)
1701 }
1702 fn visit_i32_store(&mut self, memarg: MemArg) -> Self::Output {
1703 let ty = self.check_memarg(memarg)?;
1704 self.pop_operand(Some(ValType::I32))?;
1705 self.pop_operand(Some(ty))?;
1706 Ok(())
1707 }
1708 fn visit_i64_store(&mut self, memarg: MemArg) -> Self::Output {
1709 let ty = self.check_memarg(memarg)?;
1710 self.pop_operand(Some(ValType::I64))?;
1711 self.pop_operand(Some(ty))?;
1712 Ok(())
1713 }
1714 fn visit_f32_store(&mut self, memarg: MemArg) -> Self::Output {
1715 self.check_floats_enabled()?;
1716 let ty = self.check_memarg(memarg)?;
1717 self.pop_operand(Some(ValType::F32))?;
1718 self.pop_operand(Some(ty))?;
1719 Ok(())
1720 }
1721 fn visit_f64_store(&mut self, memarg: MemArg) -> Self::Output {
1722 self.check_floats_enabled()?;
1723 let ty = self.check_memarg(memarg)?;
1724 self.pop_operand(Some(ValType::F64))?;
1725 self.pop_operand(Some(ty))?;
1726 Ok(())
1727 }
1728 fn visit_i32_store8(&mut self, memarg: MemArg) -> Self::Output {
1729 let ty = self.check_memarg(memarg)?;
1730 self.pop_operand(Some(ValType::I32))?;
1731 self.pop_operand(Some(ty))?;
1732 Ok(())
1733 }
1734 fn visit_i32_store16(&mut self, memarg: MemArg) -> Self::Output {
1735 let ty = self.check_memarg(memarg)?;
1736 self.pop_operand(Some(ValType::I32))?;
1737 self.pop_operand(Some(ty))?;
1738 Ok(())
1739 }
1740 fn visit_i64_store8(&mut self, memarg: MemArg) -> Self::Output {
1741 let ty = self.check_memarg(memarg)?;
1742 self.pop_operand(Some(ValType::I64))?;
1743 self.pop_operand(Some(ty))?;
1744 Ok(())
1745 }
1746 fn visit_i64_store16(&mut self, memarg: MemArg) -> Self::Output {
1747 let ty = self.check_memarg(memarg)?;
1748 self.pop_operand(Some(ValType::I64))?;
1749 self.pop_operand(Some(ty))?;
1750 Ok(())
1751 }
1752 fn visit_i64_store32(&mut self, memarg: MemArg) -> Self::Output {
1753 let ty = self.check_memarg(memarg)?;
1754 self.pop_operand(Some(ValType::I64))?;
1755 self.pop_operand(Some(ty))?;
1756 Ok(())
1757 }
1758 fn visit_memory_size(&mut self, mem: u32, mem_byte: u8) -> Self::Output {
1759 if mem_byte != 0 && !self.features.multi_memory {
1760 bail!(self.offset, "multi-memory not enabled: zero byte expected");
1761 }
1762 let index_ty = self.check_memory_index(mem)?;
1763 self.push_operand(index_ty)?;
1764 Ok(())
1765 }
1766 fn visit_memory_grow(&mut self, mem: u32, mem_byte: u8) -> Self::Output {
1767 if mem_byte != 0 && !self.features.multi_memory {
1768 bail!(self.offset, "multi-memory not enabled: zero byte expected");
1769 }
1770 let index_ty = self.check_memory_index(mem)?;
1771 self.pop_operand(Some(index_ty))?;
1772 self.push_operand(index_ty)?;
1773 Ok(())
1774 }
1775 fn visit_i32_const(&mut self, _value: i32) -> Self::Output {
1776 self.push_operand(ValType::I32)?;
1777 Ok(())
1778 }
1779 fn visit_i64_const(&mut self, _value: i64) -> Self::Output {
1780 self.push_operand(ValType::I64)?;
1781 Ok(())
1782 }
1783 fn visit_f32_const(&mut self, _value: Ieee32) -> Self::Output {
1784 self.check_floats_enabled()?;
1785 self.push_operand(ValType::F32)?;
1786 Ok(())
1787 }
1788 fn visit_f64_const(&mut self, _value: Ieee64) -> Self::Output {
1789 self.check_floats_enabled()?;
1790 self.push_operand(ValType::F64)?;
1791 Ok(())
1792 }
1793 fn visit_i32_eqz(&mut self) -> Self::Output {
1794 self.pop_operand(Some(ValType::I32))?;
1795 self.push_operand(ValType::I32)?;
1796 Ok(())
1797 }
1798 fn visit_i32_eq(&mut self) -> Self::Output {
1799 self.check_cmp_op(ValType::I32)
1800 }
1801 fn visit_i32_ne(&mut self) -> Self::Output {
1802 self.check_cmp_op(ValType::I32)
1803 }
1804 fn visit_i32_lt_s(&mut self) -> Self::Output {
1805 self.check_cmp_op(ValType::I32)
1806 }
1807 fn visit_i32_lt_u(&mut self) -> Self::Output {
1808 self.check_cmp_op(ValType::I32)
1809 }
1810 fn visit_i32_gt_s(&mut self) -> Self::Output {
1811 self.check_cmp_op(ValType::I32)
1812 }
1813 fn visit_i32_gt_u(&mut self) -> Self::Output {
1814 self.check_cmp_op(ValType::I32)
1815 }
1816 fn visit_i32_le_s(&mut self) -> Self::Output {
1817 self.check_cmp_op(ValType::I32)
1818 }
1819 fn visit_i32_le_u(&mut self) -> Self::Output {
1820 self.check_cmp_op(ValType::I32)
1821 }
1822 fn visit_i32_ge_s(&mut self) -> Self::Output {
1823 self.check_cmp_op(ValType::I32)
1824 }
1825 fn visit_i32_ge_u(&mut self) -> Self::Output {
1826 self.check_cmp_op(ValType::I32)
1827 }
1828 fn visit_i64_eqz(&mut self) -> Self::Output {
1829 self.pop_operand(Some(ValType::I64))?;
1830 self.push_operand(ValType::I32)?;
1831 Ok(())
1832 }
1833 fn visit_i64_eq(&mut self) -> Self::Output {
1834 self.check_cmp_op(ValType::I64)
1835 }
1836 fn visit_i64_ne(&mut self) -> Self::Output {
1837 self.check_cmp_op(ValType::I64)
1838 }
1839 fn visit_i64_lt_s(&mut self) -> Self::Output {
1840 self.check_cmp_op(ValType::I64)
1841 }
1842 fn visit_i64_lt_u(&mut self) -> Self::Output {
1843 self.check_cmp_op(ValType::I64)
1844 }
1845 fn visit_i64_gt_s(&mut self) -> Self::Output {
1846 self.check_cmp_op(ValType::I64)
1847 }
1848 fn visit_i64_gt_u(&mut self) -> Self::Output {
1849 self.check_cmp_op(ValType::I64)
1850 }
1851 fn visit_i64_le_s(&mut self) -> Self::Output {
1852 self.check_cmp_op(ValType::I64)
1853 }
1854 fn visit_i64_le_u(&mut self) -> Self::Output {
1855 self.check_cmp_op(ValType::I64)
1856 }
1857 fn visit_i64_ge_s(&mut self) -> Self::Output {
1858 self.check_cmp_op(ValType::I64)
1859 }
1860 fn visit_i64_ge_u(&mut self) -> Self::Output {
1861 self.check_cmp_op(ValType::I64)
1862 }
1863 fn visit_f32_eq(&mut self) -> Self::Output {
1864 self.check_fcmp_op(ValType::F32)
1865 }
1866 fn visit_f32_ne(&mut self) -> Self::Output {
1867 self.check_fcmp_op(ValType::F32)
1868 }
1869 fn visit_f32_lt(&mut self) -> Self::Output {
1870 self.check_fcmp_op(ValType::F32)
1871 }
1872 fn visit_f32_gt(&mut self) -> Self::Output {
1873 self.check_fcmp_op(ValType::F32)
1874 }
1875 fn visit_f32_le(&mut self) -> Self::Output {
1876 self.check_fcmp_op(ValType::F32)
1877 }
1878 fn visit_f32_ge(&mut self) -> Self::Output {
1879 self.check_fcmp_op(ValType::F32)
1880 }
1881 fn visit_f64_eq(&mut self) -> Self::Output {
1882 self.check_fcmp_op(ValType::F64)
1883 }
1884 fn visit_f64_ne(&mut self) -> Self::Output {
1885 self.check_fcmp_op(ValType::F64)
1886 }
1887 fn visit_f64_lt(&mut self) -> Self::Output {
1888 self.check_fcmp_op(ValType::F64)
1889 }
1890 fn visit_f64_gt(&mut self) -> Self::Output {
1891 self.check_fcmp_op(ValType::F64)
1892 }
1893 fn visit_f64_le(&mut self) -> Self::Output {
1894 self.check_fcmp_op(ValType::F64)
1895 }
1896 fn visit_f64_ge(&mut self) -> Self::Output {
1897 self.check_fcmp_op(ValType::F64)
1898 }
1899 fn visit_i32_clz(&mut self) -> Self::Output {
1900 self.check_unary_op(ValType::I32)
1901 }
1902 fn visit_i32_ctz(&mut self) -> Self::Output {
1903 self.check_unary_op(ValType::I32)
1904 }
1905 fn visit_i32_popcnt(&mut self) -> Self::Output {
1906 self.check_unary_op(ValType::I32)
1907 }
1908 fn visit_i32_add(&mut self) -> Self::Output {
1909 self.check_binary_op(ValType::I32)
1910 }
1911 fn visit_i32_sub(&mut self) -> Self::Output {
1912 self.check_binary_op(ValType::I32)
1913 }
1914 fn visit_i32_mul(&mut self) -> Self::Output {
1915 self.check_binary_op(ValType::I32)
1916 }
1917 fn visit_i32_div_s(&mut self) -> Self::Output {
1918 self.check_binary_op(ValType::I32)
1919 }
1920 fn visit_i32_div_u(&mut self) -> Self::Output {
1921 self.check_binary_op(ValType::I32)
1922 }
1923 fn visit_i32_rem_s(&mut self) -> Self::Output {
1924 self.check_binary_op(ValType::I32)
1925 }
1926 fn visit_i32_rem_u(&mut self) -> Self::Output {
1927 self.check_binary_op(ValType::I32)
1928 }
1929 fn visit_i32_and(&mut self) -> Self::Output {
1930 self.check_binary_op(ValType::I32)
1931 }
1932 fn visit_i32_or(&mut self) -> Self::Output {
1933 self.check_binary_op(ValType::I32)
1934 }
1935 fn visit_i32_xor(&mut self) -> Self::Output {
1936 self.check_binary_op(ValType::I32)
1937 }
1938 fn visit_i32_shl(&mut self) -> Self::Output {
1939 self.check_binary_op(ValType::I32)
1940 }
1941 fn visit_i32_shr_s(&mut self) -> Self::Output {
1942 self.check_binary_op(ValType::I32)
1943 }
1944 fn visit_i32_shr_u(&mut self) -> Self::Output {
1945 self.check_binary_op(ValType::I32)
1946 }
1947 fn visit_i32_rotl(&mut self) -> Self::Output {
1948 self.check_binary_op(ValType::I32)
1949 }
1950 fn visit_i32_rotr(&mut self) -> Self::Output {
1951 self.check_binary_op(ValType::I32)
1952 }
1953 fn visit_i64_clz(&mut self) -> Self::Output {
1954 self.check_unary_op(ValType::I64)
1955 }
1956 fn visit_i64_ctz(&mut self) -> Self::Output {
1957 self.check_unary_op(ValType::I64)
1958 }
1959 fn visit_i64_popcnt(&mut self) -> Self::Output {
1960 self.check_unary_op(ValType::I64)
1961 }
1962 fn visit_i64_add(&mut self) -> Self::Output {
1963 self.check_binary_op(ValType::I64)
1964 }
1965 fn visit_i64_sub(&mut self) -> Self::Output {
1966 self.check_binary_op(ValType::I64)
1967 }
1968 fn visit_i64_mul(&mut self) -> Self::Output {
1969 self.check_binary_op(ValType::I64)
1970 }
1971 fn visit_i64_div_s(&mut self) -> Self::Output {
1972 self.check_binary_op(ValType::I64)
1973 }
1974 fn visit_i64_div_u(&mut self) -> Self::Output {
1975 self.check_binary_op(ValType::I64)
1976 }
1977 fn visit_i64_rem_s(&mut self) -> Self::Output {
1978 self.check_binary_op(ValType::I64)
1979 }
1980 fn visit_i64_rem_u(&mut self) -> Self::Output {
1981 self.check_binary_op(ValType::I64)
1982 }
1983 fn visit_i64_and(&mut self) -> Self::Output {
1984 self.check_binary_op(ValType::I64)
1985 }
1986 fn visit_i64_or(&mut self) -> Self::Output {
1987 self.check_binary_op(ValType::I64)
1988 }
1989 fn visit_i64_xor(&mut self) -> Self::Output {
1990 self.check_binary_op(ValType::I64)
1991 }
1992 fn visit_i64_shl(&mut self) -> Self::Output {
1993 self.check_binary_op(ValType::I64)
1994 }
1995 fn visit_i64_shr_s(&mut self) -> Self::Output {
1996 self.check_binary_op(ValType::I64)
1997 }
1998 fn visit_i64_shr_u(&mut self) -> Self::Output {
1999 self.check_binary_op(ValType::I64)
2000 }
2001 fn visit_i64_rotl(&mut self) -> Self::Output {
2002 self.check_binary_op(ValType::I64)
2003 }
2004 fn visit_i64_rotr(&mut self) -> Self::Output {
2005 self.check_binary_op(ValType::I64)
2006 }
2007 fn visit_f32_abs(&mut self) -> Self::Output {
2008 self.check_funary_op(ValType::F32)
2009 }
2010 fn visit_f32_neg(&mut self) -> Self::Output {
2011 self.check_funary_op(ValType::F32)
2012 }
2013 fn visit_f32_ceil(&mut self) -> Self::Output {
2014 self.check_funary_op(ValType::F32)
2015 }
2016 fn visit_f32_floor(&mut self) -> Self::Output {
2017 self.check_funary_op(ValType::F32)
2018 }
2019 fn visit_f32_trunc(&mut self) -> Self::Output {
2020 self.check_funary_op(ValType::F32)
2021 }
2022 fn visit_f32_nearest(&mut self) -> Self::Output {
2023 self.check_funary_op(ValType::F32)
2024 }
2025 fn visit_f32_sqrt(&mut self) -> Self::Output {
2026 self.check_funary_op(ValType::F32)
2027 }
2028 fn visit_f32_add(&mut self) -> Self::Output {
2029 self.check_fbinary_op(ValType::F32)
2030 }
2031 fn visit_f32_sub(&mut self) -> Self::Output {
2032 self.check_fbinary_op(ValType::F32)
2033 }
2034 fn visit_f32_mul(&mut self) -> Self::Output {
2035 self.check_fbinary_op(ValType::F32)
2036 }
2037 fn visit_f32_div(&mut self) -> Self::Output {
2038 self.check_fbinary_op(ValType::F32)
2039 }
2040 fn visit_f32_min(&mut self) -> Self::Output {
2041 self.check_fbinary_op(ValType::F32)
2042 }
2043 fn visit_f32_max(&mut self) -> Self::Output {
2044 self.check_fbinary_op(ValType::F32)
2045 }
2046 fn visit_f32_copysign(&mut self) -> Self::Output {
2047 self.check_fbinary_op(ValType::F32)
2048 }
2049 fn visit_f64_abs(&mut self) -> Self::Output {
2050 self.check_funary_op(ValType::F64)
2051 }
2052 fn visit_f64_neg(&mut self) -> Self::Output {
2053 self.check_funary_op(ValType::F64)
2054 }
2055 fn visit_f64_ceil(&mut self) -> Self::Output {
2056 self.check_funary_op(ValType::F64)
2057 }
2058 fn visit_f64_floor(&mut self) -> Self::Output {
2059 self.check_funary_op(ValType::F64)
2060 }
2061 fn visit_f64_trunc(&mut self) -> Self::Output {
2062 self.check_funary_op(ValType::F64)
2063 }
2064 fn visit_f64_nearest(&mut self) -> Self::Output {
2065 self.check_funary_op(ValType::F64)
2066 }
2067 fn visit_f64_sqrt(&mut self) -> Self::Output {
2068 self.check_funary_op(ValType::F64)
2069 }
2070 fn visit_f64_add(&mut self) -> Self::Output {
2071 self.check_fbinary_op(ValType::F64)
2072 }
2073 fn visit_f64_sub(&mut self) -> Self::Output {
2074 self.check_fbinary_op(ValType::F64)
2075 }
2076 fn visit_f64_mul(&mut self) -> Self::Output {
2077 self.check_fbinary_op(ValType::F64)
2078 }
2079 fn visit_f64_div(&mut self) -> Self::Output {
2080 self.check_fbinary_op(ValType::F64)
2081 }
2082 fn visit_f64_min(&mut self) -> Self::Output {
2083 self.check_fbinary_op(ValType::F64)
2084 }
2085 fn visit_f64_max(&mut self) -> Self::Output {
2086 self.check_fbinary_op(ValType::F64)
2087 }
2088 fn visit_f64_copysign(&mut self) -> Self::Output {
2089 self.check_fbinary_op(ValType::F64)
2090 }
2091 fn visit_i32_wrap_i64(&mut self) -> Self::Output {
2092 self.check_conversion_op(ValType::I32, ValType::I64)
2093 }
2094 fn visit_i32_trunc_f32_s(&mut self) -> Self::Output {
2095 self.check_conversion_op(ValType::I32, ValType::F32)
2096 }
2097 fn visit_i32_trunc_f32_u(&mut self) -> Self::Output {
2098 self.check_conversion_op(ValType::I32, ValType::F32)
2099 }
2100 fn visit_i32_trunc_f64_s(&mut self) -> Self::Output {
2101 self.check_conversion_op(ValType::I32, ValType::F64)
2102 }
2103 fn visit_i32_trunc_f64_u(&mut self) -> Self::Output {
2104 self.check_conversion_op(ValType::I32, ValType::F64)
2105 }
2106 fn visit_i64_extend_i32_s(&mut self) -> Self::Output {
2107 self.check_conversion_op(ValType::I64, ValType::I32)
2108 }
2109 fn visit_i64_extend_i32_u(&mut self) -> Self::Output {
2110 self.check_conversion_op(ValType::I64, ValType::I32)
2111 }
2112 fn visit_i64_trunc_f32_s(&mut self) -> Self::Output {
2113 self.check_conversion_op(ValType::I64, ValType::F32)
2114 }
2115 fn visit_i64_trunc_f32_u(&mut self) -> Self::Output {
2116 self.check_conversion_op(ValType::I64, ValType::F32)
2117 }
2118 fn visit_i64_trunc_f64_s(&mut self) -> Self::Output {
2119 self.check_conversion_op(ValType::I64, ValType::F64)
2120 }
2121 fn visit_i64_trunc_f64_u(&mut self) -> Self::Output {
2122 self.check_conversion_op(ValType::I64, ValType::F64)
2123 }
2124 fn visit_f32_convert_i32_s(&mut self) -> Self::Output {
2125 self.check_fconversion_op(ValType::F32, ValType::I32)
2126 }
2127 fn visit_f32_convert_i32_u(&mut self) -> Self::Output {
2128 self.check_fconversion_op(ValType::F32, ValType::I32)
2129 }
2130 fn visit_f32_convert_i64_s(&mut self) -> Self::Output {
2131 self.check_fconversion_op(ValType::F32, ValType::I64)
2132 }
2133 fn visit_f32_convert_i64_u(&mut self) -> Self::Output {
2134 self.check_fconversion_op(ValType::F32, ValType::I64)
2135 }
2136 fn visit_f32_demote_f64(&mut self) -> Self::Output {
2137 self.check_fconversion_op(ValType::F32, ValType::F64)
2138 }
2139 fn visit_f64_convert_i32_s(&mut self) -> Self::Output {
2140 self.check_fconversion_op(ValType::F64, ValType::I32)
2141 }
2142 fn visit_f64_convert_i32_u(&mut self) -> Self::Output {
2143 self.check_fconversion_op(ValType::F64, ValType::I32)
2144 }
2145 fn visit_f64_convert_i64_s(&mut self) -> Self::Output {
2146 self.check_fconversion_op(ValType::F64, ValType::I64)
2147 }
2148 fn visit_f64_convert_i64_u(&mut self) -> Self::Output {
2149 self.check_fconversion_op(ValType::F64, ValType::I64)
2150 }
2151 fn visit_f64_promote_f32(&mut self) -> Self::Output {
2152 self.check_fconversion_op(ValType::F64, ValType::F32)
2153 }
2154 fn visit_i32_reinterpret_f32(&mut self) -> Self::Output {
2155 self.check_conversion_op(ValType::I32, ValType::F32)
2156 }
2157 fn visit_i64_reinterpret_f64(&mut self) -> Self::Output {
2158 self.check_conversion_op(ValType::I64, ValType::F64)
2159 }
2160 fn visit_f32_reinterpret_i32(&mut self) -> Self::Output {
2161 self.check_fconversion_op(ValType::F32, ValType::I32)
2162 }
2163 fn visit_f64_reinterpret_i64(&mut self) -> Self::Output {
2164 self.check_fconversion_op(ValType::F64, ValType::I64)
2165 }
2166 fn visit_i32_trunc_sat_f32_s(&mut self) -> Self::Output {
2167 self.check_conversion_op(ValType::I32, ValType::F32)
2168 }
2169 fn visit_i32_trunc_sat_f32_u(&mut self) -> Self::Output {
2170 self.check_conversion_op(ValType::I32, ValType::F32)
2171 }
2172 fn visit_i32_trunc_sat_f64_s(&mut self) -> Self::Output {
2173 self.check_conversion_op(ValType::I32, ValType::F64)
2174 }
2175 fn visit_i32_trunc_sat_f64_u(&mut self) -> Self::Output {
2176 self.check_conversion_op(ValType::I32, ValType::F64)
2177 }
2178 fn visit_i64_trunc_sat_f32_s(&mut self) -> Self::Output {
2179 self.check_conversion_op(ValType::I64, ValType::F32)
2180 }
2181 fn visit_i64_trunc_sat_f32_u(&mut self) -> Self::Output {
2182 self.check_conversion_op(ValType::I64, ValType::F32)
2183 }
2184 fn visit_i64_trunc_sat_f64_s(&mut self) -> Self::Output {
2185 self.check_conversion_op(ValType::I64, ValType::F64)
2186 }
2187 fn visit_i64_trunc_sat_f64_u(&mut self) -> Self::Output {
2188 self.check_conversion_op(ValType::I64, ValType::F64)
2189 }
2190 fn visit_i32_extend8_s(&mut self) -> Self::Output {
2191 self.check_unary_op(ValType::I32)
2192 }
2193 fn visit_i32_extend16_s(&mut self) -> Self::Output {
2194 self.check_unary_op(ValType::I32)
2195 }
2196 fn visit_i64_extend8_s(&mut self) -> Self::Output {
2197 self.check_unary_op(ValType::I64)
2198 }
2199 fn visit_i64_extend16_s(&mut self) -> Self::Output {
2200 self.check_unary_op(ValType::I64)
2201 }
2202 fn visit_i64_extend32_s(&mut self) -> Self::Output {
2203 self.check_unary_op(ValType::I64)
2204 }
2205 fn visit_i32_atomic_load(&mut self, memarg: MemArg) -> Self::Output {
2206 self.check_atomic_load(memarg, ValType::I32)
2207 }
2208 fn visit_i32_atomic_load16_u(&mut self, memarg: MemArg) -> Self::Output {
2209 self.check_atomic_load(memarg, ValType::I32)
2210 }
2211 fn visit_i32_atomic_load8_u(&mut self, memarg: MemArg) -> Self::Output {
2212 self.check_atomic_load(memarg, ValType::I32)
2213 }
2214 fn visit_i64_atomic_load(&mut self, memarg: MemArg) -> Self::Output {
2215 self.check_atomic_load(memarg, ValType::I64)
2216 }
2217 fn visit_i64_atomic_load32_u(&mut self, memarg: MemArg) -> Self::Output {
2218 self.check_atomic_load(memarg, ValType::I64)
2219 }
2220 fn visit_i64_atomic_load16_u(&mut self, memarg: MemArg) -> Self::Output {
2221 self.check_atomic_load(memarg, ValType::I64)
2222 }
2223 fn visit_i64_atomic_load8_u(&mut self, memarg: MemArg) -> Self::Output {
2224 self.check_atomic_load(memarg, ValType::I64)
2225 }
2226 fn visit_i32_atomic_store(&mut self, memarg: MemArg) -> Self::Output {
2227 self.check_atomic_store(memarg, ValType::I32)
2228 }
2229 fn visit_i32_atomic_store16(&mut self, memarg: MemArg) -> Self::Output {
2230 self.check_atomic_store(memarg, ValType::I32)
2231 }
2232 fn visit_i32_atomic_store8(&mut self, memarg: MemArg) -> Self::Output {
2233 self.check_atomic_store(memarg, ValType::I32)
2234 }
2235 fn visit_i64_atomic_store(&mut self, memarg: MemArg) -> Self::Output {
2236 self.check_atomic_store(memarg, ValType::I64)
2237 }
2238 fn visit_i64_atomic_store32(&mut self, memarg: MemArg) -> Self::Output {
2239 self.check_atomic_store(memarg, ValType::I64)
2240 }
2241 fn visit_i64_atomic_store16(&mut self, memarg: MemArg) -> Self::Output {
2242 self.check_atomic_store(memarg, ValType::I64)
2243 }
2244 fn visit_i64_atomic_store8(&mut self, memarg: MemArg) -> Self::Output {
2245 self.check_atomic_store(memarg, ValType::I64)
2246 }
2247 fn visit_i32_atomic_rmw_add(&mut self, memarg: MemArg) -> Self::Output {
2248 self.check_atomic_binary_op(memarg, ValType::I32)
2249 }
2250 fn visit_i32_atomic_rmw_sub(&mut self, memarg: MemArg) -> Self::Output {
2251 self.check_atomic_binary_op(memarg, ValType::I32)
2252 }
2253 fn visit_i32_atomic_rmw_and(&mut self, memarg: MemArg) -> Self::Output {
2254 self.check_atomic_binary_op(memarg, ValType::I32)
2255 }
2256 fn visit_i32_atomic_rmw_or(&mut self, memarg: MemArg) -> Self::Output {
2257 self.check_atomic_binary_op(memarg, ValType::I32)
2258 }
2259 fn visit_i32_atomic_rmw_xor(&mut self, memarg: MemArg) -> Self::Output {
2260 self.check_atomic_binary_op(memarg, ValType::I32)
2261 }
2262 fn visit_i32_atomic_rmw16_add_u(&mut self, memarg: MemArg) -> Self::Output {
2263 self.check_atomic_binary_op(memarg, ValType::I32)
2264 }
2265 fn visit_i32_atomic_rmw16_sub_u(&mut self, memarg: MemArg) -> Self::Output {
2266 self.check_atomic_binary_op(memarg, ValType::I32)
2267 }
2268 fn visit_i32_atomic_rmw16_and_u(&mut self, memarg: MemArg) -> Self::Output {
2269 self.check_atomic_binary_op(memarg, ValType::I32)
2270 }
2271 fn visit_i32_atomic_rmw16_or_u(&mut self, memarg: MemArg) -> Self::Output {
2272 self.check_atomic_binary_op(memarg, ValType::I32)
2273 }
2274 fn visit_i32_atomic_rmw16_xor_u(&mut self, memarg: MemArg) -> Self::Output {
2275 self.check_atomic_binary_op(memarg, ValType::I32)
2276 }
2277 fn visit_i32_atomic_rmw8_add_u(&mut self, memarg: MemArg) -> Self::Output {
2278 self.check_atomic_binary_op(memarg, ValType::I32)
2279 }
2280 fn visit_i32_atomic_rmw8_sub_u(&mut self, memarg: MemArg) -> Self::Output {
2281 self.check_atomic_binary_op(memarg, ValType::I32)
2282 }
2283 fn visit_i32_atomic_rmw8_and_u(&mut self, memarg: MemArg) -> Self::Output {
2284 self.check_atomic_binary_op(memarg, ValType::I32)
2285 }
2286 fn visit_i32_atomic_rmw8_or_u(&mut self, memarg: MemArg) -> Self::Output {
2287 self.check_atomic_binary_op(memarg, ValType::I32)
2288 }
2289 fn visit_i32_atomic_rmw8_xor_u(&mut self, memarg: MemArg) -> Self::Output {
2290 self.check_atomic_binary_op(memarg, ValType::I32)
2291 }
2292 fn visit_i64_atomic_rmw_add(&mut self, memarg: MemArg) -> Self::Output {
2293 self.check_atomic_binary_op(memarg, ValType::I64)
2294 }
2295 fn visit_i64_atomic_rmw_sub(&mut self, memarg: MemArg) -> Self::Output {
2296 self.check_atomic_binary_op(memarg, ValType::I64)
2297 }
2298 fn visit_i64_atomic_rmw_and(&mut self, memarg: MemArg) -> Self::Output {
2299 self.check_atomic_binary_op(memarg, ValType::I64)
2300 }
2301 fn visit_i64_atomic_rmw_or(&mut self, memarg: MemArg) -> Self::Output {
2302 self.check_atomic_binary_op(memarg, ValType::I64)
2303 }
2304 fn visit_i64_atomic_rmw_xor(&mut self, memarg: MemArg) -> Self::Output {
2305 self.check_atomic_binary_op(memarg, ValType::I64)
2306 }
2307 fn visit_i64_atomic_rmw32_add_u(&mut self, memarg: MemArg) -> Self::Output {
2308 self.check_atomic_binary_op(memarg, ValType::I64)
2309 }
2310 fn visit_i64_atomic_rmw32_sub_u(&mut self, memarg: MemArg) -> Self::Output {
2311 self.check_atomic_binary_op(memarg, ValType::I64)
2312 }
2313 fn visit_i64_atomic_rmw32_and_u(&mut self, memarg: MemArg) -> Self::Output {
2314 self.check_atomic_binary_op(memarg, ValType::I64)
2315 }
2316 fn visit_i64_atomic_rmw32_or_u(&mut self, memarg: MemArg) -> Self::Output {
2317 self.check_atomic_binary_op(memarg, ValType::I64)
2318 }
2319 fn visit_i64_atomic_rmw32_xor_u(&mut self, memarg: MemArg) -> Self::Output {
2320 self.check_atomic_binary_op(memarg, ValType::I64)
2321 }
2322 fn visit_i64_atomic_rmw16_add_u(&mut self, memarg: MemArg) -> Self::Output {
2323 self.check_atomic_binary_op(memarg, ValType::I64)
2324 }
2325 fn visit_i64_atomic_rmw16_sub_u(&mut self, memarg: MemArg) -> Self::Output {
2326 self.check_atomic_binary_op(memarg, ValType::I64)
2327 }
2328 fn visit_i64_atomic_rmw16_and_u(&mut self, memarg: MemArg) -> Self::Output {
2329 self.check_atomic_binary_op(memarg, ValType::I64)
2330 }
2331 fn visit_i64_atomic_rmw16_or_u(&mut self, memarg: MemArg) -> Self::Output {
2332 self.check_atomic_binary_op(memarg, ValType::I64)
2333 }
2334 fn visit_i64_atomic_rmw16_xor_u(&mut self, memarg: MemArg) -> Self::Output {
2335 self.check_atomic_binary_op(memarg, ValType::I64)
2336 }
2337 fn visit_i64_atomic_rmw8_add_u(&mut self, memarg: MemArg) -> Self::Output {
2338 self.check_atomic_binary_op(memarg, ValType::I64)
2339 }
2340 fn visit_i64_atomic_rmw8_sub_u(&mut self, memarg: MemArg) -> Self::Output {
2341 self.check_atomic_binary_op(memarg, ValType::I64)
2342 }
2343 fn visit_i64_atomic_rmw8_and_u(&mut self, memarg: MemArg) -> Self::Output {
2344 self.check_atomic_binary_op(memarg, ValType::I64)
2345 }
2346 fn visit_i64_atomic_rmw8_or_u(&mut self, memarg: MemArg) -> Self::Output {
2347 self.check_atomic_binary_op(memarg, ValType::I64)
2348 }
2349 fn visit_i64_atomic_rmw8_xor_u(&mut self, memarg: MemArg) -> Self::Output {
2350 self.check_atomic_binary_op(memarg, ValType::I64)
2351 }
2352 fn visit_i32_atomic_rmw_xchg(&mut self, memarg: MemArg) -> Self::Output {
2353 self.check_atomic_binary_op(memarg, ValType::I32)
2354 }
2355 fn visit_i32_atomic_rmw16_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
2356 self.check_atomic_binary_op(memarg, ValType::I32)
2357 }
2358 fn visit_i32_atomic_rmw8_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
2359 self.check_atomic_binary_op(memarg, ValType::I32)
2360 }
2361 fn visit_i32_atomic_rmw_cmpxchg(&mut self, memarg: MemArg) -> Self::Output {
2362 self.check_atomic_binary_cmpxchg(memarg, ValType::I32)
2363 }
2364 fn visit_i32_atomic_rmw16_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
2365 self.check_atomic_binary_cmpxchg(memarg, ValType::I32)
2366 }
2367 fn visit_i32_atomic_rmw8_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
2368 self.check_atomic_binary_cmpxchg(memarg, ValType::I32)
2369 }
2370 fn visit_i64_atomic_rmw_xchg(&mut self, memarg: MemArg) -> Self::Output {
2371 self.check_atomic_binary_op(memarg, ValType::I64)
2372 }
2373 fn visit_i64_atomic_rmw32_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
2374 self.check_atomic_binary_op(memarg, ValType::I64)
2375 }
2376 fn visit_i64_atomic_rmw16_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
2377 self.check_atomic_binary_op(memarg, ValType::I64)
2378 }
2379 fn visit_i64_atomic_rmw8_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
2380 self.check_atomic_binary_op(memarg, ValType::I64)
2381 }
2382 fn visit_i64_atomic_rmw_cmpxchg(&mut self, memarg: MemArg) -> Self::Output {
2383 self.check_atomic_binary_cmpxchg(memarg, ValType::I64)
2384 }
2385 fn visit_i64_atomic_rmw32_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
2386 self.check_atomic_binary_cmpxchg(memarg, ValType::I64)
2387 }
2388 fn visit_i64_atomic_rmw16_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
2389 self.check_atomic_binary_cmpxchg(memarg, ValType::I64)
2390 }
2391 fn visit_i64_atomic_rmw8_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
2392 self.check_atomic_binary_cmpxchg(memarg, ValType::I64)
2393 }
2394 fn visit_memory_atomic_notify(&mut self, memarg: MemArg) -> Self::Output {
2395 self.check_atomic_binary_op(memarg, ValType::I32)
2396 }
2397 fn visit_memory_atomic_wait32(&mut self, memarg: MemArg) -> Self::Output {
2398 let ty = self.check_shared_memarg(memarg)?;
2399 self.pop_operand(Some(ValType::I64))?;
2400 self.pop_operand(Some(ValType::I32))?;
2401 self.pop_operand(Some(ty))?;
2402 self.push_operand(ValType::I32)?;
2403 Ok(())
2404 }
2405 fn visit_memory_atomic_wait64(&mut self, memarg: MemArg) -> Self::Output {
2406 let ty = self.check_shared_memarg(memarg)?;
2407 self.pop_operand(Some(ValType::I64))?;
2408 self.pop_operand(Some(ValType::I64))?;
2409 self.pop_operand(Some(ty))?;
2410 self.push_operand(ValType::I32)?;
2411 Ok(())
2412 }
2413 fn visit_atomic_fence(&mut self) -> Self::Output {
2414 Ok(())
2415 }
2416 fn visit_ref_null(&mut self, mut heap_type: HeapType) -> Self::Output {
2417 if let Some(ty) = RefType::new(true, heap_type) {
2418 self.features
2419 .check_ref_type(ty)
2420 .map_err(|e| BinaryReaderError::new(e, self.offset))?;
2421 }
2422 self.resources
2423 .check_heap_type(&mut heap_type, self.offset)?;
2424 let ty = ValType::Ref(
2425 RefType::new(true, heap_type).expect("existing heap types should be within our limits"),
2426 );
2427 self.push_operand(ty)?;
2428 Ok(())
2429 }
2430
2431 fn visit_ref_as_non_null(&mut self) -> Self::Output {
2432 let ty = match self.pop_ref()? {
2433 Some(ty) => MaybeType::Type(ValType::Ref(ty.as_non_null())),
2434 None => MaybeType::HeapBot,
2435 };
2436 self.push_operand(ty)?;
2437 Ok(())
2438 }
2439 fn visit_br_on_null(&mut self, relative_depth: u32) -> Self::Output {
2440 let ref_ty = match self.pop_ref()? {
2441 None => MaybeType::HeapBot,
2442 Some(ty) => MaybeType::Type(ValType::Ref(ty.as_non_null())),
2443 };
2444 let (ft, kind) = self.jump(relative_depth)?;
2445 let label_types = self.label_types(ft, kind)?;
2446 self.pop_push_label_types(label_types)?;
2447 self.push_operand(ref_ty)?;
2448 Ok(())
2449 }
2450 fn visit_br_on_non_null(&mut self, relative_depth: u32) -> Self::Output {
2451 let ty = self.pop_ref()?;
2452 let (ft, kind) = self.jump(relative_depth)?;
2453
2454 let mut label_types = self.label_types(ft, kind)?;
2455 match (label_types.next_back(), ty) {
2456 (None, _) => bail!(
2457 self.offset,
2458 "type mismatch: br_on_non_null target has no label types",
2459 ),
2460 (Some(ValType::Ref(_)), None) => {}
2461 (Some(rt1 @ ValType::Ref(_)), Some(rt0)) => {
2462 let ty = rt0.as_non_null();
2466 if !self.resources.is_subtype(ty.into(), rt1) {
2467 bail!(
2468 self.offset,
2469 "type mismatch: expected {} but found {}",
2470 ty_to_str(rt0.into()),
2471 ty_to_str(rt1)
2472 )
2473 }
2474 }
2475 (Some(_), _) => bail!(
2476 self.offset,
2477 "type mismatch: br_on_non_null target does not end with heap type",
2478 ),
2479 }
2480
2481 self.pop_push_label_types(label_types)?;
2482 Ok(())
2483 }
2484 fn visit_ref_is_null(&mut self) -> Self::Output {
2485 self.pop_ref()?;
2486 self.push_operand(ValType::I32)?;
2487 Ok(())
2488 }
2489 fn visit_ref_func(&mut self, function_index: u32) -> Self::Output {
2490 let type_id = match self.resources.type_id_of_function(function_index) {
2491 Some(id) => id,
2492 None => bail!(
2493 self.offset,
2494 "unknown function {}: function index out of bounds",
2495 function_index,
2496 ),
2497 };
2498 if !self.resources.is_function_referenced(function_index) {
2499 bail!(self.offset, "undeclared function reference");
2500 }
2501
2502 let index = UnpackedIndex::Id(type_id);
2503 let ty = ValType::Ref(
2504 RefType::new(false, HeapType::Concrete(index)).ok_or_else(|| {
2505 BinaryReaderError::new("implementation limit: type index too large", self.offset)
2506 })?,
2507 );
2508 self.push_operand(ty)?;
2509 Ok(())
2510 }
2511 fn visit_ref_eq(&mut self) -> Self::Output {
2512 self.pop_operand(Some(RefType::EQ.nullable().into()))?;
2513 self.pop_operand(Some(RefType::EQ.nullable().into()))?;
2514 self.push_operand(ValType::I32)
2515 }
2516 fn visit_v128_load(&mut self, memarg: MemArg) -> Self::Output {
2517 let ty = self.check_memarg(memarg)?;
2518 self.pop_operand(Some(ty))?;
2519 self.push_operand(ValType::V128)?;
2520 Ok(())
2521 }
2522 fn visit_v128_store(&mut self, memarg: MemArg) -> Self::Output {
2523 let ty = self.check_memarg(memarg)?;
2524 self.pop_operand(Some(ValType::V128))?;
2525 self.pop_operand(Some(ty))?;
2526 Ok(())
2527 }
2528 fn visit_v128_const(&mut self, _value: V128) -> Self::Output {
2529 self.push_operand(ValType::V128)?;
2530 Ok(())
2531 }
2532 fn visit_i8x16_splat(&mut self) -> Self::Output {
2533 self.check_v128_splat(ValType::I32)
2534 }
2535 fn visit_i16x8_splat(&mut self) -> Self::Output {
2536 self.check_v128_splat(ValType::I32)
2537 }
2538 fn visit_i32x4_splat(&mut self) -> Self::Output {
2539 self.check_v128_splat(ValType::I32)
2540 }
2541 fn visit_i64x2_splat(&mut self) -> Self::Output {
2542 self.check_v128_splat(ValType::I64)
2543 }
2544 fn visit_f32x4_splat(&mut self) -> Self::Output {
2545 self.check_floats_enabled()?;
2546 self.check_v128_splat(ValType::F32)
2547 }
2548 fn visit_f64x2_splat(&mut self) -> Self::Output {
2549 self.check_floats_enabled()?;
2550 self.check_v128_splat(ValType::F64)
2551 }
2552 fn visit_i8x16_extract_lane_s(&mut self, lane: u8) -> Self::Output {
2553 self.check_simd_lane_index(lane, 16)?;
2554 self.pop_operand(Some(ValType::V128))?;
2555 self.push_operand(ValType::I32)?;
2556 Ok(())
2557 }
2558 fn visit_i8x16_extract_lane_u(&mut self, lane: u8) -> Self::Output {
2559 self.visit_i8x16_extract_lane_s(lane)
2560 }
2561 fn visit_i16x8_extract_lane_s(&mut self, lane: u8) -> Self::Output {
2562 self.check_simd_lane_index(lane, 8)?;
2563 self.pop_operand(Some(ValType::V128))?;
2564 self.push_operand(ValType::I32)?;
2565 Ok(())
2566 }
2567 fn visit_i16x8_extract_lane_u(&mut self, lane: u8) -> Self::Output {
2568 self.visit_i16x8_extract_lane_s(lane)
2569 }
2570 fn visit_i32x4_extract_lane(&mut self, lane: u8) -> Self::Output {
2571 self.check_simd_lane_index(lane, 4)?;
2572 self.pop_operand(Some(ValType::V128))?;
2573 self.push_operand(ValType::I32)?;
2574 Ok(())
2575 }
2576 fn visit_i8x16_replace_lane(&mut self, lane: u8) -> Self::Output {
2577 self.check_simd_lane_index(lane, 16)?;
2578 self.pop_operand(Some(ValType::I32))?;
2579 self.pop_operand(Some(ValType::V128))?;
2580 self.push_operand(ValType::V128)?;
2581 Ok(())
2582 }
2583 fn visit_i16x8_replace_lane(&mut self, lane: u8) -> Self::Output {
2584 self.check_simd_lane_index(lane, 8)?;
2585 self.pop_operand(Some(ValType::I32))?;
2586 self.pop_operand(Some(ValType::V128))?;
2587 self.push_operand(ValType::V128)?;
2588 Ok(())
2589 }
2590 fn visit_i32x4_replace_lane(&mut self, lane: u8) -> Self::Output {
2591 self.check_simd_lane_index(lane, 4)?;
2592 self.pop_operand(Some(ValType::I32))?;
2593 self.pop_operand(Some(ValType::V128))?;
2594 self.push_operand(ValType::V128)?;
2595 Ok(())
2596 }
2597 fn visit_i64x2_extract_lane(&mut self, lane: u8) -> Self::Output {
2598 self.check_simd_lane_index(lane, 2)?;
2599 self.pop_operand(Some(ValType::V128))?;
2600 self.push_operand(ValType::I64)?;
2601 Ok(())
2602 }
2603 fn visit_i64x2_replace_lane(&mut self, lane: u8) -> Self::Output {
2604 self.check_simd_lane_index(lane, 2)?;
2605 self.pop_operand(Some(ValType::I64))?;
2606 self.pop_operand(Some(ValType::V128))?;
2607 self.push_operand(ValType::V128)?;
2608 Ok(())
2609 }
2610 fn visit_f32x4_extract_lane(&mut self, lane: u8) -> Self::Output {
2611 self.check_floats_enabled()?;
2612 self.check_simd_lane_index(lane, 4)?;
2613 self.pop_operand(Some(ValType::V128))?;
2614 self.push_operand(ValType::F32)?;
2615 Ok(())
2616 }
2617 fn visit_f32x4_replace_lane(&mut self, lane: u8) -> Self::Output {
2618 self.check_floats_enabled()?;
2619 self.check_simd_lane_index(lane, 4)?;
2620 self.pop_operand(Some(ValType::F32))?;
2621 self.pop_operand(Some(ValType::V128))?;
2622 self.push_operand(ValType::V128)?;
2623 Ok(())
2624 }
2625 fn visit_f64x2_extract_lane(&mut self, lane: u8) -> Self::Output {
2626 self.check_floats_enabled()?;
2627 self.check_simd_lane_index(lane, 2)?;
2628 self.pop_operand(Some(ValType::V128))?;
2629 self.push_operand(ValType::F64)?;
2630 Ok(())
2631 }
2632 fn visit_f64x2_replace_lane(&mut self, lane: u8) -> Self::Output {
2633 self.check_floats_enabled()?;
2634 self.check_simd_lane_index(lane, 2)?;
2635 self.pop_operand(Some(ValType::F64))?;
2636 self.pop_operand(Some(ValType::V128))?;
2637 self.push_operand(ValType::V128)?;
2638 Ok(())
2639 }
2640 fn visit_f32x4_eq(&mut self) -> Self::Output {
2641 self.check_v128_fbinary_op()
2642 }
2643 fn visit_f32x4_ne(&mut self) -> Self::Output {
2644 self.check_v128_fbinary_op()
2645 }
2646 fn visit_f32x4_lt(&mut self) -> Self::Output {
2647 self.check_v128_fbinary_op()
2648 }
2649 fn visit_f32x4_gt(&mut self) -> Self::Output {
2650 self.check_v128_fbinary_op()
2651 }
2652 fn visit_f32x4_le(&mut self) -> Self::Output {
2653 self.check_v128_fbinary_op()
2654 }
2655 fn visit_f32x4_ge(&mut self) -> Self::Output {
2656 self.check_v128_fbinary_op()
2657 }
2658 fn visit_f64x2_eq(&mut self) -> Self::Output {
2659 self.check_v128_fbinary_op()
2660 }
2661 fn visit_f64x2_ne(&mut self) -> Self::Output {
2662 self.check_v128_fbinary_op()
2663 }
2664 fn visit_f64x2_lt(&mut self) -> Self::Output {
2665 self.check_v128_fbinary_op()
2666 }
2667 fn visit_f64x2_gt(&mut self) -> Self::Output {
2668 self.check_v128_fbinary_op()
2669 }
2670 fn visit_f64x2_le(&mut self) -> Self::Output {
2671 self.check_v128_fbinary_op()
2672 }
2673 fn visit_f64x2_ge(&mut self) -> Self::Output {
2674 self.check_v128_fbinary_op()
2675 }
2676 fn visit_f32x4_add(&mut self) -> Self::Output {
2677 self.check_v128_fbinary_op()
2678 }
2679 fn visit_f32x4_sub(&mut self) -> Self::Output {
2680 self.check_v128_fbinary_op()
2681 }
2682 fn visit_f32x4_mul(&mut self) -> Self::Output {
2683 self.check_v128_fbinary_op()
2684 }
2685 fn visit_f32x4_div(&mut self) -> Self::Output {
2686 self.check_v128_fbinary_op()
2687 }
2688 fn visit_f32x4_min(&mut self) -> Self::Output {
2689 self.check_v128_fbinary_op()
2690 }
2691 fn visit_f32x4_max(&mut self) -> Self::Output {
2692 self.check_v128_fbinary_op()
2693 }
2694 fn visit_f32x4_pmin(&mut self) -> Self::Output {
2695 self.check_v128_fbinary_op()
2696 }
2697 fn visit_f32x4_pmax(&mut self) -> Self::Output {
2698 self.check_v128_fbinary_op()
2699 }
2700 fn visit_f64x2_add(&mut self) -> Self::Output {
2701 self.check_v128_fbinary_op()
2702 }
2703 fn visit_f64x2_sub(&mut self) -> Self::Output {
2704 self.check_v128_fbinary_op()
2705 }
2706 fn visit_f64x2_mul(&mut self) -> Self::Output {
2707 self.check_v128_fbinary_op()
2708 }
2709 fn visit_f64x2_div(&mut self) -> Self::Output {
2710 self.check_v128_fbinary_op()
2711 }
2712 fn visit_f64x2_min(&mut self) -> Self::Output {
2713 self.check_v128_fbinary_op()
2714 }
2715 fn visit_f64x2_max(&mut self) -> Self::Output {
2716 self.check_v128_fbinary_op()
2717 }
2718 fn visit_f64x2_pmin(&mut self) -> Self::Output {
2719 self.check_v128_fbinary_op()
2720 }
2721 fn visit_f64x2_pmax(&mut self) -> Self::Output {
2722 self.check_v128_fbinary_op()
2723 }
2724 fn visit_i8x16_eq(&mut self) -> Self::Output {
2725 self.check_v128_binary_op()
2726 }
2727 fn visit_i8x16_ne(&mut self) -> Self::Output {
2728 self.check_v128_binary_op()
2729 }
2730 fn visit_i8x16_lt_s(&mut self) -> Self::Output {
2731 self.check_v128_binary_op()
2732 }
2733 fn visit_i8x16_lt_u(&mut self) -> Self::Output {
2734 self.check_v128_binary_op()
2735 }
2736 fn visit_i8x16_gt_s(&mut self) -> Self::Output {
2737 self.check_v128_binary_op()
2738 }
2739 fn visit_i8x16_gt_u(&mut self) -> Self::Output {
2740 self.check_v128_binary_op()
2741 }
2742 fn visit_i8x16_le_s(&mut self) -> Self::Output {
2743 self.check_v128_binary_op()
2744 }
2745 fn visit_i8x16_le_u(&mut self) -> Self::Output {
2746 self.check_v128_binary_op()
2747 }
2748 fn visit_i8x16_ge_s(&mut self) -> Self::Output {
2749 self.check_v128_binary_op()
2750 }
2751 fn visit_i8x16_ge_u(&mut self) -> Self::Output {
2752 self.check_v128_binary_op()
2753 }
2754 fn visit_i16x8_eq(&mut self) -> Self::Output {
2755 self.check_v128_binary_op()
2756 }
2757 fn visit_i16x8_ne(&mut self) -> Self::Output {
2758 self.check_v128_binary_op()
2759 }
2760 fn visit_i16x8_lt_s(&mut self) -> Self::Output {
2761 self.check_v128_binary_op()
2762 }
2763 fn visit_i16x8_lt_u(&mut self) -> Self::Output {
2764 self.check_v128_binary_op()
2765 }
2766 fn visit_i16x8_gt_s(&mut self) -> Self::Output {
2767 self.check_v128_binary_op()
2768 }
2769 fn visit_i16x8_gt_u(&mut self) -> Self::Output {
2770 self.check_v128_binary_op()
2771 }
2772 fn visit_i16x8_le_s(&mut self) -> Self::Output {
2773 self.check_v128_binary_op()
2774 }
2775 fn visit_i16x8_le_u(&mut self) -> Self::Output {
2776 self.check_v128_binary_op()
2777 }
2778 fn visit_i16x8_ge_s(&mut self) -> Self::Output {
2779 self.check_v128_binary_op()
2780 }
2781 fn visit_i16x8_ge_u(&mut self) -> Self::Output {
2782 self.check_v128_binary_op()
2783 }
2784 fn visit_i32x4_eq(&mut self) -> Self::Output {
2785 self.check_v128_binary_op()
2786 }
2787 fn visit_i32x4_ne(&mut self) -> Self::Output {
2788 self.check_v128_binary_op()
2789 }
2790 fn visit_i32x4_lt_s(&mut self) -> Self::Output {
2791 self.check_v128_binary_op()
2792 }
2793 fn visit_i32x4_lt_u(&mut self) -> Self::Output {
2794 self.check_v128_binary_op()
2795 }
2796 fn visit_i32x4_gt_s(&mut self) -> Self::Output {
2797 self.check_v128_binary_op()
2798 }
2799 fn visit_i32x4_gt_u(&mut self) -> Self::Output {
2800 self.check_v128_binary_op()
2801 }
2802 fn visit_i32x4_le_s(&mut self) -> Self::Output {
2803 self.check_v128_binary_op()
2804 }
2805 fn visit_i32x4_le_u(&mut self) -> Self::Output {
2806 self.check_v128_binary_op()
2807 }
2808 fn visit_i32x4_ge_s(&mut self) -> Self::Output {
2809 self.check_v128_binary_op()
2810 }
2811 fn visit_i32x4_ge_u(&mut self) -> Self::Output {
2812 self.check_v128_binary_op()
2813 }
2814 fn visit_i64x2_eq(&mut self) -> Self::Output {
2815 self.check_v128_binary_op()
2816 }
2817 fn visit_i64x2_ne(&mut self) -> Self::Output {
2818 self.check_v128_binary_op()
2819 }
2820 fn visit_i64x2_lt_s(&mut self) -> Self::Output {
2821 self.check_v128_binary_op()
2822 }
2823 fn visit_i64x2_gt_s(&mut self) -> Self::Output {
2824 self.check_v128_binary_op()
2825 }
2826 fn visit_i64x2_le_s(&mut self) -> Self::Output {
2827 self.check_v128_binary_op()
2828 }
2829 fn visit_i64x2_ge_s(&mut self) -> Self::Output {
2830 self.check_v128_binary_op()
2831 }
2832 fn visit_v128_and(&mut self) -> Self::Output {
2833 self.check_v128_binary_op()
2834 }
2835 fn visit_v128_andnot(&mut self) -> Self::Output {
2836 self.check_v128_binary_op()
2837 }
2838 fn visit_v128_or(&mut self) -> Self::Output {
2839 self.check_v128_binary_op()
2840 }
2841 fn visit_v128_xor(&mut self) -> Self::Output {
2842 self.check_v128_binary_op()
2843 }
2844 fn visit_i8x16_add(&mut self) -> Self::Output {
2845 self.check_v128_binary_op()
2846 }
2847 fn visit_i8x16_add_sat_s(&mut self) -> Self::Output {
2848 self.check_v128_binary_op()
2849 }
2850 fn visit_i8x16_add_sat_u(&mut self) -> Self::Output {
2851 self.check_v128_binary_op()
2852 }
2853 fn visit_i8x16_sub(&mut self) -> Self::Output {
2854 self.check_v128_binary_op()
2855 }
2856 fn visit_i8x16_sub_sat_s(&mut self) -> Self::Output {
2857 self.check_v128_binary_op()
2858 }
2859 fn visit_i8x16_sub_sat_u(&mut self) -> Self::Output {
2860 self.check_v128_binary_op()
2861 }
2862 fn visit_i8x16_min_s(&mut self) -> Self::Output {
2863 self.check_v128_binary_op()
2864 }
2865 fn visit_i8x16_min_u(&mut self) -> Self::Output {
2866 self.check_v128_binary_op()
2867 }
2868 fn visit_i8x16_max_s(&mut self) -> Self::Output {
2869 self.check_v128_binary_op()
2870 }
2871 fn visit_i8x16_max_u(&mut self) -> Self::Output {
2872 self.check_v128_binary_op()
2873 }
2874 fn visit_i16x8_add(&mut self) -> Self::Output {
2875 self.check_v128_binary_op()
2876 }
2877 fn visit_i16x8_add_sat_s(&mut self) -> Self::Output {
2878 self.check_v128_binary_op()
2879 }
2880 fn visit_i16x8_add_sat_u(&mut self) -> Self::Output {
2881 self.check_v128_binary_op()
2882 }
2883 fn visit_i16x8_sub(&mut self) -> Self::Output {
2884 self.check_v128_binary_op()
2885 }
2886 fn visit_i16x8_sub_sat_s(&mut self) -> Self::Output {
2887 self.check_v128_binary_op()
2888 }
2889 fn visit_i16x8_sub_sat_u(&mut self) -> Self::Output {
2890 self.check_v128_binary_op()
2891 }
2892 fn visit_i16x8_mul(&mut self) -> Self::Output {
2893 self.check_v128_binary_op()
2894 }
2895 fn visit_i16x8_min_s(&mut self) -> Self::Output {
2896 self.check_v128_binary_op()
2897 }
2898 fn visit_i16x8_min_u(&mut self) -> Self::Output {
2899 self.check_v128_binary_op()
2900 }
2901 fn visit_i16x8_max_s(&mut self) -> Self::Output {
2902 self.check_v128_binary_op()
2903 }
2904 fn visit_i16x8_max_u(&mut self) -> Self::Output {
2905 self.check_v128_binary_op()
2906 }
2907 fn visit_i32x4_add(&mut self) -> Self::Output {
2908 self.check_v128_binary_op()
2909 }
2910 fn visit_i32x4_sub(&mut self) -> Self::Output {
2911 self.check_v128_binary_op()
2912 }
2913 fn visit_i32x4_mul(&mut self) -> Self::Output {
2914 self.check_v128_binary_op()
2915 }
2916 fn visit_i32x4_min_s(&mut self) -> Self::Output {
2917 self.check_v128_binary_op()
2918 }
2919 fn visit_i32x4_min_u(&mut self) -> Self::Output {
2920 self.check_v128_binary_op()
2921 }
2922 fn visit_i32x4_max_s(&mut self) -> Self::Output {
2923 self.check_v128_binary_op()
2924 }
2925 fn visit_i32x4_max_u(&mut self) -> Self::Output {
2926 self.check_v128_binary_op()
2927 }
2928 fn visit_i32x4_dot_i16x8_s(&mut self) -> Self::Output {
2929 self.check_v128_binary_op()
2930 }
2931 fn visit_i64x2_add(&mut self) -> Self::Output {
2932 self.check_v128_binary_op()
2933 }
2934 fn visit_i64x2_sub(&mut self) -> Self::Output {
2935 self.check_v128_binary_op()
2936 }
2937 fn visit_i64x2_mul(&mut self) -> Self::Output {
2938 self.check_v128_binary_op()
2939 }
2940 fn visit_i8x16_avgr_u(&mut self) -> Self::Output {
2941 self.check_v128_binary_op()
2942 }
2943 fn visit_i16x8_avgr_u(&mut self) -> Self::Output {
2944 self.check_v128_binary_op()
2945 }
2946 fn visit_i8x16_narrow_i16x8_s(&mut self) -> Self::Output {
2947 self.check_v128_binary_op()
2948 }
2949 fn visit_i8x16_narrow_i16x8_u(&mut self) -> Self::Output {
2950 self.check_v128_binary_op()
2951 }
2952 fn visit_i16x8_narrow_i32x4_s(&mut self) -> Self::Output {
2953 self.check_v128_binary_op()
2954 }
2955 fn visit_i16x8_narrow_i32x4_u(&mut self) -> Self::Output {
2956 self.check_v128_binary_op()
2957 }
2958 fn visit_i16x8_extmul_low_i8x16_s(&mut self) -> Self::Output {
2959 self.check_v128_binary_op()
2960 }
2961 fn visit_i16x8_extmul_high_i8x16_s(&mut self) -> Self::Output {
2962 self.check_v128_binary_op()
2963 }
2964 fn visit_i16x8_extmul_low_i8x16_u(&mut self) -> Self::Output {
2965 self.check_v128_binary_op()
2966 }
2967 fn visit_i16x8_extmul_high_i8x16_u(&mut self) -> Self::Output {
2968 self.check_v128_binary_op()
2969 }
2970 fn visit_i32x4_extmul_low_i16x8_s(&mut self) -> Self::Output {
2971 self.check_v128_binary_op()
2972 }
2973 fn visit_i32x4_extmul_high_i16x8_s(&mut self) -> Self::Output {
2974 self.check_v128_binary_op()
2975 }
2976 fn visit_i32x4_extmul_low_i16x8_u(&mut self) -> Self::Output {
2977 self.check_v128_binary_op()
2978 }
2979 fn visit_i32x4_extmul_high_i16x8_u(&mut self) -> Self::Output {
2980 self.check_v128_binary_op()
2981 }
2982 fn visit_i64x2_extmul_low_i32x4_s(&mut self) -> Self::Output {
2983 self.check_v128_binary_op()
2984 }
2985 fn visit_i64x2_extmul_high_i32x4_s(&mut self) -> Self::Output {
2986 self.check_v128_binary_op()
2987 }
2988 fn visit_i64x2_extmul_low_i32x4_u(&mut self) -> Self::Output {
2989 self.check_v128_binary_op()
2990 }
2991 fn visit_i64x2_extmul_high_i32x4_u(&mut self) -> Self::Output {
2992 self.check_v128_binary_op()
2993 }
2994 fn visit_i16x8_q15mulr_sat_s(&mut self) -> Self::Output {
2995 self.check_v128_binary_op()
2996 }
2997 fn visit_f32x4_ceil(&mut self) -> Self::Output {
2998 self.check_v128_funary_op()
2999 }
3000 fn visit_f32x4_floor(&mut self) -> Self::Output {
3001 self.check_v128_funary_op()
3002 }
3003 fn visit_f32x4_trunc(&mut self) -> Self::Output {
3004 self.check_v128_funary_op()
3005 }
3006 fn visit_f32x4_nearest(&mut self) -> Self::Output {
3007 self.check_v128_funary_op()
3008 }
3009 fn visit_f64x2_ceil(&mut self) -> Self::Output {
3010 self.check_v128_funary_op()
3011 }
3012 fn visit_f64x2_floor(&mut self) -> Self::Output {
3013 self.check_v128_funary_op()
3014 }
3015 fn visit_f64x2_trunc(&mut self) -> Self::Output {
3016 self.check_v128_funary_op()
3017 }
3018 fn visit_f64x2_nearest(&mut self) -> Self::Output {
3019 self.check_v128_funary_op()
3020 }
3021 fn visit_f32x4_abs(&mut self) -> Self::Output {
3022 self.check_v128_funary_op()
3023 }
3024 fn visit_f32x4_neg(&mut self) -> Self::Output {
3025 self.check_v128_funary_op()
3026 }
3027 fn visit_f32x4_sqrt(&mut self) -> Self::Output {
3028 self.check_v128_funary_op()
3029 }
3030 fn visit_f64x2_abs(&mut self) -> Self::Output {
3031 self.check_v128_funary_op()
3032 }
3033 fn visit_f64x2_neg(&mut self) -> Self::Output {
3034 self.check_v128_funary_op()
3035 }
3036 fn visit_f64x2_sqrt(&mut self) -> Self::Output {
3037 self.check_v128_funary_op()
3038 }
3039 fn visit_f32x4_demote_f64x2_zero(&mut self) -> Self::Output {
3040 self.check_v128_funary_op()
3041 }
3042 fn visit_f64x2_promote_low_f32x4(&mut self) -> Self::Output {
3043 self.check_v128_funary_op()
3044 }
3045 fn visit_f64x2_convert_low_i32x4_s(&mut self) -> Self::Output {
3046 self.check_v128_funary_op()
3047 }
3048 fn visit_f64x2_convert_low_i32x4_u(&mut self) -> Self::Output {
3049 self.check_v128_funary_op()
3050 }
3051 fn visit_i32x4_trunc_sat_f32x4_s(&mut self) -> Self::Output {
3052 self.check_v128_funary_op()
3053 }
3054 fn visit_i32x4_trunc_sat_f32x4_u(&mut self) -> Self::Output {
3055 self.check_v128_funary_op()
3056 }
3057 fn visit_i32x4_trunc_sat_f64x2_s_zero(&mut self) -> Self::Output {
3058 self.check_v128_funary_op()
3059 }
3060 fn visit_i32x4_trunc_sat_f64x2_u_zero(&mut self) -> Self::Output {
3061 self.check_v128_funary_op()
3062 }
3063 fn visit_f32x4_convert_i32x4_s(&mut self) -> Self::Output {
3064 self.check_v128_funary_op()
3065 }
3066 fn visit_f32x4_convert_i32x4_u(&mut self) -> Self::Output {
3067 self.check_v128_funary_op()
3068 }
3069 fn visit_v128_not(&mut self) -> Self::Output {
3070 self.check_v128_unary_op()
3071 }
3072 fn visit_i8x16_abs(&mut self) -> Self::Output {
3073 self.check_v128_unary_op()
3074 }
3075 fn visit_i8x16_neg(&mut self) -> Self::Output {
3076 self.check_v128_unary_op()
3077 }
3078 fn visit_i8x16_popcnt(&mut self) -> Self::Output {
3079 self.check_v128_unary_op()
3080 }
3081 fn visit_i16x8_abs(&mut self) -> Self::Output {
3082 self.check_v128_unary_op()
3083 }
3084 fn visit_i16x8_neg(&mut self) -> Self::Output {
3085 self.check_v128_unary_op()
3086 }
3087 fn visit_i32x4_abs(&mut self) -> Self::Output {
3088 self.check_v128_unary_op()
3089 }
3090 fn visit_i32x4_neg(&mut self) -> Self::Output {
3091 self.check_v128_unary_op()
3092 }
3093 fn visit_i64x2_abs(&mut self) -> Self::Output {
3094 self.check_v128_unary_op()
3095 }
3096 fn visit_i64x2_neg(&mut self) -> Self::Output {
3097 self.check_v128_unary_op()
3098 }
3099 fn visit_i16x8_extend_low_i8x16_s(&mut self) -> Self::Output {
3100 self.check_v128_unary_op()
3101 }
3102 fn visit_i16x8_extend_high_i8x16_s(&mut self) -> Self::Output {
3103 self.check_v128_unary_op()
3104 }
3105 fn visit_i16x8_extend_low_i8x16_u(&mut self) -> Self::Output {
3106 self.check_v128_unary_op()
3107 }
3108 fn visit_i16x8_extend_high_i8x16_u(&mut self) -> Self::Output {
3109 self.check_v128_unary_op()
3110 }
3111 fn visit_i32x4_extend_low_i16x8_s(&mut self) -> Self::Output {
3112 self.check_v128_unary_op()
3113 }
3114 fn visit_i32x4_extend_high_i16x8_s(&mut self) -> Self::Output {
3115 self.check_v128_unary_op()
3116 }
3117 fn visit_i32x4_extend_low_i16x8_u(&mut self) -> Self::Output {
3118 self.check_v128_unary_op()
3119 }
3120 fn visit_i32x4_extend_high_i16x8_u(&mut self) -> Self::Output {
3121 self.check_v128_unary_op()
3122 }
3123 fn visit_i64x2_extend_low_i32x4_s(&mut self) -> Self::Output {
3124 self.check_v128_unary_op()
3125 }
3126 fn visit_i64x2_extend_high_i32x4_s(&mut self) -> Self::Output {
3127 self.check_v128_unary_op()
3128 }
3129 fn visit_i64x2_extend_low_i32x4_u(&mut self) -> Self::Output {
3130 self.check_v128_unary_op()
3131 }
3132 fn visit_i64x2_extend_high_i32x4_u(&mut self) -> Self::Output {
3133 self.check_v128_unary_op()
3134 }
3135 fn visit_i16x8_extadd_pairwise_i8x16_s(&mut self) -> Self::Output {
3136 self.check_v128_unary_op()
3137 }
3138 fn visit_i16x8_extadd_pairwise_i8x16_u(&mut self) -> Self::Output {
3139 self.check_v128_unary_op()
3140 }
3141 fn visit_i32x4_extadd_pairwise_i16x8_s(&mut self) -> Self::Output {
3142 self.check_v128_unary_op()
3143 }
3144 fn visit_i32x4_extadd_pairwise_i16x8_u(&mut self) -> Self::Output {
3145 self.check_v128_unary_op()
3146 }
3147 fn visit_v128_bitselect(&mut self) -> Self::Output {
3148 self.pop_operand(Some(ValType::V128))?;
3149 self.pop_operand(Some(ValType::V128))?;
3150 self.pop_operand(Some(ValType::V128))?;
3151 self.push_operand(ValType::V128)?;
3152 Ok(())
3153 }
3154 fn visit_i8x16_relaxed_swizzle(&mut self) -> Self::Output {
3155 self.pop_operand(Some(ValType::V128))?;
3156 self.pop_operand(Some(ValType::V128))?;
3157 self.push_operand(ValType::V128)?;
3158 Ok(())
3159 }
3160 fn visit_i32x4_relaxed_trunc_f32x4_s(&mut self) -> Self::Output {
3161 self.check_v128_unary_op()
3162 }
3163 fn visit_i32x4_relaxed_trunc_f32x4_u(&mut self) -> Self::Output {
3164 self.check_v128_unary_op()
3165 }
3166 fn visit_i32x4_relaxed_trunc_f64x2_s_zero(&mut self) -> Self::Output {
3167 self.check_v128_unary_op()
3168 }
3169 fn visit_i32x4_relaxed_trunc_f64x2_u_zero(&mut self) -> Self::Output {
3170 self.check_v128_unary_op()
3171 }
3172 fn visit_f32x4_relaxed_madd(&mut self) -> Self::Output {
3173 self.check_v128_ternary_op()
3174 }
3175 fn visit_f32x4_relaxed_nmadd(&mut self) -> Self::Output {
3176 self.check_v128_ternary_op()
3177 }
3178 fn visit_f64x2_relaxed_madd(&mut self) -> Self::Output {
3179 self.check_v128_ternary_op()
3180 }
3181 fn visit_f64x2_relaxed_nmadd(&mut self) -> Self::Output {
3182 self.check_v128_ternary_op()
3183 }
3184 fn visit_i8x16_relaxed_laneselect(&mut self) -> Self::Output {
3185 self.check_v128_ternary_op()
3186 }
3187 fn visit_i16x8_relaxed_laneselect(&mut self) -> Self::Output {
3188 self.check_v128_ternary_op()
3189 }
3190 fn visit_i32x4_relaxed_laneselect(&mut self) -> Self::Output {
3191 self.check_v128_ternary_op()
3192 }
3193 fn visit_i64x2_relaxed_laneselect(&mut self) -> Self::Output {
3194 self.check_v128_ternary_op()
3195 }
3196 fn visit_f32x4_relaxed_min(&mut self) -> Self::Output {
3197 self.check_v128_binary_op()
3198 }
3199 fn visit_f32x4_relaxed_max(&mut self) -> Self::Output {
3200 self.check_v128_binary_op()
3201 }
3202 fn visit_f64x2_relaxed_min(&mut self) -> Self::Output {
3203 self.check_v128_binary_op()
3204 }
3205 fn visit_f64x2_relaxed_max(&mut self) -> Self::Output {
3206 self.check_v128_binary_op()
3207 }
3208 fn visit_i16x8_relaxed_q15mulr_s(&mut self) -> Self::Output {
3209 self.check_v128_binary_op()
3210 }
3211 fn visit_i16x8_relaxed_dot_i8x16_i7x16_s(&mut self) -> Self::Output {
3212 self.check_v128_binary_op()
3213 }
3214 fn visit_i32x4_relaxed_dot_i8x16_i7x16_add_s(&mut self) -> Self::Output {
3215 self.check_v128_ternary_op()
3216 }
3217 fn visit_v128_any_true(&mut self) -> Self::Output {
3218 self.check_v128_bitmask_op()
3219 }
3220 fn visit_i8x16_all_true(&mut self) -> Self::Output {
3221 self.check_v128_bitmask_op()
3222 }
3223 fn visit_i8x16_bitmask(&mut self) -> Self::Output {
3224 self.check_v128_bitmask_op()
3225 }
3226 fn visit_i16x8_all_true(&mut self) -> Self::Output {
3227 self.check_v128_bitmask_op()
3228 }
3229 fn visit_i16x8_bitmask(&mut self) -> Self::Output {
3230 self.check_v128_bitmask_op()
3231 }
3232 fn visit_i32x4_all_true(&mut self) -> Self::Output {
3233 self.check_v128_bitmask_op()
3234 }
3235 fn visit_i32x4_bitmask(&mut self) -> Self::Output {
3236 self.check_v128_bitmask_op()
3237 }
3238 fn visit_i64x2_all_true(&mut self) -> Self::Output {
3239 self.check_v128_bitmask_op()
3240 }
3241 fn visit_i64x2_bitmask(&mut self) -> Self::Output {
3242 self.check_v128_bitmask_op()
3243 }
3244 fn visit_i8x16_shl(&mut self) -> Self::Output {
3245 self.check_v128_shift_op()
3246 }
3247 fn visit_i8x16_shr_s(&mut self) -> Self::Output {
3248 self.check_v128_shift_op()
3249 }
3250 fn visit_i8x16_shr_u(&mut self) -> Self::Output {
3251 self.check_v128_shift_op()
3252 }
3253 fn visit_i16x8_shl(&mut self) -> Self::Output {
3254 self.check_v128_shift_op()
3255 }
3256 fn visit_i16x8_shr_s(&mut self) -> Self::Output {
3257 self.check_v128_shift_op()
3258 }
3259 fn visit_i16x8_shr_u(&mut self) -> Self::Output {
3260 self.check_v128_shift_op()
3261 }
3262 fn visit_i32x4_shl(&mut self) -> Self::Output {
3263 self.check_v128_shift_op()
3264 }
3265 fn visit_i32x4_shr_s(&mut self) -> Self::Output {
3266 self.check_v128_shift_op()
3267 }
3268 fn visit_i32x4_shr_u(&mut self) -> Self::Output {
3269 self.check_v128_shift_op()
3270 }
3271 fn visit_i64x2_shl(&mut self) -> Self::Output {
3272 self.check_v128_shift_op()
3273 }
3274 fn visit_i64x2_shr_s(&mut self) -> Self::Output {
3275 self.check_v128_shift_op()
3276 }
3277 fn visit_i64x2_shr_u(&mut self) -> Self::Output {
3278 self.check_v128_shift_op()
3279 }
3280 fn visit_i8x16_swizzle(&mut self) -> Self::Output {
3281 self.pop_operand(Some(ValType::V128))?;
3282 self.pop_operand(Some(ValType::V128))?;
3283 self.push_operand(ValType::V128)?;
3284 Ok(())
3285 }
3286 fn visit_i8x16_shuffle(&mut self, lanes: [u8; 16]) -> Self::Output {
3287 self.pop_operand(Some(ValType::V128))?;
3288 self.pop_operand(Some(ValType::V128))?;
3289 for i in lanes {
3290 self.check_simd_lane_index(i, 32)?;
3291 }
3292 self.push_operand(ValType::V128)?;
3293 Ok(())
3294 }
3295 fn visit_v128_load8_splat(&mut self, memarg: MemArg) -> Self::Output {
3296 let ty = self.check_memarg(memarg)?;
3297 self.pop_operand(Some(ty))?;
3298 self.push_operand(ValType::V128)?;
3299 Ok(())
3300 }
3301 fn visit_v128_load16_splat(&mut self, memarg: MemArg) -> Self::Output {
3302 let ty = self.check_memarg(memarg)?;
3303 self.pop_operand(Some(ty))?;
3304 self.push_operand(ValType::V128)?;
3305 Ok(())
3306 }
3307 fn visit_v128_load32_splat(&mut self, memarg: MemArg) -> Self::Output {
3308 let ty = self.check_memarg(memarg)?;
3309 self.pop_operand(Some(ty))?;
3310 self.push_operand(ValType::V128)?;
3311 Ok(())
3312 }
3313 fn visit_v128_load32_zero(&mut self, memarg: MemArg) -> Self::Output {
3314 self.visit_v128_load32_splat(memarg)
3315 }
3316 fn visit_v128_load64_splat(&mut self, memarg: MemArg) -> Self::Output {
3317 self.check_v128_load_op(memarg)
3318 }
3319 fn visit_v128_load64_zero(&mut self, memarg: MemArg) -> Self::Output {
3320 self.check_v128_load_op(memarg)
3321 }
3322 fn visit_v128_load8x8_s(&mut self, memarg: MemArg) -> Self::Output {
3323 self.check_v128_load_op(memarg)
3324 }
3325 fn visit_v128_load8x8_u(&mut self, memarg: MemArg) -> Self::Output {
3326 self.check_v128_load_op(memarg)
3327 }
3328 fn visit_v128_load16x4_s(&mut self, memarg: MemArg) -> Self::Output {
3329 self.check_v128_load_op(memarg)
3330 }
3331 fn visit_v128_load16x4_u(&mut self, memarg: MemArg) -> Self::Output {
3332 self.check_v128_load_op(memarg)
3333 }
3334 fn visit_v128_load32x2_s(&mut self, memarg: MemArg) -> Self::Output {
3335 self.check_v128_load_op(memarg)
3336 }
3337 fn visit_v128_load32x2_u(&mut self, memarg: MemArg) -> Self::Output {
3338 self.check_v128_load_op(memarg)
3339 }
3340 fn visit_v128_load8_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output {
3341 let idx = self.check_memarg(memarg)?;
3342 self.check_simd_lane_index(lane, 16)?;
3343 self.pop_operand(Some(ValType::V128))?;
3344 self.pop_operand(Some(idx))?;
3345 self.push_operand(ValType::V128)?;
3346 Ok(())
3347 }
3348 fn visit_v128_load16_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output {
3349 let idx = self.check_memarg(memarg)?;
3350 self.check_simd_lane_index(lane, 8)?;
3351 self.pop_operand(Some(ValType::V128))?;
3352 self.pop_operand(Some(idx))?;
3353 self.push_operand(ValType::V128)?;
3354 Ok(())
3355 }
3356 fn visit_v128_load32_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output {
3357 let idx = self.check_memarg(memarg)?;
3358 self.check_simd_lane_index(lane, 4)?;
3359 self.pop_operand(Some(ValType::V128))?;
3360 self.pop_operand(Some(idx))?;
3361 self.push_operand(ValType::V128)?;
3362 Ok(())
3363 }
3364 fn visit_v128_load64_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output {
3365 let idx = self.check_memarg(memarg)?;
3366 self.check_simd_lane_index(lane, 2)?;
3367 self.pop_operand(Some(ValType::V128))?;
3368 self.pop_operand(Some(idx))?;
3369 self.push_operand(ValType::V128)?;
3370 Ok(())
3371 }
3372 fn visit_v128_store8_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output {
3373 let idx = self.check_memarg(memarg)?;
3374 self.check_simd_lane_index(lane, 16)?;
3375 self.pop_operand(Some(ValType::V128))?;
3376 self.pop_operand(Some(idx))?;
3377 Ok(())
3378 }
3379 fn visit_v128_store16_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output {
3380 let idx = self.check_memarg(memarg)?;
3381 self.check_simd_lane_index(lane, 8)?;
3382 self.pop_operand(Some(ValType::V128))?;
3383 self.pop_operand(Some(idx))?;
3384 Ok(())
3385 }
3386 fn visit_v128_store32_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output {
3387 let idx = self.check_memarg(memarg)?;
3388 self.check_simd_lane_index(lane, 4)?;
3389 self.pop_operand(Some(ValType::V128))?;
3390 self.pop_operand(Some(idx))?;
3391 Ok(())
3392 }
3393 fn visit_v128_store64_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output {
3394 let idx = self.check_memarg(memarg)?;
3395 self.check_simd_lane_index(lane, 2)?;
3396 self.pop_operand(Some(ValType::V128))?;
3397 self.pop_operand(Some(idx))?;
3398 Ok(())
3399 }
3400 fn visit_memory_init(&mut self, segment: u32, mem: u32) -> Self::Output {
3401 let ty = self.check_memory_index(mem)?;
3402 match self.resources.data_count() {
3403 None => bail!(self.offset, "data count section required"),
3404 Some(count) if segment < count => {}
3405 Some(_) => bail!(self.offset, "unknown data segment {}", segment),
3406 }
3407 self.pop_operand(Some(ValType::I32))?;
3408 self.pop_operand(Some(ValType::I32))?;
3409 self.pop_operand(Some(ty))?;
3410 Ok(())
3411 }
3412 fn visit_data_drop(&mut self, segment: u32) -> Self::Output {
3413 match self.resources.data_count() {
3414 None => bail!(self.offset, "data count section required"),
3415 Some(count) if segment < count => {}
3416 Some(_) => bail!(self.offset, "unknown data segment {}", segment),
3417 }
3418 Ok(())
3419 }
3420 fn visit_memory_copy(&mut self, dst: u32, src: u32) -> Self::Output {
3421 let dst_ty = self.check_memory_index(dst)?;
3422 let src_ty = self.check_memory_index(src)?;
3423
3424 self.pop_operand(Some(match src_ty {
3427 ValType::I32 => ValType::I32,
3428 _ => dst_ty,
3429 }))?;
3430
3431 self.pop_operand(Some(src_ty))?;
3434 self.pop_operand(Some(dst_ty))?;
3435 Ok(())
3436 }
3437 fn visit_memory_fill(&mut self, mem: u32) -> Self::Output {
3438 let ty = self.check_memory_index(mem)?;
3439 self.pop_operand(Some(ty))?;
3440 self.pop_operand(Some(ValType::I32))?;
3441 self.pop_operand(Some(ty))?;
3442 Ok(())
3443 }
3444 fn visit_memory_discard(&mut self, mem: u32) -> Self::Output {
3445 let ty = self.check_memory_index(mem)?;
3446 self.pop_operand(Some(ty))?;
3447 self.pop_operand(Some(ty))?;
3448 Ok(())
3449 }
3450 fn visit_table_init(&mut self, segment: u32, table: u32) -> Self::Output {
3451 if table > 0 {}
3452 let table = match self.resources.table_at(table) {
3453 Some(table) => table,
3454 None => bail!(
3455 self.offset,
3456 "unknown table {}: table index out of bounds",
3457 table
3458 ),
3459 };
3460 let segment_ty = self.element_type_at(segment)?;
3461 if !self
3462 .resources
3463 .is_subtype(ValType::Ref(segment_ty), ValType::Ref(table.element_type))
3464 {
3465 bail!(self.offset, "type mismatch");
3466 }
3467 self.pop_operand(Some(ValType::I32))?;
3468 self.pop_operand(Some(ValType::I32))?;
3469 self.pop_operand(Some(ValType::I32))?;
3470 Ok(())
3471 }
3472 fn visit_elem_drop(&mut self, segment: u32) -> Self::Output {
3473 if segment >= self.resources.element_count() {
3474 bail!(
3475 self.offset,
3476 "unknown elem segment {}: segment index out of bounds",
3477 segment
3478 );
3479 }
3480 Ok(())
3481 }
3482 fn visit_table_copy(&mut self, dst_table: u32, src_table: u32) -> Self::Output {
3483 if src_table > 0 || dst_table > 0 {}
3484 let (src, dst) = match (
3485 self.resources.table_at(src_table),
3486 self.resources.table_at(dst_table),
3487 ) {
3488 (Some(a), Some(b)) => (a, b),
3489 _ => bail!(self.offset, "table index out of bounds"),
3490 };
3491 if !self.resources.is_subtype(
3492 ValType::Ref(src.element_type),
3493 ValType::Ref(dst.element_type),
3494 ) {
3495 bail!(self.offset, "type mismatch");
3496 }
3497 self.pop_operand(Some(ValType::I32))?;
3498 self.pop_operand(Some(ValType::I32))?;
3499 self.pop_operand(Some(ValType::I32))?;
3500 Ok(())
3501 }
3502 fn visit_table_get(&mut self, table: u32) -> Self::Output {
3503 let ty = match self.resources.table_at(table) {
3504 Some(ty) => ty.element_type,
3505 None => bail!(self.offset, "table index out of bounds"),
3506 };
3507 let ty = ValType::Ref(ty);
3508 debug_assert_type_indices_are_ids(ty);
3509 self.pop_operand(Some(ValType::I32))?;
3510 self.push_operand(ty)?;
3511 Ok(())
3512 }
3513 fn visit_table_set(&mut self, table: u32) -> Self::Output {
3514 let ty = match self.resources.table_at(table) {
3515 Some(ty) => ValType::Ref(ty.element_type),
3516 None => bail!(self.offset, "table index out of bounds"),
3517 };
3518 debug_assert_type_indices_are_ids(ty);
3519 self.pop_operand(Some(ty))?;
3520 self.pop_operand(Some(ValType::I32))?;
3521 Ok(())
3522 }
3523 fn visit_table_grow(&mut self, table: u32) -> Self::Output {
3524 let ty = match self.resources.table_at(table) {
3525 Some(ty) => ValType::Ref(ty.element_type),
3526 None => bail!(self.offset, "table index out of bounds"),
3527 };
3528 debug_assert_type_indices_are_ids(ty);
3529 self.pop_operand(Some(ValType::I32))?;
3530 self.pop_operand(Some(ty))?;
3531 self.push_operand(ValType::I32)?;
3532 Ok(())
3533 }
3534 fn visit_table_size(&mut self, table: u32) -> Self::Output {
3535 if self.resources.table_at(table).is_none() {
3536 bail!(self.offset, "table index out of bounds");
3537 }
3538 self.push_operand(ValType::I32)?;
3539 Ok(())
3540 }
3541 fn visit_table_fill(&mut self, table: u32) -> Self::Output {
3542 let ty = match self.resources.table_at(table) {
3543 Some(ty) => ValType::Ref(ty.element_type),
3544 None => bail!(self.offset, "table index out of bounds"),
3545 };
3546 debug_assert_type_indices_are_ids(ty);
3547 self.pop_operand(Some(ValType::I32))?;
3548 self.pop_operand(Some(ty))?;
3549 self.pop_operand(Some(ValType::I32))?;
3550 Ok(())
3551 }
3552 fn visit_struct_new(&mut self, struct_type_index: u32) -> Self::Output {
3553 let struct_ty = self.struct_type_at(struct_type_index)?;
3554 for ty in struct_ty.fields.iter().rev() {
3555 self.pop_operand(Some(ty.element_type.unpack()))?;
3556 }
3557 self.push_concrete_ref(false, struct_type_index)?;
3558 Ok(())
3559 }
3560 fn visit_struct_new_default(&mut self, type_index: u32) -> Self::Output {
3561 let ty = self.struct_type_at(type_index)?;
3562 for field in ty.fields.iter() {
3563 let val_ty = field.element_type.unpack();
3564 if !val_ty.is_defaultable() {
3565 bail!(
3566 self.offset,
3567 "invalid `struct.new_default`: {val_ty} field is not defaultable"
3568 );
3569 }
3570 }
3571 self.push_concrete_ref(false, type_index)?;
3572 Ok(())
3573 }
3574 fn visit_struct_get(&mut self, struct_type_index: u32, field_index: u32) -> Self::Output {
3575 let field_ty = self.struct_field_at(struct_type_index, field_index)?;
3576 if field_ty.element_type.is_packed() {
3577 bail!(
3578 self.offset,
3579 "can only use struct.get with non-packed storage types"
3580 )
3581 }
3582 self.pop_concrete_ref(true, struct_type_index)?;
3583 self.push_operand(field_ty.element_type.unpack())
3584 }
3585 fn visit_struct_get_s(&mut self, struct_type_index: u32, field_index: u32) -> Self::Output {
3586 let field_ty = self.struct_field_at(struct_type_index, field_index)?;
3587 if !field_ty.element_type.is_packed() {
3588 bail!(
3589 self.offset,
3590 "cannot use struct.get_s with non-packed storage types"
3591 )
3592 }
3593 self.pop_concrete_ref(true, struct_type_index)?;
3594 self.push_operand(field_ty.element_type.unpack())
3595 }
3596 fn visit_struct_get_u(&mut self, struct_type_index: u32, field_index: u32) -> Self::Output {
3597 let field_ty = self.struct_field_at(struct_type_index, field_index)?;
3598 if !field_ty.element_type.is_packed() {
3599 bail!(
3600 self.offset,
3601 "cannot use struct.get_u with non-packed storage types"
3602 )
3603 }
3604 self.pop_concrete_ref(true, struct_type_index)?;
3605 self.push_operand(field_ty.element_type.unpack())
3606 }
3607 fn visit_struct_set(&mut self, struct_type_index: u32, field_index: u32) -> Self::Output {
3608 let field_ty = self.struct_field_at(struct_type_index, field_index)?;
3609 if !field_ty.mutable {
3610 bail!(self.offset, "invalid struct.set: struct field is immutable")
3611 }
3612 self.pop_operand(Some(field_ty.element_type.unpack()))?;
3613 self.pop_concrete_ref(true, struct_type_index)?;
3614 Ok(())
3615 }
3616 fn visit_array_new(&mut self, type_index: u32) -> Self::Output {
3617 let array_ty = self.array_type_at(type_index)?;
3618 self.pop_operand(Some(ValType::I32))?;
3619 self.pop_operand(Some(array_ty.0.element_type.unpack()))?;
3620 self.push_concrete_ref(false, type_index)
3621 }
3622 fn visit_array_new_default(&mut self, type_index: u32) -> Self::Output {
3623 let ty = self.array_type_at(type_index)?;
3624 let val_ty = ty.0.element_type.unpack();
3625 if !val_ty.is_defaultable() {
3626 bail!(
3627 self.offset,
3628 "invalid `array.new_default`: {val_ty} field is not defaultable"
3629 );
3630 }
3631 self.pop_operand(Some(ValType::I32))?;
3632 self.push_concrete_ref(false, type_index)
3633 }
3634 fn visit_array_new_fixed(&mut self, type_index: u32, n: u32) -> Self::Output {
3635 let array_ty = self.array_type_at(type_index)?;
3636 let elem_ty = array_ty.0.element_type.unpack();
3637 for _ in 0..n {
3638 self.pop_operand(Some(elem_ty))?;
3639 }
3640 self.push_concrete_ref(false, type_index)
3641 }
3642 fn visit_array_new_data(&mut self, type_index: u32, data_index: u32) -> Self::Output {
3643 let array_ty = self.array_type_at(type_index)?;
3644 let elem_ty = array_ty.0.element_type.unpack();
3645 match elem_ty {
3646 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => {}
3647 ValType::Ref(_) => bail!(
3648 self.offset,
3649 "type mismatch: array.new_data can only create arrays with numeric and vector elements"
3650 ),
3651 }
3652 match self.resources.data_count() {
3653 None => bail!(self.offset, "data count section required"),
3654 Some(count) if data_index < count => {}
3655 Some(_) => bail!(self.offset, "unknown data segment {}", data_index),
3656 }
3657 self.pop_operand(Some(ValType::I32))?;
3658 self.pop_operand(Some(ValType::I32))?;
3659 self.push_concrete_ref(false, type_index)
3660 }
3661 fn visit_array_new_elem(&mut self, type_index: u32, elem_index: u32) -> Self::Output {
3662 let array_ty = self.array_type_at(type_index)?;
3663 let array_ref_ty = match array_ty.0.element_type.unpack() {
3664 ValType::Ref(rt) => rt,
3665 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => bail!(
3666 self.offset,
3667 "type mismatch: array.new_elem can only create arrays with reference elements"
3668 ),
3669 };
3670 let elem_ref_ty = self.element_type_at(elem_index)?;
3671 if !self
3672 .resources
3673 .is_subtype(elem_ref_ty.into(), array_ref_ty.into())
3674 {
3675 bail!(
3676 self.offset,
3677 "invalid array.new_elem instruction: element segment {elem_index} type mismatch: \
3678 expected {array_ref_ty}, found {elem_ref_ty}"
3679 )
3680 }
3681 self.pop_operand(Some(ValType::I32))?;
3682 self.pop_operand(Some(ValType::I32))?;
3683 self.push_concrete_ref(false, type_index)
3684 }
3685 fn visit_array_get(&mut self, type_index: u32) -> Self::Output {
3686 let array_ty = self.array_type_at(type_index)?;
3687 let elem_ty = array_ty.0.element_type;
3688 if elem_ty.is_packed() {
3689 bail!(
3690 self.offset,
3691 "cannot use array.get with packed storage types"
3692 )
3693 }
3694 self.pop_operand(Some(ValType::I32))?;
3695 self.pop_concrete_ref(true, type_index)?;
3696 self.push_operand(elem_ty.unpack())
3697 }
3698 fn visit_array_get_s(&mut self, type_index: u32) -> Self::Output {
3699 let array_ty = self.array_type_at(type_index)?;
3700 let elem_ty = array_ty.0.element_type;
3701 if !elem_ty.is_packed() {
3702 bail!(
3703 self.offset,
3704 "cannot use array.get_s with non-packed storage types"
3705 )
3706 }
3707 self.pop_operand(Some(ValType::I32))?;
3708 self.pop_concrete_ref(true, type_index)?;
3709 self.push_operand(elem_ty.unpack())
3710 }
3711 fn visit_array_get_u(&mut self, type_index: u32) -> Self::Output {
3712 let array_ty = self.array_type_at(type_index)?;
3713 let elem_ty = array_ty.0.element_type;
3714 if !elem_ty.is_packed() {
3715 bail!(
3716 self.offset,
3717 "cannot use array.get_u with non-packed storage types"
3718 )
3719 }
3720 self.pop_operand(Some(ValType::I32))?;
3721 self.pop_concrete_ref(true, type_index)?;
3722 self.push_operand(elem_ty.unpack())
3723 }
3724 fn visit_array_set(&mut self, type_index: u32) -> Self::Output {
3725 let array_ty = self.array_type_at(type_index)?;
3726 if !array_ty.0.mutable {
3727 bail!(self.offset, "invalid array.set: array is immutable")
3728 }
3729 self.pop_operand(Some(array_ty.0.element_type.unpack()))?;
3730 self.pop_operand(Some(ValType::I32))?;
3731 self.pop_concrete_ref(true, type_index)?;
3732 Ok(())
3733 }
3734 fn visit_array_len(&mut self) -> Self::Output {
3735 self.pop_operand(Some(RefType::ARRAY.nullable().into()))?;
3736 self.push_operand(ValType::I32)
3737 }
3738 fn visit_array_fill(&mut self, array_type_index: u32) -> Self::Output {
3739 let array_ty = self.array_type_at(array_type_index)?;
3740 if !array_ty.0.mutable {
3741 bail!(self.offset, "invalid array.fill: array is immutable");
3742 }
3743 self.pop_operand(Some(ValType::I32))?;
3744 self.pop_operand(Some(array_ty.0.element_type.unpack()))?;
3745 self.pop_operand(Some(ValType::I32))?;
3746 self.pop_concrete_ref(true, array_type_index)?;
3747 Ok(())
3748 }
3749 fn visit_array_copy(&mut self, type_index_dst: u32, type_index_src: u32) -> Self::Output {
3750 let array_ty_dst = self.array_type_at(type_index_dst)?;
3751 if !array_ty_dst.0.mutable {
3752 bail!(
3753 self.offset,
3754 "invalid array.copy: destination array is immutable"
3755 );
3756 }
3757 let array_ty_src = self.array_type_at(type_index_src)?;
3758 match (array_ty_dst.0.element_type, array_ty_src.0.element_type) {
3759 (StorageType::I8, StorageType::I8) => {}
3760 (StorageType::I8, ty) => bail!(
3761 self.offset,
3762 "array types do not match: expected i8, found {ty}"
3763 ),
3764 (StorageType::I16, StorageType::I16) => {}
3765 (StorageType::I16, ty) => bail!(
3766 self.offset,
3767 "array types do not match: expected i16, found {ty}"
3768 ),
3769 (StorageType::Val(dst), StorageType::Val(src)) => {
3770 if !self.resources.is_subtype(src, dst) {
3771 bail!(
3772 self.offset,
3773 "array types do not match: expected {dst}, found {src}"
3774 )
3775 }
3776 }
3777 (StorageType::Val(dst), src) => {
3778 bail!(
3779 self.offset,
3780 "array types do not match: expected {dst}, found {src}"
3781 )
3782 }
3783 }
3784 self.pop_operand(Some(ValType::I32))?;
3785 self.pop_operand(Some(ValType::I32))?;
3786 self.pop_concrete_ref(true, type_index_src)?;
3787 self.pop_operand(Some(ValType::I32))?;
3788 self.pop_concrete_ref(true, type_index_dst)?;
3789 Ok(())
3790 }
3791 fn visit_array_init_data(
3792 &mut self,
3793 array_type_index: u32,
3794 array_data_index: u32,
3795 ) -> Self::Output {
3796 let array_ty = self.array_type_at(array_type_index)?;
3797 if !array_ty.0.mutable {
3798 bail!(self.offset, "invalid array.init_data: array is immutable");
3799 }
3800 let val_ty = array_ty.0.element_type.unpack();
3801 match val_ty {
3802 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => {}
3803 ValType::Ref(_) => bail!(
3804 self.offset,
3805 "invalid array.init_data: array type is not numeric or vector"
3806 ),
3807 }
3808 match self.resources.data_count() {
3809 None => bail!(self.offset, "data count section required"),
3810 Some(count) if array_data_index < count => {}
3811 Some(_) => bail!(self.offset, "unknown data segment {}", array_data_index),
3812 }
3813 self.pop_operand(Some(ValType::I32))?;
3814 self.pop_operand(Some(ValType::I32))?;
3815 self.pop_operand(Some(ValType::I32))?;
3816 self.pop_concrete_ref(true, array_type_index)?;
3817 Ok(())
3818 }
3819 fn visit_array_init_elem(&mut self, type_index: u32, elem_index: u32) -> Self::Output {
3820 let array_ty = self.array_type_at(type_index)?;
3821 if !array_ty.0.mutable {
3822 bail!(self.offset, "invalid array.init_data: array is immutable");
3823 }
3824 let array_ref_ty = match array_ty.0.element_type.unpack() {
3825 ValType::Ref(rt) => rt,
3826 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => bail!(
3827 self.offset,
3828 "type mismatch: array.init_elem can only create arrays with reference elements"
3829 ),
3830 };
3831 let elem_ref_ty = self.element_type_at(elem_index)?;
3832 if !self
3833 .resources
3834 .is_subtype(elem_ref_ty.into(), array_ref_ty.into())
3835 {
3836 bail!(
3837 self.offset,
3838 "invalid array.init_elem instruction: element segment {elem_index} type mismatch: \
3839 expected {array_ref_ty}, found {elem_ref_ty}"
3840 )
3841 }
3842 self.pop_operand(Some(ValType::I32))?;
3843 self.pop_operand(Some(ValType::I32))?;
3844 self.pop_operand(Some(ValType::I32))?;
3845 self.pop_concrete_ref(true, type_index)?;
3846 Ok(())
3847 }
3848 fn visit_any_convert_extern(&mut self) -> Self::Output {
3849 let extern_ref = self.pop_operand(Some(RefType::EXTERNREF.into()))?;
3850 let is_nullable = extern_ref
3851 .as_type()
3852 .map_or(false, |ty| ty.as_reference_type().unwrap().is_nullable());
3853 let any_ref = RefType::new(is_nullable, HeapType::Any).unwrap();
3854 self.push_operand(any_ref)
3855 }
3856 fn visit_extern_convert_any(&mut self) -> Self::Output {
3857 let any_ref = self.pop_operand(Some(RefType::ANY.nullable().into()))?;
3858 let is_nullable = any_ref
3859 .as_type()
3860 .map_or(false, |ty| ty.as_reference_type().unwrap().is_nullable());
3861 let extern_ref = RefType::new(is_nullable, HeapType::Extern).unwrap();
3862 self.push_operand(extern_ref)
3863 }
3864 fn visit_ref_test_non_null(&mut self, heap_type: HeapType) -> Self::Output {
3865 self.check_ref_test(false, heap_type)
3866 }
3867 fn visit_ref_test_nullable(&mut self, heap_type: HeapType) -> Self::Output {
3868 self.check_ref_test(true, heap_type)
3869 }
3870 fn visit_ref_cast_non_null(&mut self, heap_type: HeapType) -> Self::Output {
3871 self.check_ref_cast(false, heap_type)
3872 }
3873 fn visit_ref_cast_nullable(&mut self, heap_type: HeapType) -> Self::Output {
3874 self.check_ref_cast(true, heap_type)
3875 }
3876 fn visit_br_on_cast(
3877 &mut self,
3878 relative_depth: u32,
3879 mut from_ref_type: RefType,
3880 mut to_ref_type: RefType,
3881 ) -> Self::Output {
3882 self.resources
3883 .check_ref_type(&mut from_ref_type, self.offset)?;
3884 self.resources
3885 .check_ref_type(&mut to_ref_type, self.offset)?;
3886
3887 if !self
3888 .resources
3889 .is_subtype(to_ref_type.into(), from_ref_type.into())
3890 {
3891 bail!(
3892 self.offset,
3893 "type mismatch: expected {from_ref_type}, found {to_ref_type}"
3894 );
3895 }
3896
3897 let (block_ty, frame_kind) = self.jump(relative_depth)?;
3898 let mut label_types = self.label_types(block_ty, frame_kind)?;
3899
3900 match label_types.next_back() {
3901 Some(label_ty) if self.resources.is_subtype(to_ref_type.into(), label_ty) => {
3902 self.pop_operand(Some(from_ref_type.into()))?;
3903 }
3904 Some(label_ty) => bail!(
3905 self.offset,
3906 "type mismatch: casting to type {to_ref_type}, but it does not match \
3907 label result type {label_ty}"
3908 ),
3909 None => bail!(
3910 self.offset,
3911 "type mismtach: br_on_cast to label with empty types, must have a reference type"
3912 ),
3913 };
3914
3915 self.pop_push_label_types(label_types)?;
3916 let diff_ty = RefType::difference(from_ref_type, to_ref_type);
3917 self.push_operand(diff_ty)?;
3918 Ok(())
3919 }
3920 fn visit_br_on_cast_fail(
3921 &mut self,
3922 relative_depth: u32,
3923 mut from_ref_type: RefType,
3924 mut to_ref_type: RefType,
3925 ) -> Self::Output {
3926 self.resources
3927 .check_ref_type(&mut from_ref_type, self.offset)?;
3928 self.resources
3929 .check_ref_type(&mut to_ref_type, self.offset)?;
3930
3931 if !self
3932 .resources
3933 .is_subtype(to_ref_type.into(), from_ref_type.into())
3934 {
3935 bail!(
3936 self.offset,
3937 "type mismatch: expected {from_ref_type}, found {to_ref_type}"
3938 );
3939 }
3940
3941 let (block_ty, frame_kind) = self.jump(relative_depth)?;
3942 let mut label_tys = self.label_types(block_ty, frame_kind)?;
3943
3944 let diff_ty = RefType::difference(from_ref_type, to_ref_type);
3945 match label_tys.next_back() {
3946 Some(label_ty) if self.resources.is_subtype(diff_ty.into(), label_ty) => {
3947 self.pop_operand(Some(from_ref_type.into()))?;
3948 }
3949 Some(label_ty) => bail!(
3950 self.offset,
3951 "type mismatch: expected label result type {label_ty}, found {diff_ty}"
3952 ),
3953 None => bail!(
3954 self.offset,
3955 "type mismatch: expected a reference type, found nothing"
3956 ),
3957 }
3958
3959 self.pop_push_label_types(label_tys)?;
3960 self.push_operand(to_ref_type)?;
3961 Ok(())
3962 }
3963 fn visit_ref_i31(&mut self) -> Self::Output {
3964 self.pop_operand(Some(ValType::I32))?;
3965 self.push_operand(ValType::Ref(RefType::I31))
3966 }
3967 fn visit_i31_get_s(&mut self) -> Self::Output {
3968 self.pop_operand(Some(ValType::Ref(RefType::I31REF)))?;
3969 self.push_operand(ValType::I32)
3970 }
3971 fn visit_i31_get_u(&mut self) -> Self::Output {
3972 self.pop_operand(Some(ValType::Ref(RefType::I31REF)))?;
3973 self.push_operand(ValType::I32)
3974 }
3975}
3976
3977#[derive(Clone, Debug)]
3978enum Either<A, B> {
3979 A(A),
3980 B(B),
3981}
3982
3983impl<A, B> Iterator for Either<A, B>
3984where
3985 A: Iterator,
3986 B: Iterator<Item = A::Item>,
3987{
3988 type Item = A::Item;
3989 fn next(&mut self) -> Option<A::Item> {
3990 match self {
3991 Either::A(a) => a.next(),
3992 Either::B(b) => b.next(),
3993 }
3994 }
3995}
3996
3997impl<A, B> DoubleEndedIterator for Either<A, B>
3998where
3999 A: DoubleEndedIterator,
4000 B: DoubleEndedIterator<Item = A::Item>,
4001{
4002 fn next_back(&mut self) -> Option<A::Item> {
4003 match self {
4004 Either::A(a) => a.next_back(),
4005 Either::B(b) => b.next_back(),
4006 }
4007 }
4008}
4009
4010impl<A, B> ExactSizeIterator for Either<A, B>
4011where
4012 A: ExactSizeIterator,
4013 B: ExactSizeIterator<Item = A::Item>,
4014{
4015 fn len(&self) -> usize {
4016 match self {
4017 Either::A(a) => a.len(),
4018 Either::B(b) => b.len(),
4019 }
4020 }
4021}
4022
4023trait PreciseIterator:
4024 ExactSizeIterator + DoubleEndedIterator + Clone + crate::std::fmt::Debug
4025{
4026}
4027impl<T: ExactSizeIterator + DoubleEndedIterator + Clone + crate::std::fmt::Debug> PreciseIterator
4028 for T
4029{
4030}
4031
4032impl Locals {
4033 fn define(&mut self, count: u32, ty: ValType) -> bool {
4039 match self.num_locals.checked_add(count) {
4040 Some(n) => self.num_locals = n,
4041 None => return false,
4042 }
4043 if self.num_locals > (MAX_WASM_FUNCTION_LOCALS as u32) {
4044 return false;
4045 }
4046 for _ in 0..count {
4047 if self.first.len() >= MAX_LOCALS_TO_TRACK {
4048 break;
4049 }
4050 self.first.push(ty);
4051 }
4052 self.all.push((self.num_locals - 1, ty));
4053 true
4054 }
4055
4056 pub(super) fn len_locals(&self) -> u32 {
4058 self.num_locals
4059 }
4060
4061 #[inline]
4063 pub(super) fn get(&self, idx: u32) -> Option<ValType> {
4064 match self.first.get(idx as usize) {
4065 Some(ty) => Some(*ty),
4066 None => self.get_bsearch(idx),
4067 }
4068 }
4069
4070 fn get_bsearch(&self, idx: u32) -> Option<ValType> {
4071 match self.all.binary_search_by_key(&idx, |(idx, _)| *idx) {
4072 Err(i) if i == self.all.len() => None,
4075
4076 Ok(i) | Err(i) => Some(self.all[i].1),
4082 }
4083 }
4084}