1#[cfg(feature = "simd")]
26use crate::VisitSimdOperator;
27use crate::{
28 AbstractHeapType, BinaryReaderError, BlockType, BrTable, Catch, ContType, FieldType, FrameKind,
29 FrameStack, FuncType, GlobalType, Handle, HeapType, Ieee32, Ieee64, MemArg, ModuleArity,
30 RefType, Result, ResumeTable, StorageType, StructType, SubType, TableType, TryTable,
31 UnpackedIndex, ValType, VisitOperator, WasmFeatures, WasmModuleResources,
32 limits::MAX_WASM_FUNCTION_LOCALS,
33};
34use crate::{CompositeInnerType, Ordering, prelude::*};
35use core::ops::{Deref, DerefMut};
36use core::{cmp, iter, mem};
37
38#[cfg(feature = "simd")]
39mod simd;
40
41#[cfg(feature = "try-op")]
42mod transaction;
43#[cfg(not(feature = "try-op"))]
44mod transaction_disabled;
45#[cfg(not(feature = "try-op"))]
46use transaction_disabled as transaction;
47
48use transaction::{RollbackLogAllocations, Transaction};
49
50#[derive(Clone, PartialEq)]
51pub(crate) struct OperatorValidator {
52 pub(super) locals: Locals,
53 local_inits: LocalInits,
54
55 pub(crate) features: WasmFeatures,
58
59 popped_types_tmp: Vec<MaybeType>,
61
62 control: Vec<Frame>,
64 operands: Vec<MaybeType>,
66
67 shared: bool,
69
70 #[cfg(debug_assertions)]
75 pub(crate) pop_push_log: Vec<bool>,
76
77 transaction: Transaction,
81}
82
83#[derive(Clone, PartialEq)]
85struct LocalInits {
86 local_inits: Vec<bool>,
88 inits: Vec<u32>,
91 first_non_default_local: u32,
98}
99
100impl Default for LocalInits {
101 fn default() -> Self {
102 Self {
103 local_inits: Vec::default(),
104 inits: Vec::default(),
105 first_non_default_local: u32::MAX,
106 }
107 }
108}
109
110impl LocalInits {
111 pub fn define_params(&mut self, count: usize) {
113 let Some(new_len) = self.local_inits.len().checked_add(count) else {
114 panic!("tried to define too many function locals as parameters: {count}");
115 };
116 self.local_inits.resize(new_len, true);
117 }
118
119 pub fn define_locals(&mut self, count: u32, ty: ValType) {
121 let Ok(count) = usize::try_from(count) else {
122 panic!("tried to define too many function locals: {count}");
123 };
124 let len = self.local_inits.len();
125 let Some(new_len) = len.checked_add(count) else {
126 panic!("tried to define too many function locals: {count}");
127 };
128 let is_defaultable = ty.is_defaultable();
129 if !is_defaultable && self.first_non_default_local == u32::MAX {
130 self.first_non_default_local = len as u32;
131 }
132 self.local_inits.resize(new_len, is_defaultable);
133 }
134
135 #[inline]
137 pub fn is_uninit(&self, local_index: u32) -> bool {
138 if local_index < self.first_non_default_local {
139 return false;
140 }
141 !self.local_inits[local_index as usize]
142 }
143
144 #[inline]
146 pub fn set_init(&mut self, local_index: u32) {
147 if self.is_uninit(local_index) {
148 self.local_inits[local_index as usize] = true;
149 self.inits.push(local_index);
150 }
151 }
152
153 pub fn height(&self) -> usize {
155 self.inits.len()
156 }
157
158 #[inline]
163 pub fn pop_ctrl(&mut self, height: usize) -> Vec<u32> {
164 let inits = self.inits.split_off(height);
165 for local_index in &inits {
166 self.local_inits[*local_index as usize] = false;
167 }
168 inits
169 }
170
171 pub fn clear(&mut self) {
175 self.local_inits.clear();
176 self.inits.clear();
177 self.first_non_default_local = u32::MAX;
178 }
179
180 pub fn is_empty(&self) -> bool {
182 self.local_inits.is_empty()
183 }
184}
185
186const MAX_LOCALS_TO_TRACK: u32 = 50;
189
190#[derive(Clone, PartialEq)]
191pub(super) struct Locals {
192 num_locals: u32,
194
195 first: Vec<ValType>,
200
201 uncached: Vec<(u32, ValType)>,
212}
213
214#[derive(Debug, Copy, Clone, PartialEq)]
221pub struct Frame {
222 pub kind: FrameKind,
224 pub block_type: BlockType,
227 pub height: usize,
229 pub unreachable: bool,
231 pub init_height: usize,
233}
234
235struct OperatorValidatorTemp<'validator, 'resources, T> {
236 offset: usize,
237 inner: &'validator mut OperatorValidator,
238 resources: &'resources T,
239}
240
241#[derive(Default)]
242pub struct OperatorValidatorAllocations {
243 popped_types_tmp: Vec<MaybeType>,
244 control: Vec<Frame>,
245 operands: Vec<MaybeType>,
246 local_inits: LocalInits,
247 locals_first: Vec<ValType>,
248 locals_uncached: Vec<(u32, ValType)>,
249 rollback_log: RollbackLogAllocations,
250}
251
252#[derive(Debug, Copy, Clone, PartialEq)]
259enum MaybeType<T = ValType> {
260 Bottom,
266 UnknownRef(Option<AbstractHeapType>),
277 Known(T),
279}
280
281#[test]
285fn assert_maybe_type_small() {
286 assert!(core::mem::size_of::<MaybeType>() == 8);
287}
288
289impl core::fmt::Display for MaybeType {
290 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
291 match self {
292 MaybeType::Bottom => write!(f, "bot"),
293 MaybeType::UnknownRef(ty) => {
294 write!(f, "(ref shared? ")?;
295 match ty {
296 Some(ty) => write!(f, "{}bot", ty.as_str(true))?,
297 None => write!(f, "bot")?,
298 }
299 write!(f, ")")
300 }
301 MaybeType::Known(ty) => core::fmt::Display::fmt(ty, f),
302 }
303 }
304}
305
306impl From<ValType> for MaybeType {
307 fn from(ty: ValType) -> MaybeType {
308 MaybeType::Known(ty)
309 }
310}
311
312impl From<RefType> for MaybeType {
313 fn from(ty: RefType) -> MaybeType {
314 let ty: ValType = ty.into();
315 ty.into()
316 }
317}
318impl From<MaybeType<RefType>> for MaybeType<ValType> {
319 fn from(ty: MaybeType<RefType>) -> MaybeType<ValType> {
320 match ty {
321 MaybeType::Bottom => MaybeType::Bottom,
322 MaybeType::UnknownRef(ty) => MaybeType::UnknownRef(ty),
323 MaybeType::Known(t) => MaybeType::Known(t.into()),
324 }
325 }
326}
327
328impl MaybeType<RefType> {
329 fn as_non_null(&self) -> MaybeType<RefType> {
330 match self {
331 MaybeType::Bottom => MaybeType::Bottom,
332 MaybeType::UnknownRef(ty) => MaybeType::UnknownRef(*ty),
333 MaybeType::Known(ty) => MaybeType::Known(ty.as_non_null()),
334 }
335 }
336
337 fn is_maybe_shared(&self, resources: &impl WasmModuleResources) -> Option<bool> {
338 match self {
339 MaybeType::Bottom => None,
340 MaybeType::UnknownRef(_) => None,
341 MaybeType::Known(ty) => Some(resources.is_shared(*ty)),
342 }
343 }
344}
345
346impl OperatorValidator {
347 fn new(features: &WasmFeatures, allocs: OperatorValidatorAllocations) -> Self {
348 let OperatorValidatorAllocations {
349 popped_types_tmp,
350 control,
351 operands,
352 local_inits,
353 locals_first,
354 locals_uncached,
355 rollback_log,
356 } = allocs;
357 debug_assert!(popped_types_tmp.is_empty());
358 debug_assert!(control.is_empty());
359 debug_assert!(operands.is_empty());
360 debug_assert!(local_inits.is_empty());
361 debug_assert!(locals_first.is_empty());
362 debug_assert!(locals_uncached.is_empty());
363 OperatorValidator {
364 locals: Locals {
365 num_locals: 0,
366 first: locals_first,
367 uncached: locals_uncached,
368 },
369 local_inits,
370 features: *features,
371 popped_types_tmp,
372 operands,
373 control,
374 shared: false,
375 #[cfg(debug_assertions)]
376 pop_push_log: vec![],
377 transaction: Transaction::new(rollback_log),
378 }
379 }
380
381 pub fn new_func<T>(
387 ty: u32,
388 offset: usize,
389 features: &WasmFeatures,
390 resources: &T,
391 allocs: OperatorValidatorAllocations,
392 ) -> Result<Self>
393 where
394 T: WasmModuleResources,
395 {
396 let mut ret = OperatorValidator::new(features, allocs);
397 ret.control.push(Frame {
398 kind: FrameKind::Block,
399 block_type: BlockType::FuncType(ty),
400 height: 0,
401 unreachable: false,
402 init_height: 0,
403 });
404
405 let sub_ty = OperatorValidatorTemp {
408 offset,
409 inner: &mut ret,
410 resources,
411 }
412 .sub_type_at(ty)?;
413
414 if let CompositeInnerType::Func(func_ty) = &sub_ty.composite_type.inner {
416 for ty in func_ty.params() {
417 ret.locals.define(1, *ty);
418 }
419 ret.local_inits.define_params(func_ty.params().len());
420 } else {
421 bail!(offset, "expected func type at index {ty}, found {sub_ty}")
422 }
423
424 if sub_ty.composite_type.shared {
427 ret.shared = true;
428 }
429 Ok(ret)
430 }
431
432 pub fn new_const_expr(
436 features: &WasmFeatures,
437 ty: ValType,
438 allocs: OperatorValidatorAllocations,
439 ) -> Self {
440 let mut ret = OperatorValidator::new(features, allocs);
441 ret.control.push(Frame {
442 kind: FrameKind::Block,
443 block_type: BlockType::Type(ty),
444 height: 0,
445 unreachable: false,
446 init_height: 0,
447 });
448 ret
449 }
450
451 pub fn define_locals(
452 &mut self,
453 offset: usize,
454 count: u32,
455 mut ty: ValType,
456 resources: &impl WasmModuleResources,
457 ) -> Result<()> {
458 resources.check_value_type(&mut ty, &self.features, offset)?;
459 if count == 0 {
460 return Ok(());
461 }
462 if !self.locals.define(count, ty) {
463 return Err(BinaryReaderError::new(
464 "too many locals: locals exceed maximum",
465 offset,
466 ));
467 }
468 self.local_inits.define_locals(count, ty);
469 Ok(())
470 }
471
472 pub fn operand_stack_height(&self) -> usize {
474 self.operands.len()
475 }
476
477 pub fn peek_operand_at(&self, depth: usize) -> Option<Option<ValType>> {
488 Some(match self.operands.iter().rev().nth(depth)? {
489 MaybeType::Known(t) => Some(*t),
490 MaybeType::Bottom | MaybeType::UnknownRef(..) => None,
491 })
492 }
493
494 pub fn control_stack_height(&self) -> usize {
496 self.control.len()
497 }
498
499 pub(crate) fn jump(&self, depth: u32) -> Option<(BlockType, FrameKind)> {
504 assert!(!self.control.is_empty());
505 let i = (self.control.len() - 1).checked_sub(depth as usize)?;
506 let frame = &self.control[i];
507 Some((frame.block_type, frame.kind))
508 }
509
510 pub fn get_frame(&self, depth: usize) -> Option<&Frame> {
511 self.control.iter().rev().nth(depth)
512 }
513
514 pub fn with_resources<'a, 'validator, 'resources, T>(
516 &'validator mut self,
517 resources: &'resources T,
518 offset: usize,
519 ) -> impl VisitOperator<'a, Output = Result<()>> + ModuleArity + FrameStack + 'validator
520 where
521 T: WasmModuleResources,
522 'resources: 'validator,
523 {
524 WasmProposalValidator(OperatorValidatorTemp {
525 offset,
526 inner: self,
527 resources,
528 })
529 }
530
531 #[cfg(feature = "simd")]
534 pub fn with_resources_simd<'a, 'validator, 'resources, T>(
535 &'validator mut self,
536 resources: &'resources T,
537 offset: usize,
538 ) -> impl VisitSimdOperator<'a, Output = Result<()>> + ModuleArity + 'validator
539 where
540 T: WasmModuleResources,
541 'resources: 'validator,
542 {
543 WasmProposalValidator(OperatorValidatorTemp {
544 offset,
545 inner: self,
546 resources,
547 })
548 }
549
550 pub fn into_allocations(mut self) -> OperatorValidatorAllocations {
551 fn clear<T>(mut tmp: Vec<T>) -> Vec<T> {
552 tmp.clear();
553 tmp
554 }
555 OperatorValidatorAllocations {
556 popped_types_tmp: clear(self.popped_types_tmp),
557 control: clear(self.control),
558 operands: clear(self.operands),
559 local_inits: {
560 self.local_inits.clear();
561 self.local_inits
562 },
563 locals_first: clear(self.locals.first),
564 locals_uncached: clear(self.locals.uncached),
565 rollback_log: self.transaction.into_allocations(),
566 }
567 }
568
569 fn record_pop(&mut self, ty: MaybeType) {
571 self.transaction.map(|log| log.record_pop(ty));
572 self.record_any_pop();
573 }
574
575 fn record_any_pop(&mut self) {
577 #[cfg(debug_assertions)]
578 {
579 self.pop_push_log.push(false);
580 }
581 }
582
583 fn record_push(&mut self) {
584 self.transaction.map(|log| log.record_push());
585 #[cfg(debug_assertions)]
586 {
587 self.pop_push_log.push(true);
588 }
589 }
590
591 #[allow(dead_code)]
592 pub(super) fn begin_try_op(&mut self) {
593 self.transaction.begin(self.local_inits.height());
594 }
595
596 #[allow(dead_code)]
597 pub(super) fn commit(&mut self) {
598 self.transaction.end();
599 }
600
601 #[cfg(feature = "try-op")]
605 pub(super) fn rollback(&mut self) {
606 let Transaction::Active(rollback_log) = &self.transaction else {
607 panic!("no transaction pending");
608 };
609
610 if rollback_log.unreachable {
611 self.control.last_mut().unwrap().unreachable = false;
612 }
613
614 for x in rollback_log.operands.iter().rev() {
615 match x {
616 None => {
617 self.operands.pop();
618 }
619 Some(mt) => self.operands.push(*mt),
620 }
621 }
622
623 for x in rollback_log.frames.iter().rev() {
624 match x {
625 None => {
626 let frame = self.control.pop().unwrap();
627 self.local_inits.pop_ctrl(frame.init_height);
628 }
629 Some(frame) => {
630 self.control.push(*frame);
631 }
632 }
633 }
634
635 for idx in &rollback_log.inits {
636 self.local_inits.set_init(*idx);
637 }
638
639 if self.local_inits.height() > rollback_log.init_height {
640 self.local_inits.pop_ctrl(rollback_log.init_height);
641 }
642
643 self.transaction.end();
644 }
645}
646
647impl<R> Deref for OperatorValidatorTemp<'_, '_, R> {
648 type Target = OperatorValidator;
649 fn deref(&self) -> &OperatorValidator {
650 self.inner
651 }
652}
653
654impl<R> DerefMut for OperatorValidatorTemp<'_, '_, R> {
655 fn deref_mut(&mut self) -> &mut OperatorValidator {
656 self.inner
657 }
658}
659
660impl<'resources, R> OperatorValidatorTemp<'_, 'resources, R>
661where
662 R: WasmModuleResources,
663{
664 fn push_operand<T>(&mut self, ty: T) -> Result<()>
670 where
671 T: Into<MaybeType>,
672 {
673 let maybe_ty = ty.into();
674
675 if cfg!(debug_assertions) {
676 match maybe_ty {
677 MaybeType::Known(ValType::Ref(r)) => match r.heap_type() {
678 HeapType::Concrete(index) | HeapType::Exact(index) => {
679 debug_assert!(
680 matches!(index, UnpackedIndex::Id(_)),
681 "only ref types referencing `CoreTypeId`s can \
682 be pushed to the operand stack"
683 );
684 }
685 _ => {}
686 },
687 _ => {}
688 }
689 }
690
691 self.operands.push(maybe_ty);
692 self.record_push();
693 Ok(())
694 }
695
696 fn push_concrete_ref(&mut self, nullable: bool, type_index: u32) -> Result<()> {
697 let mut heap_ty = HeapType::Concrete(UnpackedIndex::Module(type_index));
698
699 self.resources.check_heap_type(&mut heap_ty, self.offset)?;
701 debug_assert!(matches!(heap_ty, HeapType::Concrete(UnpackedIndex::Id(_))));
702
703 let ref_ty = RefType::new(nullable, heap_ty).ok_or_else(|| {
704 format_err!(self.offset, "implementation limit: type index too large")
705 })?;
706
707 self.push_operand(ref_ty)
708 }
709
710 fn push_exact_ref(&mut self, nullable: bool, type_index: u32) -> Result<()> {
711 let mut heap_ty = HeapType::Exact(UnpackedIndex::Module(type_index));
712
713 self.resources.check_heap_type(&mut heap_ty, self.offset)?;
715 debug_assert!(matches!(heap_ty, HeapType::Exact(UnpackedIndex::Id(_))));
716
717 let ref_ty = RefType::new(nullable, heap_ty).ok_or_else(|| {
718 format_err!(self.offset, "implementation limit: type index too large")
719 })?;
720
721 self.push_operand(ref_ty)
722 }
723
724 fn push_exact_ref_if_available(&mut self, nullable: bool, type_index: u32) -> Result<()> {
725 if self.features.custom_descriptors() {
726 self.push_exact_ref(nullable, type_index)
727 } else {
728 self.push_concrete_ref(nullable, type_index)
729 }
730 }
731
732 fn pop_concrete_ref(&mut self, nullable: bool, type_index: u32) -> Result<MaybeType> {
733 let mut heap_ty = HeapType::Concrete(UnpackedIndex::Module(type_index));
734
735 self.resources.check_heap_type(&mut heap_ty, self.offset)?;
737 debug_assert!(matches!(heap_ty, HeapType::Concrete(UnpackedIndex::Id(_))));
738
739 let ref_ty = RefType::new(nullable, heap_ty).ok_or_else(|| {
740 format_err!(self.offset, "implementation limit: type index too large")
741 })?;
742
743 self.pop_operand(Some(ref_ty.into()))
744 }
745
746 fn pop_concrete_or_exact_ref(
747 &mut self,
748 nullable: bool,
749 type_index: u32,
750 ) -> Result<(MaybeType, bool)> {
751 let ty = self.pop_concrete_ref(nullable, type_index)?;
752 let is_exact = match ty {
753 MaybeType::Known(ValType::Ref(rt)) if rt.is_exact_type_ref() || rt.is_none_ref() => {
754 let mut heap_ty = HeapType::Exact(UnpackedIndex::Module(type_index));
755 self.resources.check_heap_type(&mut heap_ty, self.offset)?;
756 let expected = RefType::new(nullable, heap_ty).ok_or_else(|| {
757 format_err!(self.offset, "implementation limit: type index too large")
758 })?;
759 self.resources.is_subtype(rt.into(), expected.into())
760 }
761 MaybeType::Bottom => true,
762 _ => false,
763 };
764 Ok((ty, is_exact))
765 }
766
767 fn pop_push_label_types(
770 &mut self,
771 label_types: impl PreciseIterator<Item = ValType>,
772 ) -> Result<()> {
773 for ty in label_types.clone().rev() {
774 self.pop_operand(Some(ty))?;
775 }
776 for ty in label_types {
777 self.push_operand(ty)?;
778 }
779 Ok(())
780 }
781
782 fn pop_operand(&mut self, expected: Option<ValType>) -> Result<MaybeType> {
801 let popped = match self.operands.pop() {
813 Some(MaybeType::Known(actual_ty)) => {
814 if Some(actual_ty) == expected {
815 if let Some(control) = self.control.last() {
816 if self.operands.len() >= control.height {
817 self.record_pop(MaybeType::Known(actual_ty));
818 return Ok(MaybeType::Known(actual_ty));
819 }
820 }
821 }
822 Some(MaybeType::Known(actual_ty))
823 }
824 other => other,
825 };
826
827 self._pop_operand(expected, popped)
828 }
829
830 #[cold]
834 fn _pop_operand(
835 &mut self,
836 expected: Option<ValType>,
837 popped: Option<MaybeType>,
838 ) -> Result<MaybeType> {
839 self.operands.extend(popped);
840 let control = self.control.last().unwrap();
841 let actual = if self.operands.len() == control.height && control.unreachable {
842 self.record_any_pop();
843 MaybeType::Bottom
844 } else {
845 if self.operands.len() == control.height {
846 let desc = match expected {
847 Some(ty) => ty_to_str(ty),
848 None => "a type".into(),
849 };
850 bail!(
851 self.offset,
852 "type mismatch: expected {desc} but nothing on stack"
853 )
854 } else {
855 let ty = self.operands.pop().unwrap();
856 self.record_pop(ty);
857 ty
858 }
859 };
860 if let Some(expected) = expected {
861 match (actual, expected) {
862 (MaybeType::Bottom, _) => {}
864
865 (MaybeType::UnknownRef(actual_ty), ValType::Ref(expected)) => {
870 if let Some(actual) = actual_ty {
871 let expected_shared = self.resources.is_shared(expected);
872 let actual = RefType::new(
873 false,
874 HeapType::Abstract {
875 shared: expected_shared,
876 ty: actual,
877 },
878 )
879 .unwrap();
880 if !self.resources.is_subtype(actual.into(), expected.into()) {
881 bail!(
882 self.offset,
883 "type mismatch: expected {}, found {}",
884 ty_to_str(expected.into()),
885 ty_to_str(actual.into())
886 );
887 }
888 }
889 }
890
891 (MaybeType::Known(actual), expected) => {
894 if !self.resources.is_subtype(actual, expected) {
895 bail!(
896 self.offset,
897 "type mismatch: expected {}, found {}",
898 ty_to_str(expected),
899 ty_to_str(actual)
900 );
901 }
902 }
903
904 (
906 MaybeType::UnknownRef(..),
907 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128,
908 ) => {
909 bail!(
910 self.offset,
911 "type mismatch: expected {}, found heap type",
912 ty_to_str(expected)
913 )
914 }
915 }
916 }
917 Ok(actual)
918 }
919
920 fn match_operand(
922 &mut self,
923 actual: ValType,
924 expected: ValType,
925 ) -> Result<(), BinaryReaderError> {
926 self.push_operand(actual)?;
927 self.pop_operand(Some(expected))?;
928 Ok(())
929 }
930
931 fn match_stack_operands(
933 &mut self,
934 expected_tys: impl PreciseIterator<Item = ValType> + 'resources,
935 ) -> Result<()> {
936 let mut popped_types_tmp = mem::take(&mut self.popped_types_tmp);
937 debug_assert!(popped_types_tmp.is_empty());
938 popped_types_tmp.reserve(expected_tys.len());
939
940 for expected_ty in expected_tys.rev() {
941 let actual_ty = self.pop_operand(Some(expected_ty))?;
942 popped_types_tmp.push(actual_ty);
943 }
944 for ty in popped_types_tmp.drain(..).rev() {
945 self.push_operand(ty)?;
946 }
947
948 debug_assert!(self.popped_types_tmp.is_empty());
949 self.popped_types_tmp = popped_types_tmp;
950 Ok(())
951 }
952
953 fn pop_ref(&mut self, expected: Option<RefType>) -> Result<MaybeType<RefType>> {
955 match self.pop_operand(expected.map(|t| t.into()))? {
956 MaybeType::Bottom => Ok(MaybeType::UnknownRef(None)),
957 MaybeType::UnknownRef(ty) => Ok(MaybeType::UnknownRef(ty)),
958 MaybeType::Known(ValType::Ref(rt)) => Ok(MaybeType::Known(rt)),
959 MaybeType::Known(ty) => bail!(
960 self.offset,
961 "type mismatch: expected ref but found {}",
962 ty_to_str(ty)
963 ),
964 }
965 }
966
967 fn pop_maybe_shared_ref(&mut self, expected: AbstractHeapType) -> Result<MaybeType<RefType>> {
973 let actual = match self.pop_ref(None)? {
974 MaybeType::Bottom => return Ok(MaybeType::Bottom),
975 MaybeType::UnknownRef(None) => return Ok(MaybeType::UnknownRef(None)),
976 MaybeType::UnknownRef(Some(actual)) => {
977 if !actual.is_subtype_of(expected) {
978 bail!(
979 self.offset,
980 "type mismatch: expected subtype of {}, found {}",
981 expected.as_str(false),
982 actual.as_str(false),
983 )
984 }
985 return Ok(MaybeType::UnknownRef(Some(actual)));
986 }
987 MaybeType::Known(ty) => ty,
988 };
989 let is_actual_shared = self.resources.is_shared(actual);
992 let expected = RefType::new(
993 true,
994 HeapType::Abstract {
995 shared: is_actual_shared,
996 ty: expected,
997 },
998 )
999 .unwrap();
1000
1001 if !self.resources.is_subtype(actual.into(), expected.into()) {
1005 bail!(
1006 self.offset,
1007 "type mismatch: expected subtype of {expected}, found {actual}",
1008 )
1009 }
1010 Ok(MaybeType::Known(actual))
1011 }
1012
1013 fn local(&self, idx: u32) -> Result<ValType> {
1016 match self.locals.get(idx) {
1017 Some(ty) => Ok(ty),
1018 None => bail!(
1019 self.offset,
1020 "unknown local {}: local index out of bounds",
1021 idx
1022 ),
1023 }
1024 }
1025
1026 fn unreachable(&mut self) -> Result<()> {
1029 if !self.control.last().unwrap().unreachable {
1030 self.transaction.map(|log| log.set_unreachable());
1031 }
1032
1033 let control = self.control.last_mut().unwrap();
1034 control.unreachable = true;
1035 let new_height = control.height;
1036
1037 let operands = self.operands.split_off(new_height);
1038 self.transaction.map(|log| {
1039 for op in operands.iter().rev() {
1040 log.record_pop(*op);
1041 }
1042 });
1043
1044 self.operands.truncate(new_height);
1045 Ok(())
1046 }
1047
1048 fn push_ctrl(&mut self, kind: FrameKind, ty: BlockType) -> Result<()> {
1055 self.push_bare_ctrl(kind, ty);
1056 for ty in self.params(ty)? {
1059 self.push_operand(ty)?;
1060 }
1061 Ok(())
1062 }
1063
1064 fn push_bare_ctrl(&mut self, kind: FrameKind, ty: BlockType) {
1067 let height = self.operands.len();
1070 let init_height = self.local_inits.height();
1071 self.control.push(Frame {
1072 kind,
1073 block_type: ty,
1074 height,
1075 unreachable: false,
1076 init_height,
1077 });
1078 self.transaction.map(|log| log.push_ctrl());
1079 }
1080
1081 fn pop_ctrl(&mut self) -> Result<Frame> {
1086 let frame = self.control.last().unwrap();
1089 let ty = frame.block_type;
1090 let height = frame.height;
1091
1092 for ty in self.results(ty)?.rev() {
1095 self.pop_operand(Some(ty))?;
1096 }
1097
1098 if self.operands.len() != height {
1101 bail!(
1102 self.offset,
1103 "type mismatch: values remaining on stack at end of block"
1104 );
1105 }
1106
1107 let frame = self.control.pop().unwrap();
1109 let _inits = self.local_inits.pop_ctrl(frame.init_height);
1110 self.transaction.map(|log| log.pop_ctrl(frame, _inits));
1111
1112 Ok(frame)
1113 }
1114
1115 fn jump(&self, depth: u32) -> Result<(BlockType, FrameKind)> {
1120 match self.inner.jump(depth) {
1121 Some(tup) => Ok(tup),
1122 None => bail!(self.offset, "unknown label: branch depth too large"),
1123 }
1124 }
1125
1126 fn check_memory_index(&self, memory_index: u32) -> Result<ValType> {
1129 match self.resources.memory_at(memory_index) {
1130 Some(mem) => Ok(mem.index_type()),
1131 None => bail!(self.offset, "unknown memory {}", memory_index),
1132 }
1133 }
1134
1135 fn check_memarg(&self, memarg: MemArg) -> Result<ValType> {
1138 let index_ty = self.check_memory_index(memarg.memory)?;
1139 if memarg.align > memarg.max_align {
1140 bail!(
1141 self.offset,
1142 "invalid memop alignment: alignment must not be larger than natural"
1143 );
1144 }
1145 if index_ty == ValType::I32 && memarg.offset > u64::from(u32::MAX) {
1146 bail!(self.offset, "offset out of range: must be <= 2**32");
1147 }
1148 Ok(index_ty)
1149 }
1150
1151 fn check_floats_enabled(&self) -> Result<()> {
1152 if !self.features.floats() {
1153 bail!(self.offset, "floating-point instruction disallowed");
1154 }
1155 Ok(())
1156 }
1157
1158 fn check_shared_memarg(&self, memarg: MemArg) -> Result<ValType> {
1159 if memarg.align != memarg.max_align {
1160 bail!(
1161 self.offset,
1162 "atomic instructions must always specify maximum alignment"
1163 );
1164 }
1165 self.check_memory_index(memarg.memory)
1166 }
1167
1168 fn check_block_type(&self, ty: &mut BlockType) -> Result<()> {
1170 match ty {
1171 BlockType::Empty => Ok(()),
1172 BlockType::Type(t) => self
1173 .resources
1174 .check_value_type(t, &self.features, self.offset),
1175 BlockType::FuncType(idx) => {
1176 if !self.features.multi_value() {
1177 bail!(
1178 self.offset,
1179 "blocks, loops, and ifs may only produce a resulttype \
1180 when multi-value is not enabled",
1181 );
1182 }
1183 self.func_type_at(*idx)?;
1184 Ok(())
1185 }
1186 }
1187 }
1188
1189 fn type_of_function(&self, function_index: u32) -> Result<&'resources FuncType> {
1192 if let Some(type_index) = self.resources.type_index_of_function(function_index) {
1193 self.func_type_at(type_index)
1194 } else {
1195 bail!(
1196 self.offset,
1197 "unknown function {function_index}: function index out of bounds",
1198 )
1199 }
1200 }
1201
1202 fn check_call_ty(&mut self, ty: &FuncType) -> Result<()> {
1208 for &ty in ty.params().iter().rev() {
1209 debug_assert_type_indices_are_ids(ty);
1210 self.pop_operand(Some(ty))?;
1211 }
1212 for &ty in ty.results() {
1213 debug_assert_type_indices_are_ids(ty);
1214 self.push_operand(ty)?;
1215 }
1216 Ok(())
1217 }
1218
1219 fn check_return_call_ty(&mut self, ty: &FuncType) -> Result<()> {
1221 self.check_func_type_same_results(ty)?;
1222 for &ty in ty.params().iter().rev() {
1223 debug_assert_type_indices_are_ids(ty);
1224 self.pop_operand(Some(ty))?;
1225 }
1226
1227 for &ty in ty.results() {
1229 debug_assert_type_indices_are_ids(ty);
1230 self.push_operand(ty)?;
1231 }
1232 self.check_return()?;
1233
1234 Ok(())
1235 }
1236
1237 fn check_call_ref_ty(&mut self, type_index: u32) -> Result<&'resources FuncType> {
1245 let unpacked_index = UnpackedIndex::Module(type_index);
1246 let mut hty = HeapType::Concrete(unpacked_index);
1247 self.resources.check_heap_type(&mut hty, self.offset)?;
1248 let expected = RefType::new(true, hty).expect("hty should be previously validated");
1249 self.pop_ref(Some(expected))?;
1250 self.func_type_at(type_index)
1251 }
1252
1253 fn check_call_indirect_ty(
1263 &mut self,
1264 type_index: u32,
1265 table_index: u32,
1266 ) -> Result<&'resources FuncType> {
1267 let tab = self.table_type_at(table_index)?;
1268 if !self
1269 .resources
1270 .is_subtype(ValType::Ref(tab.element_type), ValType::FUNCREF)
1271 {
1272 bail!(
1273 self.offset,
1274 "type mismatch: indirect calls must go through a table with type <= funcref",
1275 );
1276 }
1277 self.pop_operand(Some(tab.index_type()))?;
1278 self.func_type_at(type_index)
1279 }
1280
1281 fn check_return(&mut self) -> Result<()> {
1284 assert!(!self.control.is_empty());
1285 for ty in self.results(self.control[0].block_type)?.rev() {
1286 self.pop_operand(Some(ty))?;
1287 }
1288 self.unreachable()?;
1289 Ok(())
1290 }
1291
1292 fn check_func_type_same_results(&self, callee_ty: &FuncType) -> Result<()> {
1295 assert!(!self.control.is_empty());
1296 let caller_rets = self.results(self.control[0].block_type)?;
1297 if callee_ty.results().len() != caller_rets.len()
1298 || !caller_rets
1299 .zip(callee_ty.results())
1300 .all(|(caller_ty, callee_ty)| self.resources.is_subtype(*callee_ty, caller_ty))
1301 {
1302 let caller_rets = self
1303 .results(self.control[0].block_type)?
1304 .map(|ty| format!("{ty}"))
1305 .collect::<Vec<_>>()
1306 .join(" ");
1307 let callee_rets = callee_ty
1308 .results()
1309 .iter()
1310 .map(|ty| format!("{ty}"))
1311 .collect::<Vec<_>>()
1312 .join(" ");
1313 bail!(
1314 self.offset,
1315 "type mismatch: current function requires result type \
1316 [{caller_rets}] but callee returns [{callee_rets}]"
1317 );
1318 }
1319 Ok(())
1320 }
1321
1322 fn check_cmp_op(&mut self, ty: ValType) -> Result<()> {
1324 self.pop_operand(Some(ty))?;
1325 self.pop_operand(Some(ty))?;
1326 self.push_operand(ValType::I32)?;
1327 Ok(())
1328 }
1329
1330 fn check_fcmp_op(&mut self, ty: ValType) -> Result<()> {
1332 debug_assert!(matches!(ty, ValType::F32 | ValType::F64));
1333 self.check_floats_enabled()?;
1334 self.check_cmp_op(ty)
1335 }
1336
1337 fn check_unary_op(&mut self, ty: ValType) -> Result<()> {
1339 self.pop_operand(Some(ty))?;
1340 self.push_operand(ty)?;
1341 Ok(())
1342 }
1343
1344 fn check_funary_op(&mut self, ty: ValType) -> Result<()> {
1346 debug_assert!(matches!(ty, ValType::F32 | ValType::F64));
1347 self.check_floats_enabled()?;
1348 self.check_unary_op(ty)
1349 }
1350
1351 fn check_conversion_op(&mut self, into: ValType, from: ValType) -> Result<()> {
1353 self.pop_operand(Some(from))?;
1354 self.push_operand(into)?;
1355 Ok(())
1356 }
1357
1358 fn check_fconversion_op(&mut self, into: ValType, from: ValType) -> Result<()> {
1360 debug_assert!(matches!(into, ValType::F32 | ValType::F64));
1361 self.check_floats_enabled()?;
1362 self.check_conversion_op(into, from)
1363 }
1364
1365 fn check_binary_op(&mut self, ty: ValType) -> Result<()> {
1367 self.pop_operand(Some(ty))?;
1368 self.pop_operand(Some(ty))?;
1369 self.push_operand(ty)?;
1370 Ok(())
1371 }
1372
1373 fn check_fbinary_op(&mut self, ty: ValType) -> Result<()> {
1375 debug_assert!(matches!(ty, ValType::F32 | ValType::F64));
1376 self.check_floats_enabled()?;
1377 self.check_binary_op(ty)
1378 }
1379
1380 fn check_atomic_load(&mut self, memarg: MemArg, load_ty: ValType) -> Result<()> {
1382 let ty = self.check_shared_memarg(memarg)?;
1383 self.pop_operand(Some(ty))?;
1384 self.push_operand(load_ty)?;
1385 Ok(())
1386 }
1387
1388 fn check_atomic_store(&mut self, memarg: MemArg, store_ty: ValType) -> Result<()> {
1390 let ty = self.check_shared_memarg(memarg)?;
1391 self.pop_operand(Some(store_ty))?;
1392 self.pop_operand(Some(ty))?;
1393 Ok(())
1394 }
1395
1396 fn check_atomic_binary_memory_op(&mut self, memarg: MemArg, op_ty: ValType) -> Result<()> {
1398 let ty = self.check_shared_memarg(memarg)?;
1399 self.pop_operand(Some(op_ty))?;
1400 self.pop_operand(Some(ty))?;
1401 self.push_operand(op_ty)?;
1402 Ok(())
1403 }
1404
1405 fn check_atomic_binary_memory_cmpxchg(&mut self, memarg: MemArg, op_ty: ValType) -> Result<()> {
1407 let ty = self.check_shared_memarg(memarg)?;
1408 self.pop_operand(Some(op_ty))?;
1409 self.pop_operand(Some(op_ty))?;
1410 self.pop_operand(Some(ty))?;
1411 self.push_operand(op_ty)?;
1412 Ok(())
1413 }
1414
1415 fn check_downcast(&mut self, nullable: bool, mut heap_type: HeapType) -> Result<RefType> {
1418 self.resources
1419 .check_heap_type(&mut heap_type, self.offset)?;
1420
1421 let sub_ty = RefType::new(nullable, heap_type).ok_or_else(|| {
1422 BinaryReaderError::new("implementation limit: type index too large", self.offset)
1423 })?;
1424 let sup_ty = RefType::new(true, self.resources.top_type(&heap_type))
1425 .expect("can't panic with non-concrete heap types");
1426
1427 self.pop_ref(Some(sup_ty))?;
1428 Ok(sub_ty)
1429 }
1430
1431 fn check_ref_test(&mut self, nullable: bool, heap_type: HeapType) -> Result<()> {
1434 self.check_downcast(nullable, heap_type)?;
1435 self.push_operand(ValType::I32)
1436 }
1437
1438 fn check_ref_cast(&mut self, nullable: bool, heap_type: HeapType) -> Result<()> {
1441 let sub_ty = self.check_downcast(nullable, heap_type)?;
1442 self.push_operand(sub_ty)
1443 }
1444
1445 fn check_br_on_cast_type_hierarchy(
1447 &self,
1448 from_ref_type: RefType,
1449 to_ref_type: RefType,
1450 ) -> Result<()> {
1451 if self.features.custom_descriptors() {
1452 let from_ref_type_top = self.resources.top_type(&from_ref_type.heap_type());
1457 let to_ref_type_top = self.resources.top_type(&to_ref_type.heap_type());
1458 if from_ref_type_top != to_ref_type_top {
1459 bail!(
1460 self.offset,
1461 "type mismatch: {from_ref_type} and {to_ref_type} have different heap type hierarchies"
1462 );
1463 }
1464 return Ok(());
1465 }
1466
1467 if !self
1468 .resources
1469 .is_subtype(to_ref_type.into(), from_ref_type.into())
1470 {
1471 bail!(
1472 self.offset,
1473 "type mismatch: expected {from_ref_type}, found {to_ref_type}"
1474 );
1475 }
1476 Ok(())
1477 }
1478
1479 fn check_descriptor(&self, heap_type: HeapType) -> Result<u32> {
1481 Ok(match heap_type {
1482 HeapType::Exact(idx) | HeapType::Concrete(idx) => {
1483 if let Some(descriptor_idx) = self
1484 .sub_type_at(idx.as_module_index().unwrap())?
1485 .composite_type
1486 .descriptor_idx
1487 {
1488 u32::try_from(crate::validator::types::TypeIdentifier::index(
1489 &descriptor_idx.as_core_type_id().unwrap(),
1490 ))
1491 .unwrap()
1492 } else {
1493 bail!(self.offset, "cast target must have descriptor")
1494 }
1495 }
1496 _ => bail!(self.offset, "unexpected heap type"),
1497 })
1498 }
1499
1500 fn check_maybe_exact_descriptor_ref(&mut self, heap_type: HeapType) -> Result<bool> {
1501 let descriptor_idx = self.check_descriptor(heap_type)?;
1502 let (ty, _is_exact) = self.pop_concrete_or_exact_ref(true, descriptor_idx)?;
1503 let is_exact = if let HeapType::Exact(_) = heap_type {
1504 let mut descriptor_ty = HeapType::Exact(UnpackedIndex::Module(descriptor_idx));
1505 self.resources
1506 .check_heap_type(&mut descriptor_ty, self.offset)?;
1507 let descriptor_ty = ValType::Ref(
1508 RefType::new(true, descriptor_ty)
1509 .expect("existing heap types should be within our limits"),
1510 );
1511
1512 match ty {
1513 MaybeType::Known(actual) if !self.resources.is_subtype(actual, descriptor_ty) => {
1514 bail!(
1515 self.offset,
1516 "type mismatch: expected descriptor of exact type {descriptor_ty} found {actual}",
1517 );
1518 }
1519 _ => (),
1520 }
1521 true
1522 } else {
1523 false
1524 };
1525 Ok(is_exact)
1526 }
1527
1528 fn check_ref_cast_desc_eq(&mut self, nullable: bool, heap_type: HeapType) -> Result<()> {
1531 let is_exact = self.check_maybe_exact_descriptor_ref(heap_type)?;
1532
1533 self.check_downcast(nullable, heap_type)?;
1534
1535 let idx = {
1536 let mut heap_type = heap_type;
1537 self.resources
1538 .check_heap_type(&mut heap_type, self.offset)?;
1539 match heap_type {
1540 HeapType::Concrete(index) | HeapType::Exact(index) => {
1541 index.pack().ok_or_else(|| {
1542 BinaryReaderError::new(
1543 "implementation limit: type index too large",
1544 self.offset,
1545 )
1546 })?
1547 }
1548 _ => panic!(),
1549 }
1550 };
1551
1552 self.push_operand(if is_exact {
1553 RefType::exact(nullable, idx)
1554 } else {
1555 RefType::concrete(nullable, idx)
1556 })
1557 }
1558
1559 fn check_atomic_global_rmw_ty(&self, global_index: u32) -> Result<ValType> {
1562 let ty = self.global_type_at(global_index)?.content_type;
1563 if !(ty == ValType::I32 || ty == ValType::I64) {
1564 bail!(
1565 self.offset,
1566 "invalid type: `global.atomic.rmw.*` only allows `i32` and `i64`"
1567 );
1568 }
1569 Ok(ty)
1570 }
1571
1572 fn check_struct_atomic_rmw(
1575 &mut self,
1576 op: &'static str,
1577 struct_type_index: u32,
1578 field_index: u32,
1579 ) -> Result<()> {
1580 let field = self.mutable_struct_field_at(struct_type_index, field_index)?;
1581 let field_ty = match field.element_type {
1582 StorageType::Val(ValType::I32) => ValType::I32,
1583 StorageType::Val(ValType::I64) => ValType::I64,
1584 _ => bail!(
1585 self.offset,
1586 "invalid type: `struct.atomic.rmw.{}` only allows `i32` and `i64`",
1587 op
1588 ),
1589 };
1590 self.pop_operand(Some(field_ty))?;
1591 self.pop_concrete_ref(true, struct_type_index)?;
1592 self.push_operand(field_ty)?;
1593 Ok(())
1594 }
1595
1596 fn check_array_atomic_rmw(&mut self, op: &'static str, type_index: u32) -> Result<()> {
1599 let field = self.mutable_array_type_at(type_index)?;
1600 let elem_ty = match field.element_type {
1601 StorageType::Val(ValType::I32) => ValType::I32,
1602 StorageType::Val(ValType::I64) => ValType::I64,
1603 _ => bail!(
1604 self.offset,
1605 "invalid type: `array.atomic.rmw.{}` only allows `i32` and `i64`",
1606 op
1607 ),
1608 };
1609 self.pop_operand(Some(elem_ty))?;
1610 self.pop_operand(Some(ValType::I32))?;
1611 self.pop_concrete_ref(true, type_index)?;
1612 self.push_operand(elem_ty)?;
1613 Ok(())
1614 }
1615
1616 fn element_type_at(&self, elem_index: u32) -> Result<RefType> {
1617 match self.resources.element_type_at(elem_index) {
1618 Some(ty) => Ok(ty),
1619 None => bail!(
1620 self.offset,
1621 "unknown elem segment {}: segment index out of bounds",
1622 elem_index
1623 ),
1624 }
1625 }
1626
1627 fn sub_type_at(&self, at: u32) -> Result<&'resources SubType> {
1628 self.resources
1629 .sub_type_at(at)
1630 .ok_or_else(|| format_err!(self.offset, "unknown type: type index out of bounds"))
1631 }
1632
1633 fn struct_type_at(&self, at: u32) -> Result<&'resources StructType> {
1634 let sub_ty = self.sub_type_at(at)?;
1635 if let CompositeInnerType::Struct(struct_ty) = &sub_ty.composite_type.inner {
1636 if self.inner.shared && !sub_ty.composite_type.shared {
1637 bail!(
1638 self.offset,
1639 "shared functions cannot access unshared structs",
1640 );
1641 }
1642 Ok(struct_ty)
1643 } else {
1644 bail!(
1645 self.offset,
1646 "expected struct type at index {at}, found {sub_ty}"
1647 )
1648 }
1649 }
1650
1651 fn struct_field_at(&self, struct_type_index: u32, field_index: u32) -> Result<FieldType> {
1652 let field_index = usize::try_from(field_index).map_err(|_| {
1653 BinaryReaderError::new("unknown field: field index out of bounds", self.offset)
1654 })?;
1655 self.struct_type_at(struct_type_index)?
1656 .fields
1657 .get(field_index)
1658 .copied()
1659 .ok_or_else(|| {
1660 BinaryReaderError::new("unknown field: field index out of bounds", self.offset)
1661 })
1662 }
1663
1664 fn mutable_struct_field_at(
1665 &self,
1666 struct_type_index: u32,
1667 field_index: u32,
1668 ) -> Result<FieldType> {
1669 let field = self.struct_field_at(struct_type_index, field_index)?;
1670 if !field.mutable {
1671 bail!(
1672 self.offset,
1673 "invalid struct modification: struct field is immutable"
1674 )
1675 }
1676 Ok(field)
1677 }
1678
1679 fn array_type_at(&self, at: u32) -> Result<FieldType> {
1680 let sub_ty = self.sub_type_at(at)?;
1681 if let CompositeInnerType::Array(array_ty) = &sub_ty.composite_type.inner {
1682 if self.inner.shared && !sub_ty.composite_type.shared {
1683 bail!(
1684 self.offset,
1685 "shared functions cannot access unshared arrays",
1686 );
1687 }
1688 Ok(array_ty.0)
1689 } else {
1690 bail!(
1691 self.offset,
1692 "expected array type at index {at}, found {sub_ty}"
1693 )
1694 }
1695 }
1696
1697 fn mutable_array_type_at(&self, at: u32) -> Result<FieldType> {
1698 let field = self.array_type_at(at)?;
1699 if !field.mutable {
1700 bail!(
1701 self.offset,
1702 "invalid array modification: array is immutable"
1703 )
1704 }
1705 Ok(field)
1706 }
1707
1708 fn func_type_at(&self, at: u32) -> Result<&'resources FuncType> {
1709 let sub_ty = self.sub_type_at(at)?;
1710 if let CompositeInnerType::Func(func_ty) = &sub_ty.composite_type.inner {
1711 if self.inner.shared && !sub_ty.composite_type.shared {
1712 bail!(
1713 self.offset,
1714 "shared functions cannot access unshared functions",
1715 );
1716 }
1717 Ok(func_ty)
1718 } else {
1719 bail!(
1720 self.offset,
1721 "expected func type at index {at}, found {sub_ty}"
1722 )
1723 }
1724 }
1725
1726 fn cont_type_at(&self, at: u32) -> Result<&ContType> {
1727 let sub_ty = self.sub_type_at(at)?;
1728 if let CompositeInnerType::Cont(cont_ty) = &sub_ty.composite_type.inner {
1729 if self.inner.shared && !sub_ty.composite_type.shared {
1730 bail!(
1731 self.offset,
1732 "shared continuations cannot access unshared continuations",
1733 );
1734 }
1735 Ok(cont_ty)
1736 } else {
1737 bail!(self.offset, "non-continuation type {at}",)
1738 }
1739 }
1740
1741 fn func_type_of_cont_type(&self, cont_ty: &ContType) -> &'resources FuncType {
1742 let func_id = cont_ty.0.as_core_type_id().expect("valid core type id");
1743 self.resources.sub_type_at_id(func_id).unwrap_func()
1744 }
1745
1746 fn tag_at(&self, at: u32) -> Result<&'resources FuncType> {
1747 self.resources
1748 .tag_at(at)
1749 .ok_or_else(|| format_err!(self.offset, "unknown tag {}: tag index out of bounds", at))
1750 }
1751
1752 fn exception_tag_at(&self, at: u32) -> Result<&'resources FuncType> {
1756 let func_ty = self.tag_at(at)?;
1757 if func_ty.results().len() != 0 {
1758 bail!(
1759 self.offset,
1760 "invalid exception type: non-empty tag result type"
1761 );
1762 }
1763 Ok(func_ty)
1764 }
1765
1766 fn global_type_at(&self, at: u32) -> Result<GlobalType> {
1767 if let Some(ty) = self.resources.global_at(at) {
1768 if self.inner.shared && !ty.shared {
1769 bail!(
1770 self.offset,
1771 "shared functions cannot access unshared globals",
1772 );
1773 }
1774 Ok(ty)
1775 } else {
1776 bail!(self.offset, "unknown global: global index out of bounds");
1777 }
1778 }
1779
1780 fn table_type_at(&self, table: u32) -> Result<TableType> {
1782 match self.resources.table_at(table) {
1783 Some(ty) => {
1784 if self.inner.shared && !ty.shared {
1785 bail!(
1786 self.offset,
1787 "shared functions cannot access unshared tables",
1788 );
1789 }
1790 Ok(ty)
1791 }
1792 None => bail!(
1793 self.offset,
1794 "unknown table {table}: table index out of bounds"
1795 ),
1796 }
1797 }
1798
1799 fn params(&self, ty: BlockType) -> Result<impl PreciseIterator<Item = ValType> + 'resources> {
1800 Ok(match ty {
1801 BlockType::Empty | BlockType::Type(_) => Either::B(None.into_iter()),
1802 BlockType::FuncType(t) => Either::A(self.func_type_at(t)?.params().iter().copied()),
1803 })
1804 }
1805
1806 fn results(&self, ty: BlockType) -> Result<impl PreciseIterator<Item = ValType> + 'resources> {
1807 Ok(match ty {
1808 BlockType::Empty => Either::B(None.into_iter()),
1809 BlockType::Type(t) => Either::B(Some(t).into_iter()),
1810 BlockType::FuncType(t) => Either::A(self.func_type_at(t)?.results().iter().copied()),
1811 })
1812 }
1813
1814 fn label_types(
1815 &self,
1816 ty: BlockType,
1817 kind: FrameKind,
1818 ) -> Result<impl PreciseIterator<Item = ValType> + 'resources> {
1819 Ok(match kind {
1820 FrameKind::Loop => Either::A(self.params(ty)?),
1821 _ => Either::B(self.results(ty)?),
1822 })
1823 }
1824
1825 fn check_data_segment(&self, data_index: u32) -> Result<()> {
1826 match self.resources.data_count() {
1827 None => bail!(self.offset, "data count section required"),
1828 Some(count) if data_index < count => Ok(()),
1829 Some(_) => bail!(self.offset, "unknown data segment {data_index}"),
1830 }
1831 }
1832
1833 fn check_resume_table(
1834 &mut self,
1835 table: ResumeTable,
1836 type_index: u32, ) -> Result<&'resources FuncType> {
1838 let cont_ty = self.cont_type_at(type_index)?;
1839 let old_func_ty = self.func_type_of_cont_type(cont_ty);
1841 for handle in table.handlers {
1842 match handle {
1843 Handle::OnLabel { tag, label } => {
1844 let tag_ty = self.tag_at(tag)?;
1846 let block = self.jump(label)?;
1848 match self.label_types(block.0, block.1)?.last() {
1850 Some(ValType::Ref(rt)) if rt.is_concrete_type_ref() => {
1851 let sub_ty = self.resources.sub_type_at_id(
1852 rt.type_index()
1853 .unwrap()
1854 .as_core_type_id()
1855 .expect("canonicalized index"),
1856 );
1857 let new_cont = if let CompositeInnerType::Cont(cont) =
1858 &sub_ty.composite_type.inner
1859 {
1860 cont
1861 } else {
1862 bail!(self.offset, "non-continuation type");
1863 };
1864 let new_func_ty = self.func_type_of_cont_type(&new_cont);
1865 if new_func_ty.params().len() != tag_ty.results().len()
1867 || !self.is_subtype_many(new_func_ty.params(), tag_ty.results())
1868 || old_func_ty.results().len() != new_func_ty.results().len()
1869 || !self
1870 .is_subtype_many(old_func_ty.results(), new_func_ty.results())
1871 {
1872 bail!(self.offset, "type mismatch in continuation type")
1873 }
1874 let expected_nargs = tag_ty.params().len() + 1;
1875 let actual_nargs = self.label_types(block.0, block.1)?.len();
1876 if actual_nargs != expected_nargs {
1877 bail!(
1878 self.offset,
1879 "type mismatch: expected {expected_nargs} label result(s), but label is annotated with {actual_nargs} results"
1880 )
1881 }
1882
1883 let labeltys =
1884 self.label_types(block.0, block.1)?.take(expected_nargs - 1);
1885
1886 for (tagty, &lblty) in labeltys.zip(tag_ty.params()) {
1888 if !self.resources.is_subtype(lblty, tagty) {
1889 bail!(
1890 self.offset,
1891 "type mismatch between tag type and label type"
1892 )
1893 }
1894 }
1895 }
1896 Some(ty) => {
1897 bail!(self.offset, "type mismatch: {}", ty_to_str(ty))
1898 }
1899 _ => bail!(
1900 self.offset,
1901 "type mismatch: instruction requires continuation reference type but label has none"
1902 ),
1903 }
1904 }
1905 Handle::OnSwitch { tag } => {
1906 let tag_ty = self.tag_at(tag)?;
1907 if tag_ty.params().len() != 0 {
1908 bail!(self.offset, "type mismatch: non-empty tag parameter type")
1909 }
1910 }
1911 }
1912 }
1913 Ok(old_func_ty)
1914 }
1915
1916 fn is_subtype_many(&mut self, ts1: &[ValType], ts2: &[ValType]) -> bool {
1919 debug_assert!(ts1.len() == ts2.len());
1920 ts1.iter()
1921 .zip(ts2.iter())
1922 .all(|(ty1, ty2)| self.resources.is_subtype(*ty1, *ty2))
1923 }
1924
1925 fn check_binop128(&mut self) -> Result<()> {
1926 self.pop_operand(Some(ValType::I64))?;
1927 self.pop_operand(Some(ValType::I64))?;
1928 self.pop_operand(Some(ValType::I64))?;
1929 self.pop_operand(Some(ValType::I64))?;
1930 self.push_operand(ValType::I64)?;
1931 self.push_operand(ValType::I64)?;
1932 Ok(())
1933 }
1934
1935 fn check_i64_mul_wide(&mut self) -> Result<()> {
1936 self.pop_operand(Some(ValType::I64))?;
1937 self.pop_operand(Some(ValType::I64))?;
1938 self.push_operand(ValType::I64)?;
1939 self.push_operand(ValType::I64)?;
1940 Ok(())
1941 }
1942
1943 fn check_enabled(&self, flag: bool, desc: &str) -> Result<()> {
1944 if flag {
1945 return Ok(());
1946 }
1947 bail!(self.offset, "{desc} support is not enabled");
1948 }
1949}
1950
1951pub fn ty_to_str(ty: ValType) -> &'static str {
1952 match ty {
1953 ValType::I32 => "i32",
1954 ValType::I64 => "i64",
1955 ValType::F32 => "f32",
1956 ValType::F64 => "f64",
1957 ValType::V128 => "v128",
1958 ValType::Ref(r) => r.wat(),
1959 }
1960}
1961
1962struct WasmProposalValidator<'validator, 'resources, T>(
1971 OperatorValidatorTemp<'validator, 'resources, T>,
1972);
1973
1974#[cfg_attr(not(feature = "simd"), allow(unused_macro_rules))]
1975macro_rules! validate_proposal {
1976 ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => {
1977 $(
1978 fn $visit(&mut self $($(,$arg: $argty)*)?) -> Result<()> {
1979 validate_proposal!(validate self $proposal / $op);
1980 self.0.$visit($( $($arg),* )?)
1981 }
1982 )*
1983 };
1984
1985 (validate self mvp / $op:ident) => {};
1986
1987 (validate self $proposal:ident / MemoryFill) => {};
1991 (validate self $proposal:ident / MemoryCopy) => {};
1992
1993 (validate $self:ident $proposal:ident / $op:ident) => {
1994 $self.0.check_enabled($self.0.features.$proposal(), validate_proposal!(desc $proposal))?
1995 };
1996
1997 (desc simd) => ("SIMD");
1998 (desc relaxed_simd) => ("relaxed SIMD");
1999 (desc threads) => ("threads");
2000 (desc shared_everything_threads) => ("shared-everything-threads");
2001 (desc saturating_float_to_int) => ("saturating float to int conversions");
2002 (desc reference_types) => ("reference types");
2003 (desc bulk_memory) => ("bulk memory");
2004 (desc sign_extension) => ("sign extension operations");
2005 (desc exceptions) => ("exceptions");
2006 (desc tail_call) => ("tail calls");
2007 (desc function_references) => ("function references");
2008 (desc memory_control) => ("memory control");
2009 (desc gc) => ("gc");
2010 (desc legacy_exceptions) => ("legacy exceptions");
2011 (desc stack_switching) => ("stack switching");
2012 (desc wide_arithmetic) => ("wide arithmetic");
2013 (desc custom_descriptors) => ("custom descriptors operations");
2014}
2015
2016impl<'a, T> VisitOperator<'a> for WasmProposalValidator<'_, '_, T>
2017where
2018 T: WasmModuleResources,
2019{
2020 type Output = Result<()>;
2021
2022 #[cfg(feature = "simd")]
2023 fn simd_visitor(&mut self) -> Option<&mut dyn VisitSimdOperator<'a, Output = Self::Output>> {
2024 Some(self)
2025 }
2026
2027 crate::for_each_visit_operator!(validate_proposal);
2028}
2029
2030#[cfg(feature = "simd")]
2031impl<'a, T> VisitSimdOperator<'a> for WasmProposalValidator<'_, '_, T>
2032where
2033 T: WasmModuleResources,
2034{
2035 crate::for_each_visit_simd_operator!(validate_proposal);
2036}
2037
2038#[track_caller]
2039#[inline]
2040fn debug_assert_type_indices_are_ids(ty: ValType) {
2041 if cfg!(debug_assertions) {
2042 if let ValType::Ref(r) = ty {
2043 if let HeapType::Concrete(idx) = r.heap_type() {
2044 debug_assert!(
2045 matches!(idx, UnpackedIndex::Id(_)),
2046 "type reference should be a `CoreTypeId`, found {idx:?}"
2047 );
2048 }
2049 }
2050 }
2051}
2052
2053impl<'a, T> VisitOperator<'a> for OperatorValidatorTemp<'_, '_, T>
2054where
2055 T: WasmModuleResources,
2056{
2057 type Output = Result<()>;
2058
2059 #[cfg(feature = "simd")]
2060 fn simd_visitor(&mut self) -> Option<&mut dyn VisitSimdOperator<'a, Output = Self::Output>> {
2061 Some(self)
2062 }
2063
2064 fn visit_nop(&mut self) -> Self::Output {
2065 Ok(())
2066 }
2067 fn visit_unreachable(&mut self) -> Self::Output {
2068 self.unreachable()?;
2069 Ok(())
2070 }
2071 fn visit_block(&mut self, mut ty: BlockType) -> Self::Output {
2072 self.check_block_type(&mut ty)?;
2073 for ty in self.params(ty)?.rev() {
2074 self.pop_operand(Some(ty))?;
2075 }
2076 self.push_ctrl(FrameKind::Block, ty)?;
2077 Ok(())
2078 }
2079 fn visit_loop(&mut self, mut ty: BlockType) -> Self::Output {
2080 self.check_block_type(&mut ty)?;
2081 for ty in self.params(ty)?.rev() {
2082 self.pop_operand(Some(ty))?;
2083 }
2084 self.push_ctrl(FrameKind::Loop, ty)?;
2085 Ok(())
2086 }
2087 fn visit_if(&mut self, mut ty: BlockType) -> Self::Output {
2088 self.check_block_type(&mut ty)?;
2089 self.pop_operand(Some(ValType::I32))?;
2090 for ty in self.params(ty)?.rev() {
2091 self.pop_operand(Some(ty))?;
2092 }
2093 self.push_ctrl(FrameKind::If, ty)?;
2094 Ok(())
2095 }
2096 fn visit_else(&mut self) -> Self::Output {
2097 let frame = self.pop_ctrl()?;
2098 debug_assert_eq!(frame.kind, FrameKind::If); self.push_ctrl(FrameKind::Else, frame.block_type)?;
2100 Ok(())
2101 }
2102 fn visit_try_table(&mut self, mut ty: TryTable) -> Self::Output {
2103 self.check_block_type(&mut ty.ty)?;
2104 for ty in self.params(ty.ty)?.rev() {
2105 self.pop_operand(Some(ty))?;
2106 }
2107 let exn_type = ValType::from(RefType::EXN);
2108 for catch in ty.catches {
2109 match catch {
2110 Catch::One { tag, label } => {
2111 let tag = self.exception_tag_at(tag)?;
2112 let (ty, kind) = self.jump(label)?;
2113 let params = tag.params();
2114 let types = self.label_types(ty, kind)?;
2115 if params.len() != types.len() {
2116 bail!(
2117 self.offset,
2118 "type mismatch: catch label must have same number of types as tag"
2119 );
2120 }
2121 for (expected, actual) in types.zip(params) {
2122 self.match_operand(*actual, expected)?;
2123 }
2124 }
2125 Catch::OneRef { tag, label } => {
2126 let tag = self.exception_tag_at(tag)?;
2127 let (ty, kind) = self.jump(label)?;
2128 let tag_params = tag.params().iter().copied();
2129 let label_types = self.label_types(ty, kind)?;
2130 if tag_params.len() + 1 != label_types.len() {
2131 bail!(
2132 self.offset,
2133 "type mismatch: catch_ref label must have one \
2134 more type than tag types",
2135 );
2136 }
2137 for (expected_label_type, actual_tag_param) in
2138 label_types.zip(tag_params.chain([exn_type]))
2139 {
2140 self.match_operand(actual_tag_param, expected_label_type)?;
2141 }
2142 }
2143
2144 Catch::All { label } => {
2145 let (ty, kind) = self.jump(label)?;
2146 if self.label_types(ty, kind)?.len() != 0 {
2147 bail!(
2148 self.offset,
2149 "type mismatch: catch_all label must have no result types"
2150 );
2151 }
2152 }
2153
2154 Catch::AllRef { label } => {
2155 let (ty, kind) = self.jump(label)?;
2156 let mut types = self.label_types(ty, kind)?;
2157 let ty = match (types.next(), types.next()) {
2158 (Some(ty), None) => ty,
2159 _ => {
2160 bail!(
2161 self.offset,
2162 "type mismatch: catch_all_ref label must have \
2163 exactly one result type"
2164 );
2165 }
2166 };
2167 if !self.resources.is_subtype(exn_type, ty) {
2168 bail!(
2169 self.offset,
2170 "type mismatch: catch_all_ref label must a \
2171 subtype of (ref exn)"
2172 );
2173 }
2174 }
2175 }
2176 }
2177 self.push_ctrl(FrameKind::TryTable, ty.ty)?;
2178 Ok(())
2179 }
2180 fn visit_throw(&mut self, index: u32) -> Self::Output {
2181 let ty = self.exception_tag_at(index)?;
2183 for ty in ty.clone().params().iter().rev() {
2184 self.pop_operand(Some(*ty))?;
2185 }
2186 debug_assert!(ty.results().is_empty());
2188 self.unreachable()?;
2189 Ok(())
2190 }
2191 fn visit_throw_ref(&mut self) -> Self::Output {
2192 self.pop_operand(Some(ValType::EXNREF))?;
2193 self.unreachable()?;
2194 Ok(())
2195 }
2196 fn visit_end(&mut self) -> Self::Output {
2197 let mut frame = self.pop_ctrl()?;
2198
2199 if frame.kind == FrameKind::If {
2206 self.push_ctrl(FrameKind::Else, frame.block_type)?;
2207 frame = self.pop_ctrl()?;
2208 }
2209 for ty in self.results(frame.block_type)? {
2210 self.push_operand(ty)?;
2211 }
2212 if self.control.is_empty() {
2213 assert_ne!(self.offset, 0);
2214 }
2215 Ok(())
2216 }
2217 fn visit_br(&mut self, relative_depth: u32) -> Self::Output {
2218 let (ty, kind) = self.jump(relative_depth)?;
2219 for ty in self.label_types(ty, kind)?.rev() {
2220 self.pop_operand(Some(ty))?;
2221 }
2222 self.unreachable()?;
2223 Ok(())
2224 }
2225 fn visit_br_if(&mut self, relative_depth: u32) -> Self::Output {
2226 self.pop_operand(Some(ValType::I32))?;
2227 let (ty, kind) = self.jump(relative_depth)?;
2228 let label_types = self.label_types(ty, kind)?;
2229 self.pop_push_label_types(label_types)?;
2230 Ok(())
2231 }
2232 fn visit_br_table(&mut self, table: BrTable) -> Self::Output {
2233 self.pop_operand(Some(ValType::I32))?;
2234 let default = self.jump(table.default())?;
2235 let default_types = self.label_types(default.0, default.1)?;
2236 for element in table.targets() {
2237 let relative_depth = element?;
2238 let block = self.jump(relative_depth)?;
2239 let label_tys = self.label_types(block.0, block.1)?;
2240 if label_tys.len() != default_types.len() {
2241 bail!(
2242 self.offset,
2243 "type mismatch: br_table target labels have different number of types"
2244 );
2245 }
2246 self.match_stack_operands(label_tys)?;
2247 }
2248 for ty in default_types.rev() {
2249 self.pop_operand(Some(ty))?;
2250 }
2251 self.unreachable()?;
2252 Ok(())
2253 }
2254 fn visit_return(&mut self) -> Self::Output {
2255 self.check_return()?;
2256 Ok(())
2257 }
2258 fn visit_call(&mut self, function_index: u32) -> Self::Output {
2259 let ty = self.type_of_function(function_index)?;
2260 self.check_call_ty(ty)?;
2261 Ok(())
2262 }
2263 fn visit_return_call(&mut self, function_index: u32) -> Self::Output {
2264 let ty = self.type_of_function(function_index)?;
2265 self.check_return_call_ty(ty)?;
2266 Ok(())
2267 }
2268 fn visit_call_ref(&mut self, type_index: u32) -> Self::Output {
2269 let ty = self.check_call_ref_ty(type_index)?;
2270 self.check_call_ty(ty)?;
2271 Ok(())
2272 }
2273 fn visit_return_call_ref(&mut self, type_index: u32) -> Self::Output {
2274 let ty = self.check_call_ref_ty(type_index)?;
2275 self.check_return_call_ty(ty)?;
2276 Ok(())
2277 }
2278 fn visit_call_indirect(&mut self, type_index: u32, table_index: u32) -> Self::Output {
2279 let ty = self.check_call_indirect_ty(type_index, table_index)?;
2280 self.check_call_ty(ty)?;
2281 Ok(())
2282 }
2283 fn visit_return_call_indirect(&mut self, type_index: u32, table_index: u32) -> Self::Output {
2284 let ty = self.check_call_indirect_ty(type_index, table_index)?;
2285 self.check_return_call_ty(ty)?;
2286 Ok(())
2287 }
2288 fn visit_drop(&mut self) -> Self::Output {
2289 self.pop_operand(None)?;
2290 Ok(())
2291 }
2292 fn visit_select(&mut self) -> Self::Output {
2293 self.pop_operand(Some(ValType::I32))?;
2294 let ty1 = self.pop_operand(None)?;
2295 let ty2 = self.pop_operand(None)?;
2296
2297 let ty = match (ty1, ty2) {
2298 (MaybeType::UnknownRef(..), _)
2301 | (_, MaybeType::UnknownRef(..))
2302 | (MaybeType::Known(ValType::Ref(_)), _)
2303 | (_, MaybeType::Known(ValType::Ref(_))) => {
2304 bail!(
2305 self.offset,
2306 "type mismatch: select only takes integral types"
2307 )
2308 }
2309
2310 (MaybeType::Bottom, t) | (t, MaybeType::Bottom) => t,
2313
2314 (t @ MaybeType::Known(t1), MaybeType::Known(t2)) => {
2317 if t1 != t2 {
2318 bail!(
2319 self.offset,
2320 "type mismatch: select operands have different types"
2321 );
2322 }
2323 t
2324 }
2325 };
2326 self.push_operand(ty)?;
2327 Ok(())
2328 }
2329 fn visit_typed_select(&mut self, mut ty: ValType) -> Self::Output {
2330 self.resources
2331 .check_value_type(&mut ty, &self.features, self.offset)?;
2332 self.pop_operand(Some(ValType::I32))?;
2333 self.pop_operand(Some(ty))?;
2334 self.pop_operand(Some(ty))?;
2335 self.push_operand(ty)?;
2336 Ok(())
2337 }
2338 fn visit_typed_select_multi(&mut self, tys: Vec<ValType>) -> Self::Output {
2339 debug_assert!(tys.len() != 1);
2340 bail!(self.offset, "invalid result arity");
2341 }
2342 fn visit_local_get(&mut self, local_index: u32) -> Self::Output {
2343 let ty = self.local(local_index)?;
2344 debug_assert_type_indices_are_ids(ty);
2345 if self.local_inits.is_uninit(local_index) {
2346 bail!(self.offset, "uninitialized local: {}", local_index);
2347 }
2348 self.push_operand(ty)?;
2349 Ok(())
2350 }
2351 fn visit_local_set(&mut self, local_index: u32) -> Self::Output {
2352 let ty = self.local(local_index)?;
2353 self.pop_operand(Some(ty))?;
2354 self.local_inits.set_init(local_index);
2355 Ok(())
2356 }
2357 fn visit_local_tee(&mut self, local_index: u32) -> Self::Output {
2358 let expected_ty = self.local(local_index)?;
2359 self.pop_operand(Some(expected_ty))?;
2360 self.local_inits.set_init(local_index);
2361 self.push_operand(expected_ty)?;
2362 Ok(())
2363 }
2364 fn visit_global_get(&mut self, global_index: u32) -> Self::Output {
2365 let ty = self.global_type_at(global_index)?.content_type;
2366 debug_assert_type_indices_are_ids(ty);
2367 self.push_operand(ty)?;
2368 Ok(())
2369 }
2370 fn visit_global_atomic_get(&mut self, _ordering: Ordering, global_index: u32) -> Self::Output {
2371 self.visit_global_get(global_index)?;
2372 let ty = self.global_type_at(global_index)?.content_type;
2376 let supertype = RefType::ANYREF.into();
2377 if !(ty == ValType::I32 || ty == ValType::I64 || self.resources.is_subtype(ty, supertype)) {
2378 bail!(
2379 self.offset,
2380 "invalid type: `global.atomic.get` only allows `i32`, `i64` and subtypes of `anyref`"
2381 );
2382 }
2383 Ok(())
2384 }
2385 fn visit_global_set(&mut self, global_index: u32) -> Self::Output {
2386 let ty = self.global_type_at(global_index)?;
2387 if !ty.mutable {
2388 bail!(
2389 self.offset,
2390 "global is immutable: cannot modify it with `global.set`"
2391 );
2392 }
2393 self.pop_operand(Some(ty.content_type))?;
2394 Ok(())
2395 }
2396 fn visit_global_atomic_set(&mut self, _ordering: Ordering, global_index: u32) -> Self::Output {
2397 self.visit_global_set(global_index)?;
2398 let ty = self.global_type_at(global_index)?.content_type;
2401 let supertype = RefType::ANYREF.into();
2402 if !(ty == ValType::I32 || ty == ValType::I64 || self.resources.is_subtype(ty, supertype)) {
2403 bail!(
2404 self.offset,
2405 "invalid type: `global.atomic.set` only allows `i32`, `i64` and subtypes of `anyref`"
2406 );
2407 }
2408 Ok(())
2409 }
2410 fn visit_global_atomic_rmw_add(
2411 &mut self,
2412 _ordering: crate::Ordering,
2413 global_index: u32,
2414 ) -> Self::Output {
2415 let ty = self.check_atomic_global_rmw_ty(global_index)?;
2416 self.check_unary_op(ty)
2417 }
2418 fn visit_global_atomic_rmw_sub(
2419 &mut self,
2420 _ordering: crate::Ordering,
2421 global_index: u32,
2422 ) -> Self::Output {
2423 let ty = self.check_atomic_global_rmw_ty(global_index)?;
2424 self.check_unary_op(ty)
2425 }
2426 fn visit_global_atomic_rmw_and(
2427 &mut self,
2428 _ordering: crate::Ordering,
2429 global_index: u32,
2430 ) -> Self::Output {
2431 let ty = self.check_atomic_global_rmw_ty(global_index)?;
2432 self.check_unary_op(ty)
2433 }
2434 fn visit_global_atomic_rmw_or(
2435 &mut self,
2436 _ordering: crate::Ordering,
2437 global_index: u32,
2438 ) -> Self::Output {
2439 let ty = self.check_atomic_global_rmw_ty(global_index)?;
2440 self.check_unary_op(ty)
2441 }
2442 fn visit_global_atomic_rmw_xor(
2443 &mut self,
2444 _ordering: crate::Ordering,
2445 global_index: u32,
2446 ) -> Self::Output {
2447 let ty = self.check_atomic_global_rmw_ty(global_index)?;
2448 self.check_unary_op(ty)
2449 }
2450 fn visit_global_atomic_rmw_xchg(
2451 &mut self,
2452 _ordering: crate::Ordering,
2453 global_index: u32,
2454 ) -> Self::Output {
2455 let ty = self.global_type_at(global_index)?.content_type;
2456 if !(ty == ValType::I32
2457 || ty == ValType::I64
2458 || self.resources.is_subtype(ty, RefType::ANYREF.into()))
2459 {
2460 bail!(
2461 self.offset,
2462 "invalid type: `global.atomic.rmw.xchg` only allows `i32`, `i64` and subtypes of `anyref`"
2463 );
2464 }
2465 self.check_unary_op(ty)
2466 }
2467 fn visit_global_atomic_rmw_cmpxchg(
2468 &mut self,
2469 _ordering: crate::Ordering,
2470 global_index: u32,
2471 ) -> Self::Output {
2472 let ty = self.global_type_at(global_index)?.content_type;
2473 if !(ty == ValType::I32
2474 || ty == ValType::I64
2475 || self.resources.is_subtype(ty, RefType::EQREF.into()))
2476 {
2477 bail!(
2478 self.offset,
2479 "invalid type: `global.atomic.rmw.cmpxchg` only allows `i32`, `i64` and subtypes of `eqref`"
2480 );
2481 }
2482 self.check_binary_op(ty)
2483 }
2484
2485 fn visit_i32_load(&mut self, memarg: MemArg) -> Self::Output {
2486 let ty = self.check_memarg(memarg)?;
2487 self.pop_operand(Some(ty))?;
2488 self.push_operand(ValType::I32)?;
2489 Ok(())
2490 }
2491 fn visit_i64_load(&mut self, memarg: MemArg) -> Self::Output {
2492 let ty = self.check_memarg(memarg)?;
2493 self.pop_operand(Some(ty))?;
2494 self.push_operand(ValType::I64)?;
2495 Ok(())
2496 }
2497 fn visit_f32_load(&mut self, memarg: MemArg) -> Self::Output {
2498 self.check_floats_enabled()?;
2499 let ty = self.check_memarg(memarg)?;
2500 self.pop_operand(Some(ty))?;
2501 self.push_operand(ValType::F32)?;
2502 Ok(())
2503 }
2504 fn visit_f64_load(&mut self, memarg: MemArg) -> Self::Output {
2505 self.check_floats_enabled()?;
2506 let ty = self.check_memarg(memarg)?;
2507 self.pop_operand(Some(ty))?;
2508 self.push_operand(ValType::F64)?;
2509 Ok(())
2510 }
2511 fn visit_i32_load8_s(&mut self, memarg: MemArg) -> Self::Output {
2512 let ty = self.check_memarg(memarg)?;
2513 self.pop_operand(Some(ty))?;
2514 self.push_operand(ValType::I32)?;
2515 Ok(())
2516 }
2517 fn visit_i32_load8_u(&mut self, memarg: MemArg) -> Self::Output {
2518 self.visit_i32_load8_s(memarg)
2519 }
2520 fn visit_i32_load16_s(&mut self, memarg: MemArg) -> Self::Output {
2521 let ty = self.check_memarg(memarg)?;
2522 self.pop_operand(Some(ty))?;
2523 self.push_operand(ValType::I32)?;
2524 Ok(())
2525 }
2526 fn visit_i32_load16_u(&mut self, memarg: MemArg) -> Self::Output {
2527 self.visit_i32_load16_s(memarg)
2528 }
2529 fn visit_i64_load8_s(&mut self, memarg: MemArg) -> Self::Output {
2530 let ty = self.check_memarg(memarg)?;
2531 self.pop_operand(Some(ty))?;
2532 self.push_operand(ValType::I64)?;
2533 Ok(())
2534 }
2535 fn visit_i64_load8_u(&mut self, memarg: MemArg) -> Self::Output {
2536 self.visit_i64_load8_s(memarg)
2537 }
2538 fn visit_i64_load16_s(&mut self, memarg: MemArg) -> Self::Output {
2539 let ty = self.check_memarg(memarg)?;
2540 self.pop_operand(Some(ty))?;
2541 self.push_operand(ValType::I64)?;
2542 Ok(())
2543 }
2544 fn visit_i64_load16_u(&mut self, memarg: MemArg) -> Self::Output {
2545 self.visit_i64_load16_s(memarg)
2546 }
2547 fn visit_i64_load32_s(&mut self, memarg: MemArg) -> Self::Output {
2548 let ty = self.check_memarg(memarg)?;
2549 self.pop_operand(Some(ty))?;
2550 self.push_operand(ValType::I64)?;
2551 Ok(())
2552 }
2553 fn visit_i64_load32_u(&mut self, memarg: MemArg) -> Self::Output {
2554 self.visit_i64_load32_s(memarg)
2555 }
2556 fn visit_i32_store(&mut self, memarg: MemArg) -> Self::Output {
2557 let ty = self.check_memarg(memarg)?;
2558 self.pop_operand(Some(ValType::I32))?;
2559 self.pop_operand(Some(ty))?;
2560 Ok(())
2561 }
2562 fn visit_i64_store(&mut self, memarg: MemArg) -> Self::Output {
2563 let ty = self.check_memarg(memarg)?;
2564 self.pop_operand(Some(ValType::I64))?;
2565 self.pop_operand(Some(ty))?;
2566 Ok(())
2567 }
2568 fn visit_f32_store(&mut self, memarg: MemArg) -> Self::Output {
2569 self.check_floats_enabled()?;
2570 let ty = self.check_memarg(memarg)?;
2571 self.pop_operand(Some(ValType::F32))?;
2572 self.pop_operand(Some(ty))?;
2573 Ok(())
2574 }
2575 fn visit_f64_store(&mut self, memarg: MemArg) -> Self::Output {
2576 self.check_floats_enabled()?;
2577 let ty = self.check_memarg(memarg)?;
2578 self.pop_operand(Some(ValType::F64))?;
2579 self.pop_operand(Some(ty))?;
2580 Ok(())
2581 }
2582 fn visit_i32_store8(&mut self, memarg: MemArg) -> Self::Output {
2583 let ty = self.check_memarg(memarg)?;
2584 self.pop_operand(Some(ValType::I32))?;
2585 self.pop_operand(Some(ty))?;
2586 Ok(())
2587 }
2588 fn visit_i32_store16(&mut self, memarg: MemArg) -> Self::Output {
2589 let ty = self.check_memarg(memarg)?;
2590 self.pop_operand(Some(ValType::I32))?;
2591 self.pop_operand(Some(ty))?;
2592 Ok(())
2593 }
2594 fn visit_i64_store8(&mut self, memarg: MemArg) -> Self::Output {
2595 let ty = self.check_memarg(memarg)?;
2596 self.pop_operand(Some(ValType::I64))?;
2597 self.pop_operand(Some(ty))?;
2598 Ok(())
2599 }
2600 fn visit_i64_store16(&mut self, memarg: MemArg) -> Self::Output {
2601 let ty = self.check_memarg(memarg)?;
2602 self.pop_operand(Some(ValType::I64))?;
2603 self.pop_operand(Some(ty))?;
2604 Ok(())
2605 }
2606 fn visit_i64_store32(&mut self, memarg: MemArg) -> Self::Output {
2607 let ty = self.check_memarg(memarg)?;
2608 self.pop_operand(Some(ValType::I64))?;
2609 self.pop_operand(Some(ty))?;
2610 Ok(())
2611 }
2612 fn visit_memory_size(&mut self, mem: u32) -> Self::Output {
2613 let index_ty = self.check_memory_index(mem)?;
2614 self.push_operand(index_ty)?;
2615 Ok(())
2616 }
2617 fn visit_memory_grow(&mut self, mem: u32) -> Self::Output {
2618 let index_ty = self.check_memory_index(mem)?;
2619 self.pop_operand(Some(index_ty))?;
2620 self.push_operand(index_ty)?;
2621 Ok(())
2622 }
2623 fn visit_i32_const(&mut self, _value: i32) -> Self::Output {
2624 self.push_operand(ValType::I32)?;
2625 Ok(())
2626 }
2627 fn visit_i64_const(&mut self, _value: i64) -> Self::Output {
2628 self.push_operand(ValType::I64)?;
2629 Ok(())
2630 }
2631 fn visit_f32_const(&mut self, _value: Ieee32) -> Self::Output {
2632 self.check_floats_enabled()?;
2633 self.push_operand(ValType::F32)?;
2634 Ok(())
2635 }
2636 fn visit_f64_const(&mut self, _value: Ieee64) -> Self::Output {
2637 self.check_floats_enabled()?;
2638 self.push_operand(ValType::F64)?;
2639 Ok(())
2640 }
2641 fn visit_i32_eqz(&mut self) -> Self::Output {
2642 self.pop_operand(Some(ValType::I32))?;
2643 self.push_operand(ValType::I32)?;
2644 Ok(())
2645 }
2646 fn visit_i32_eq(&mut self) -> Self::Output {
2647 self.check_cmp_op(ValType::I32)
2648 }
2649 fn visit_i32_ne(&mut self) -> Self::Output {
2650 self.check_cmp_op(ValType::I32)
2651 }
2652 fn visit_i32_lt_s(&mut self) -> Self::Output {
2653 self.check_cmp_op(ValType::I32)
2654 }
2655 fn visit_i32_lt_u(&mut self) -> Self::Output {
2656 self.check_cmp_op(ValType::I32)
2657 }
2658 fn visit_i32_gt_s(&mut self) -> Self::Output {
2659 self.check_cmp_op(ValType::I32)
2660 }
2661 fn visit_i32_gt_u(&mut self) -> Self::Output {
2662 self.check_cmp_op(ValType::I32)
2663 }
2664 fn visit_i32_le_s(&mut self) -> Self::Output {
2665 self.check_cmp_op(ValType::I32)
2666 }
2667 fn visit_i32_le_u(&mut self) -> Self::Output {
2668 self.check_cmp_op(ValType::I32)
2669 }
2670 fn visit_i32_ge_s(&mut self) -> Self::Output {
2671 self.check_cmp_op(ValType::I32)
2672 }
2673 fn visit_i32_ge_u(&mut self) -> Self::Output {
2674 self.check_cmp_op(ValType::I32)
2675 }
2676 fn visit_i64_eqz(&mut self) -> Self::Output {
2677 self.pop_operand(Some(ValType::I64))?;
2678 self.push_operand(ValType::I32)?;
2679 Ok(())
2680 }
2681 fn visit_i64_eq(&mut self) -> Self::Output {
2682 self.check_cmp_op(ValType::I64)
2683 }
2684 fn visit_i64_ne(&mut self) -> Self::Output {
2685 self.check_cmp_op(ValType::I64)
2686 }
2687 fn visit_i64_lt_s(&mut self) -> Self::Output {
2688 self.check_cmp_op(ValType::I64)
2689 }
2690 fn visit_i64_lt_u(&mut self) -> Self::Output {
2691 self.check_cmp_op(ValType::I64)
2692 }
2693 fn visit_i64_gt_s(&mut self) -> Self::Output {
2694 self.check_cmp_op(ValType::I64)
2695 }
2696 fn visit_i64_gt_u(&mut self) -> Self::Output {
2697 self.check_cmp_op(ValType::I64)
2698 }
2699 fn visit_i64_le_s(&mut self) -> Self::Output {
2700 self.check_cmp_op(ValType::I64)
2701 }
2702 fn visit_i64_le_u(&mut self) -> Self::Output {
2703 self.check_cmp_op(ValType::I64)
2704 }
2705 fn visit_i64_ge_s(&mut self) -> Self::Output {
2706 self.check_cmp_op(ValType::I64)
2707 }
2708 fn visit_i64_ge_u(&mut self) -> Self::Output {
2709 self.check_cmp_op(ValType::I64)
2710 }
2711 fn visit_f32_eq(&mut self) -> Self::Output {
2712 self.check_fcmp_op(ValType::F32)
2713 }
2714 fn visit_f32_ne(&mut self) -> Self::Output {
2715 self.check_fcmp_op(ValType::F32)
2716 }
2717 fn visit_f32_lt(&mut self) -> Self::Output {
2718 self.check_fcmp_op(ValType::F32)
2719 }
2720 fn visit_f32_gt(&mut self) -> Self::Output {
2721 self.check_fcmp_op(ValType::F32)
2722 }
2723 fn visit_f32_le(&mut self) -> Self::Output {
2724 self.check_fcmp_op(ValType::F32)
2725 }
2726 fn visit_f32_ge(&mut self) -> Self::Output {
2727 self.check_fcmp_op(ValType::F32)
2728 }
2729 fn visit_f64_eq(&mut self) -> Self::Output {
2730 self.check_fcmp_op(ValType::F64)
2731 }
2732 fn visit_f64_ne(&mut self) -> Self::Output {
2733 self.check_fcmp_op(ValType::F64)
2734 }
2735 fn visit_f64_lt(&mut self) -> Self::Output {
2736 self.check_fcmp_op(ValType::F64)
2737 }
2738 fn visit_f64_gt(&mut self) -> Self::Output {
2739 self.check_fcmp_op(ValType::F64)
2740 }
2741 fn visit_f64_le(&mut self) -> Self::Output {
2742 self.check_fcmp_op(ValType::F64)
2743 }
2744 fn visit_f64_ge(&mut self) -> Self::Output {
2745 self.check_fcmp_op(ValType::F64)
2746 }
2747 fn visit_i32_clz(&mut self) -> Self::Output {
2748 self.check_unary_op(ValType::I32)
2749 }
2750 fn visit_i32_ctz(&mut self) -> Self::Output {
2751 self.check_unary_op(ValType::I32)
2752 }
2753 fn visit_i32_popcnt(&mut self) -> Self::Output {
2754 self.check_unary_op(ValType::I32)
2755 }
2756 fn visit_i32_add(&mut self) -> Self::Output {
2757 self.check_binary_op(ValType::I32)
2758 }
2759 fn visit_i32_sub(&mut self) -> Self::Output {
2760 self.check_binary_op(ValType::I32)
2761 }
2762 fn visit_i32_mul(&mut self) -> Self::Output {
2763 self.check_binary_op(ValType::I32)
2764 }
2765 fn visit_i32_div_s(&mut self) -> Self::Output {
2766 self.check_binary_op(ValType::I32)
2767 }
2768 fn visit_i32_div_u(&mut self) -> Self::Output {
2769 self.check_binary_op(ValType::I32)
2770 }
2771 fn visit_i32_rem_s(&mut self) -> Self::Output {
2772 self.check_binary_op(ValType::I32)
2773 }
2774 fn visit_i32_rem_u(&mut self) -> Self::Output {
2775 self.check_binary_op(ValType::I32)
2776 }
2777 fn visit_i32_and(&mut self) -> Self::Output {
2778 self.check_binary_op(ValType::I32)
2779 }
2780 fn visit_i32_or(&mut self) -> Self::Output {
2781 self.check_binary_op(ValType::I32)
2782 }
2783 fn visit_i32_xor(&mut self) -> Self::Output {
2784 self.check_binary_op(ValType::I32)
2785 }
2786 fn visit_i32_shl(&mut self) -> Self::Output {
2787 self.check_binary_op(ValType::I32)
2788 }
2789 fn visit_i32_shr_s(&mut self) -> Self::Output {
2790 self.check_binary_op(ValType::I32)
2791 }
2792 fn visit_i32_shr_u(&mut self) -> Self::Output {
2793 self.check_binary_op(ValType::I32)
2794 }
2795 fn visit_i32_rotl(&mut self) -> Self::Output {
2796 self.check_binary_op(ValType::I32)
2797 }
2798 fn visit_i32_rotr(&mut self) -> Self::Output {
2799 self.check_binary_op(ValType::I32)
2800 }
2801 fn visit_i64_clz(&mut self) -> Self::Output {
2802 self.check_unary_op(ValType::I64)
2803 }
2804 fn visit_i64_ctz(&mut self) -> Self::Output {
2805 self.check_unary_op(ValType::I64)
2806 }
2807 fn visit_i64_popcnt(&mut self) -> Self::Output {
2808 self.check_unary_op(ValType::I64)
2809 }
2810 fn visit_i64_add(&mut self) -> Self::Output {
2811 self.check_binary_op(ValType::I64)
2812 }
2813 fn visit_i64_sub(&mut self) -> Self::Output {
2814 self.check_binary_op(ValType::I64)
2815 }
2816 fn visit_i64_mul(&mut self) -> Self::Output {
2817 self.check_binary_op(ValType::I64)
2818 }
2819 fn visit_i64_div_s(&mut self) -> Self::Output {
2820 self.check_binary_op(ValType::I64)
2821 }
2822 fn visit_i64_div_u(&mut self) -> Self::Output {
2823 self.check_binary_op(ValType::I64)
2824 }
2825 fn visit_i64_rem_s(&mut self) -> Self::Output {
2826 self.check_binary_op(ValType::I64)
2827 }
2828 fn visit_i64_rem_u(&mut self) -> Self::Output {
2829 self.check_binary_op(ValType::I64)
2830 }
2831 fn visit_i64_and(&mut self) -> Self::Output {
2832 self.check_binary_op(ValType::I64)
2833 }
2834 fn visit_i64_or(&mut self) -> Self::Output {
2835 self.check_binary_op(ValType::I64)
2836 }
2837 fn visit_i64_xor(&mut self) -> Self::Output {
2838 self.check_binary_op(ValType::I64)
2839 }
2840 fn visit_i64_shl(&mut self) -> Self::Output {
2841 self.check_binary_op(ValType::I64)
2842 }
2843 fn visit_i64_shr_s(&mut self) -> Self::Output {
2844 self.check_binary_op(ValType::I64)
2845 }
2846 fn visit_i64_shr_u(&mut self) -> Self::Output {
2847 self.check_binary_op(ValType::I64)
2848 }
2849 fn visit_i64_rotl(&mut self) -> Self::Output {
2850 self.check_binary_op(ValType::I64)
2851 }
2852 fn visit_i64_rotr(&mut self) -> Self::Output {
2853 self.check_binary_op(ValType::I64)
2854 }
2855 fn visit_f32_abs(&mut self) -> Self::Output {
2856 self.check_funary_op(ValType::F32)
2857 }
2858 fn visit_f32_neg(&mut self) -> Self::Output {
2859 self.check_funary_op(ValType::F32)
2860 }
2861 fn visit_f32_ceil(&mut self) -> Self::Output {
2862 self.check_funary_op(ValType::F32)
2863 }
2864 fn visit_f32_floor(&mut self) -> Self::Output {
2865 self.check_funary_op(ValType::F32)
2866 }
2867 fn visit_f32_trunc(&mut self) -> Self::Output {
2868 self.check_funary_op(ValType::F32)
2869 }
2870 fn visit_f32_nearest(&mut self) -> Self::Output {
2871 self.check_funary_op(ValType::F32)
2872 }
2873 fn visit_f32_sqrt(&mut self) -> Self::Output {
2874 self.check_funary_op(ValType::F32)
2875 }
2876 fn visit_f32_add(&mut self) -> Self::Output {
2877 self.check_fbinary_op(ValType::F32)
2878 }
2879 fn visit_f32_sub(&mut self) -> Self::Output {
2880 self.check_fbinary_op(ValType::F32)
2881 }
2882 fn visit_f32_mul(&mut self) -> Self::Output {
2883 self.check_fbinary_op(ValType::F32)
2884 }
2885 fn visit_f32_div(&mut self) -> Self::Output {
2886 self.check_fbinary_op(ValType::F32)
2887 }
2888 fn visit_f32_min(&mut self) -> Self::Output {
2889 self.check_fbinary_op(ValType::F32)
2890 }
2891 fn visit_f32_max(&mut self) -> Self::Output {
2892 self.check_fbinary_op(ValType::F32)
2893 }
2894 fn visit_f32_copysign(&mut self) -> Self::Output {
2895 self.check_fbinary_op(ValType::F32)
2896 }
2897 fn visit_f64_abs(&mut self) -> Self::Output {
2898 self.check_funary_op(ValType::F64)
2899 }
2900 fn visit_f64_neg(&mut self) -> Self::Output {
2901 self.check_funary_op(ValType::F64)
2902 }
2903 fn visit_f64_ceil(&mut self) -> Self::Output {
2904 self.check_funary_op(ValType::F64)
2905 }
2906 fn visit_f64_floor(&mut self) -> Self::Output {
2907 self.check_funary_op(ValType::F64)
2908 }
2909 fn visit_f64_trunc(&mut self) -> Self::Output {
2910 self.check_funary_op(ValType::F64)
2911 }
2912 fn visit_f64_nearest(&mut self) -> Self::Output {
2913 self.check_funary_op(ValType::F64)
2914 }
2915 fn visit_f64_sqrt(&mut self) -> Self::Output {
2916 self.check_funary_op(ValType::F64)
2917 }
2918 fn visit_f64_add(&mut self) -> Self::Output {
2919 self.check_fbinary_op(ValType::F64)
2920 }
2921 fn visit_f64_sub(&mut self) -> Self::Output {
2922 self.check_fbinary_op(ValType::F64)
2923 }
2924 fn visit_f64_mul(&mut self) -> Self::Output {
2925 self.check_fbinary_op(ValType::F64)
2926 }
2927 fn visit_f64_div(&mut self) -> Self::Output {
2928 self.check_fbinary_op(ValType::F64)
2929 }
2930 fn visit_f64_min(&mut self) -> Self::Output {
2931 self.check_fbinary_op(ValType::F64)
2932 }
2933 fn visit_f64_max(&mut self) -> Self::Output {
2934 self.check_fbinary_op(ValType::F64)
2935 }
2936 fn visit_f64_copysign(&mut self) -> Self::Output {
2937 self.check_fbinary_op(ValType::F64)
2938 }
2939 fn visit_i32_wrap_i64(&mut self) -> Self::Output {
2940 self.check_conversion_op(ValType::I32, ValType::I64)
2941 }
2942 fn visit_i32_trunc_f32_s(&mut self) -> Self::Output {
2943 self.check_conversion_op(ValType::I32, ValType::F32)
2944 }
2945 fn visit_i32_trunc_f32_u(&mut self) -> Self::Output {
2946 self.check_conversion_op(ValType::I32, ValType::F32)
2947 }
2948 fn visit_i32_trunc_f64_s(&mut self) -> Self::Output {
2949 self.check_conversion_op(ValType::I32, ValType::F64)
2950 }
2951 fn visit_i32_trunc_f64_u(&mut self) -> Self::Output {
2952 self.check_conversion_op(ValType::I32, ValType::F64)
2953 }
2954 fn visit_i64_extend_i32_s(&mut self) -> Self::Output {
2955 self.check_conversion_op(ValType::I64, ValType::I32)
2956 }
2957 fn visit_i64_extend_i32_u(&mut self) -> Self::Output {
2958 self.check_conversion_op(ValType::I64, ValType::I32)
2959 }
2960 fn visit_i64_trunc_f32_s(&mut self) -> Self::Output {
2961 self.check_conversion_op(ValType::I64, ValType::F32)
2962 }
2963 fn visit_i64_trunc_f32_u(&mut self) -> Self::Output {
2964 self.check_conversion_op(ValType::I64, ValType::F32)
2965 }
2966 fn visit_i64_trunc_f64_s(&mut self) -> Self::Output {
2967 self.check_conversion_op(ValType::I64, ValType::F64)
2968 }
2969 fn visit_i64_trunc_f64_u(&mut self) -> Self::Output {
2970 self.check_conversion_op(ValType::I64, ValType::F64)
2971 }
2972 fn visit_f32_convert_i32_s(&mut self) -> Self::Output {
2973 self.check_fconversion_op(ValType::F32, ValType::I32)
2974 }
2975 fn visit_f32_convert_i32_u(&mut self) -> Self::Output {
2976 self.check_fconversion_op(ValType::F32, ValType::I32)
2977 }
2978 fn visit_f32_convert_i64_s(&mut self) -> Self::Output {
2979 self.check_fconversion_op(ValType::F32, ValType::I64)
2980 }
2981 fn visit_f32_convert_i64_u(&mut self) -> Self::Output {
2982 self.check_fconversion_op(ValType::F32, ValType::I64)
2983 }
2984 fn visit_f32_demote_f64(&mut self) -> Self::Output {
2985 self.check_fconversion_op(ValType::F32, ValType::F64)
2986 }
2987 fn visit_f64_convert_i32_s(&mut self) -> Self::Output {
2988 self.check_fconversion_op(ValType::F64, ValType::I32)
2989 }
2990 fn visit_f64_convert_i32_u(&mut self) -> Self::Output {
2991 self.check_fconversion_op(ValType::F64, ValType::I32)
2992 }
2993 fn visit_f64_convert_i64_s(&mut self) -> Self::Output {
2994 self.check_fconversion_op(ValType::F64, ValType::I64)
2995 }
2996 fn visit_f64_convert_i64_u(&mut self) -> Self::Output {
2997 self.check_fconversion_op(ValType::F64, ValType::I64)
2998 }
2999 fn visit_f64_promote_f32(&mut self) -> Self::Output {
3000 self.check_fconversion_op(ValType::F64, ValType::F32)
3001 }
3002 fn visit_i32_reinterpret_f32(&mut self) -> Self::Output {
3003 self.check_conversion_op(ValType::I32, ValType::F32)
3004 }
3005 fn visit_i64_reinterpret_f64(&mut self) -> Self::Output {
3006 self.check_conversion_op(ValType::I64, ValType::F64)
3007 }
3008 fn visit_f32_reinterpret_i32(&mut self) -> Self::Output {
3009 self.check_fconversion_op(ValType::F32, ValType::I32)
3010 }
3011 fn visit_f64_reinterpret_i64(&mut self) -> Self::Output {
3012 self.check_fconversion_op(ValType::F64, ValType::I64)
3013 }
3014 fn visit_i32_trunc_sat_f32_s(&mut self) -> Self::Output {
3015 self.check_conversion_op(ValType::I32, ValType::F32)
3016 }
3017 fn visit_i32_trunc_sat_f32_u(&mut self) -> Self::Output {
3018 self.check_conversion_op(ValType::I32, ValType::F32)
3019 }
3020 fn visit_i32_trunc_sat_f64_s(&mut self) -> Self::Output {
3021 self.check_conversion_op(ValType::I32, ValType::F64)
3022 }
3023 fn visit_i32_trunc_sat_f64_u(&mut self) -> Self::Output {
3024 self.check_conversion_op(ValType::I32, ValType::F64)
3025 }
3026 fn visit_i64_trunc_sat_f32_s(&mut self) -> Self::Output {
3027 self.check_conversion_op(ValType::I64, ValType::F32)
3028 }
3029 fn visit_i64_trunc_sat_f32_u(&mut self) -> Self::Output {
3030 self.check_conversion_op(ValType::I64, ValType::F32)
3031 }
3032 fn visit_i64_trunc_sat_f64_s(&mut self) -> Self::Output {
3033 self.check_conversion_op(ValType::I64, ValType::F64)
3034 }
3035 fn visit_i64_trunc_sat_f64_u(&mut self) -> Self::Output {
3036 self.check_conversion_op(ValType::I64, ValType::F64)
3037 }
3038 fn visit_i32_extend8_s(&mut self) -> Self::Output {
3039 self.check_unary_op(ValType::I32)
3040 }
3041 fn visit_i32_extend16_s(&mut self) -> Self::Output {
3042 self.check_unary_op(ValType::I32)
3043 }
3044 fn visit_i64_extend8_s(&mut self) -> Self::Output {
3045 self.check_unary_op(ValType::I64)
3046 }
3047 fn visit_i64_extend16_s(&mut self) -> Self::Output {
3048 self.check_unary_op(ValType::I64)
3049 }
3050 fn visit_i64_extend32_s(&mut self) -> Self::Output {
3051 self.check_unary_op(ValType::I64)
3052 }
3053 fn visit_i32_atomic_load(&mut self, memarg: MemArg) -> Self::Output {
3054 self.check_atomic_load(memarg, ValType::I32)
3055 }
3056 fn visit_i32_atomic_load16_u(&mut self, memarg: MemArg) -> Self::Output {
3057 self.check_atomic_load(memarg, ValType::I32)
3058 }
3059 fn visit_i32_atomic_load8_u(&mut self, memarg: MemArg) -> Self::Output {
3060 self.check_atomic_load(memarg, ValType::I32)
3061 }
3062 fn visit_i64_atomic_load(&mut self, memarg: MemArg) -> Self::Output {
3063 self.check_atomic_load(memarg, ValType::I64)
3064 }
3065 fn visit_i64_atomic_load32_u(&mut self, memarg: MemArg) -> Self::Output {
3066 self.check_atomic_load(memarg, ValType::I64)
3067 }
3068 fn visit_i64_atomic_load16_u(&mut self, memarg: MemArg) -> Self::Output {
3069 self.check_atomic_load(memarg, ValType::I64)
3070 }
3071 fn visit_i64_atomic_load8_u(&mut self, memarg: MemArg) -> Self::Output {
3072 self.check_atomic_load(memarg, ValType::I64)
3073 }
3074 fn visit_i32_atomic_store(&mut self, memarg: MemArg) -> Self::Output {
3075 self.check_atomic_store(memarg, ValType::I32)
3076 }
3077 fn visit_i32_atomic_store16(&mut self, memarg: MemArg) -> Self::Output {
3078 self.check_atomic_store(memarg, ValType::I32)
3079 }
3080 fn visit_i32_atomic_store8(&mut self, memarg: MemArg) -> Self::Output {
3081 self.check_atomic_store(memarg, ValType::I32)
3082 }
3083 fn visit_i64_atomic_store(&mut self, memarg: MemArg) -> Self::Output {
3084 self.check_atomic_store(memarg, ValType::I64)
3085 }
3086 fn visit_i64_atomic_store32(&mut self, memarg: MemArg) -> Self::Output {
3087 self.check_atomic_store(memarg, ValType::I64)
3088 }
3089 fn visit_i64_atomic_store16(&mut self, memarg: MemArg) -> Self::Output {
3090 self.check_atomic_store(memarg, ValType::I64)
3091 }
3092 fn visit_i64_atomic_store8(&mut self, memarg: MemArg) -> Self::Output {
3093 self.check_atomic_store(memarg, ValType::I64)
3094 }
3095 fn visit_i32_atomic_rmw_add(&mut self, memarg: MemArg) -> Self::Output {
3096 self.check_atomic_binary_memory_op(memarg, ValType::I32)
3097 }
3098 fn visit_i32_atomic_rmw_sub(&mut self, memarg: MemArg) -> Self::Output {
3099 self.check_atomic_binary_memory_op(memarg, ValType::I32)
3100 }
3101 fn visit_i32_atomic_rmw_and(&mut self, memarg: MemArg) -> Self::Output {
3102 self.check_atomic_binary_memory_op(memarg, ValType::I32)
3103 }
3104 fn visit_i32_atomic_rmw_or(&mut self, memarg: MemArg) -> Self::Output {
3105 self.check_atomic_binary_memory_op(memarg, ValType::I32)
3106 }
3107 fn visit_i32_atomic_rmw_xor(&mut self, memarg: MemArg) -> Self::Output {
3108 self.check_atomic_binary_memory_op(memarg, ValType::I32)
3109 }
3110 fn visit_i32_atomic_rmw16_add_u(&mut self, memarg: MemArg) -> Self::Output {
3111 self.check_atomic_binary_memory_op(memarg, ValType::I32)
3112 }
3113 fn visit_i32_atomic_rmw16_sub_u(&mut self, memarg: MemArg) -> Self::Output {
3114 self.check_atomic_binary_memory_op(memarg, ValType::I32)
3115 }
3116 fn visit_i32_atomic_rmw16_and_u(&mut self, memarg: MemArg) -> Self::Output {
3117 self.check_atomic_binary_memory_op(memarg, ValType::I32)
3118 }
3119 fn visit_i32_atomic_rmw16_or_u(&mut self, memarg: MemArg) -> Self::Output {
3120 self.check_atomic_binary_memory_op(memarg, ValType::I32)
3121 }
3122 fn visit_i32_atomic_rmw16_xor_u(&mut self, memarg: MemArg) -> Self::Output {
3123 self.check_atomic_binary_memory_op(memarg, ValType::I32)
3124 }
3125 fn visit_i32_atomic_rmw8_add_u(&mut self, memarg: MemArg) -> Self::Output {
3126 self.check_atomic_binary_memory_op(memarg, ValType::I32)
3127 }
3128 fn visit_i32_atomic_rmw8_sub_u(&mut self, memarg: MemArg) -> Self::Output {
3129 self.check_atomic_binary_memory_op(memarg, ValType::I32)
3130 }
3131 fn visit_i32_atomic_rmw8_and_u(&mut self, memarg: MemArg) -> Self::Output {
3132 self.check_atomic_binary_memory_op(memarg, ValType::I32)
3133 }
3134 fn visit_i32_atomic_rmw8_or_u(&mut self, memarg: MemArg) -> Self::Output {
3135 self.check_atomic_binary_memory_op(memarg, ValType::I32)
3136 }
3137 fn visit_i32_atomic_rmw8_xor_u(&mut self, memarg: MemArg) -> Self::Output {
3138 self.check_atomic_binary_memory_op(memarg, ValType::I32)
3139 }
3140 fn visit_i64_atomic_rmw_add(&mut self, memarg: MemArg) -> Self::Output {
3141 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3142 }
3143 fn visit_i64_atomic_rmw_sub(&mut self, memarg: MemArg) -> Self::Output {
3144 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3145 }
3146 fn visit_i64_atomic_rmw_and(&mut self, memarg: MemArg) -> Self::Output {
3147 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3148 }
3149 fn visit_i64_atomic_rmw_or(&mut self, memarg: MemArg) -> Self::Output {
3150 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3151 }
3152 fn visit_i64_atomic_rmw_xor(&mut self, memarg: MemArg) -> Self::Output {
3153 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3154 }
3155 fn visit_i64_atomic_rmw32_add_u(&mut self, memarg: MemArg) -> Self::Output {
3156 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3157 }
3158 fn visit_i64_atomic_rmw32_sub_u(&mut self, memarg: MemArg) -> Self::Output {
3159 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3160 }
3161 fn visit_i64_atomic_rmw32_and_u(&mut self, memarg: MemArg) -> Self::Output {
3162 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3163 }
3164 fn visit_i64_atomic_rmw32_or_u(&mut self, memarg: MemArg) -> Self::Output {
3165 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3166 }
3167 fn visit_i64_atomic_rmw32_xor_u(&mut self, memarg: MemArg) -> Self::Output {
3168 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3169 }
3170 fn visit_i64_atomic_rmw16_add_u(&mut self, memarg: MemArg) -> Self::Output {
3171 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3172 }
3173 fn visit_i64_atomic_rmw16_sub_u(&mut self, memarg: MemArg) -> Self::Output {
3174 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3175 }
3176 fn visit_i64_atomic_rmw16_and_u(&mut self, memarg: MemArg) -> Self::Output {
3177 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3178 }
3179 fn visit_i64_atomic_rmw16_or_u(&mut self, memarg: MemArg) -> Self::Output {
3180 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3181 }
3182 fn visit_i64_atomic_rmw16_xor_u(&mut self, memarg: MemArg) -> Self::Output {
3183 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3184 }
3185 fn visit_i64_atomic_rmw8_add_u(&mut self, memarg: MemArg) -> Self::Output {
3186 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3187 }
3188 fn visit_i64_atomic_rmw8_sub_u(&mut self, memarg: MemArg) -> Self::Output {
3189 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3190 }
3191 fn visit_i64_atomic_rmw8_and_u(&mut self, memarg: MemArg) -> Self::Output {
3192 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3193 }
3194 fn visit_i64_atomic_rmw8_or_u(&mut self, memarg: MemArg) -> Self::Output {
3195 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3196 }
3197 fn visit_i64_atomic_rmw8_xor_u(&mut self, memarg: MemArg) -> Self::Output {
3198 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3199 }
3200 fn visit_i32_atomic_rmw_xchg(&mut self, memarg: MemArg) -> Self::Output {
3201 self.check_atomic_binary_memory_op(memarg, ValType::I32)
3202 }
3203 fn visit_i32_atomic_rmw16_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
3204 self.check_atomic_binary_memory_op(memarg, ValType::I32)
3205 }
3206 fn visit_i32_atomic_rmw8_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
3207 self.check_atomic_binary_memory_op(memarg, ValType::I32)
3208 }
3209 fn visit_i32_atomic_rmw_cmpxchg(&mut self, memarg: MemArg) -> Self::Output {
3210 self.check_atomic_binary_memory_cmpxchg(memarg, ValType::I32)
3211 }
3212 fn visit_i32_atomic_rmw16_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
3213 self.check_atomic_binary_memory_cmpxchg(memarg, ValType::I32)
3214 }
3215 fn visit_i32_atomic_rmw8_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
3216 self.check_atomic_binary_memory_cmpxchg(memarg, ValType::I32)
3217 }
3218 fn visit_i64_atomic_rmw_xchg(&mut self, memarg: MemArg) -> Self::Output {
3219 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3220 }
3221 fn visit_i64_atomic_rmw32_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
3222 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3223 }
3224 fn visit_i64_atomic_rmw16_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
3225 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3226 }
3227 fn visit_i64_atomic_rmw8_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
3228 self.check_atomic_binary_memory_op(memarg, ValType::I64)
3229 }
3230 fn visit_i64_atomic_rmw_cmpxchg(&mut self, memarg: MemArg) -> Self::Output {
3231 self.check_atomic_binary_memory_cmpxchg(memarg, ValType::I64)
3232 }
3233 fn visit_i64_atomic_rmw32_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
3234 self.check_atomic_binary_memory_cmpxchg(memarg, ValType::I64)
3235 }
3236 fn visit_i64_atomic_rmw16_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
3237 self.check_atomic_binary_memory_cmpxchg(memarg, ValType::I64)
3238 }
3239 fn visit_i64_atomic_rmw8_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
3240 self.check_atomic_binary_memory_cmpxchg(memarg, ValType::I64)
3241 }
3242 fn visit_memory_atomic_notify(&mut self, memarg: MemArg) -> Self::Output {
3243 self.check_atomic_binary_memory_op(memarg, ValType::I32)
3244 }
3245 fn visit_memory_atomic_wait32(&mut self, memarg: MemArg) -> Self::Output {
3246 let ty = self.check_shared_memarg(memarg)?;
3247 self.pop_operand(Some(ValType::I64))?;
3248 self.pop_operand(Some(ValType::I32))?;
3249 self.pop_operand(Some(ty))?;
3250 self.push_operand(ValType::I32)?;
3251 Ok(())
3252 }
3253 fn visit_memory_atomic_wait64(&mut self, memarg: MemArg) -> Self::Output {
3254 let ty = self.check_shared_memarg(memarg)?;
3255 self.pop_operand(Some(ValType::I64))?;
3256 self.pop_operand(Some(ValType::I64))?;
3257 self.pop_operand(Some(ty))?;
3258 self.push_operand(ValType::I32)?;
3259 Ok(())
3260 }
3261 fn visit_atomic_fence(&mut self) -> Self::Output {
3262 Ok(())
3263 }
3264 fn visit_ref_null(&mut self, mut heap_type: HeapType) -> Self::Output {
3265 if let Some(ty) = RefType::new(true, heap_type) {
3266 self.features
3267 .check_ref_type(ty)
3268 .map_err(|e| BinaryReaderError::new(e, self.offset))?;
3269 }
3270 self.resources
3271 .check_heap_type(&mut heap_type, self.offset)?;
3272 let ty = ValType::Ref(
3273 RefType::new(true, heap_type).expect("existing heap types should be within our limits"),
3274 );
3275 self.push_operand(ty)?;
3276 Ok(())
3277 }
3278
3279 fn visit_ref_as_non_null(&mut self) -> Self::Output {
3280 let ty = self.pop_ref(None)?.as_non_null();
3281 self.push_operand(ty)?;
3282 Ok(())
3283 }
3284 fn visit_br_on_null(&mut self, relative_depth: u32) -> Self::Output {
3285 let ref_ty = self.pop_ref(None)?.as_non_null();
3286 let (ft, kind) = self.jump(relative_depth)?;
3287 let label_types = self.label_types(ft, kind)?;
3288 self.pop_push_label_types(label_types)?;
3289 self.push_operand(ref_ty)?;
3290 Ok(())
3291 }
3292 fn visit_br_on_non_null(&mut self, relative_depth: u32) -> Self::Output {
3293 let (ft, kind) = self.jump(relative_depth)?;
3294
3295 let mut label_types = self.label_types(ft, kind)?;
3296 let expected = match label_types.next_back() {
3297 None => bail!(
3298 self.offset,
3299 "type mismatch: br_on_non_null target has no label types",
3300 ),
3301 Some(ValType::Ref(ty)) => ty,
3302 Some(_) => bail!(
3303 self.offset,
3304 "type mismatch: br_on_non_null target does not end with heap type",
3305 ),
3306 };
3307 self.pop_ref(Some(expected.nullable()))?;
3308
3309 self.pop_push_label_types(label_types)?;
3310 Ok(())
3311 }
3312 fn visit_ref_is_null(&mut self) -> Self::Output {
3313 self.pop_ref(None)?;
3314 self.push_operand(ValType::I32)?;
3315 Ok(())
3316 }
3317 fn visit_ref_func(&mut self, function_index: u32) -> Self::Output {
3318 let type_id = match self.resources.type_id_of_function(function_index) {
3319 Some(id) => id,
3320 None => bail!(
3321 self.offset,
3322 "unknown function {}: function index out of bounds",
3323 function_index,
3324 ),
3325 };
3326 if !self.resources.is_function_referenced(function_index) {
3327 bail!(self.offset, "undeclared function reference");
3328 }
3329
3330 let index = UnpackedIndex::Id(type_id);
3331 let hty = if self.features.custom_descriptors()
3332 && self.resources.has_function_exact_type(function_index)
3333 {
3334 HeapType::Exact(index)
3335 } else {
3336 HeapType::Concrete(index)
3337 };
3338 let ty = ValType::Ref(RefType::new(false, hty).ok_or_else(|| {
3339 BinaryReaderError::new("implementation limit: type index too large", self.offset)
3340 })?);
3341 self.push_operand(ty)?;
3342 Ok(())
3343 }
3344 fn visit_ref_eq(&mut self) -> Self::Output {
3345 let a = self.pop_maybe_shared_ref(AbstractHeapType::Eq)?;
3346 let b = self.pop_maybe_shared_ref(AbstractHeapType::Eq)?;
3347 let a_is_shared = a.is_maybe_shared(&self.resources);
3348 let b_is_shared = b.is_maybe_shared(&self.resources);
3349 match (a_is_shared, b_is_shared) {
3350 (None, Some(_)) | (Some(_), None) | (None, None) => {}
3353
3354 (Some(is_a_shared), Some(is_b_shared)) => {
3355 if is_a_shared != is_b_shared {
3356 bail!(
3357 self.offset,
3358 "type mismatch: expected `ref.eq` types to match `shared`-ness"
3359 );
3360 }
3361 }
3362 }
3363 self.push_operand(ValType::I32)
3364 }
3365 fn visit_memory_init(&mut self, segment: u32, mem: u32) -> Self::Output {
3366 let ty = self.check_memory_index(mem)?;
3367 self.check_data_segment(segment)?;
3368 self.pop_operand(Some(ValType::I32))?;
3369 self.pop_operand(Some(ValType::I32))?;
3370 self.pop_operand(Some(ty))?;
3371 Ok(())
3372 }
3373 fn visit_data_drop(&mut self, segment: u32) -> Self::Output {
3374 self.check_data_segment(segment)?;
3375 Ok(())
3376 }
3377 fn visit_memory_copy(&mut self, dst: u32, src: u32) -> Self::Output {
3378 self.check_enabled(self.features.bulk_memory_opt(), "bulk memory")?;
3379 let dst_ty = self.check_memory_index(dst)?;
3380 let src_ty = self.check_memory_index(src)?;
3381
3382 self.pop_operand(Some(match src_ty {
3385 ValType::I32 => ValType::I32,
3386 _ => dst_ty,
3387 }))?;
3388
3389 self.pop_operand(Some(src_ty))?;
3392 self.pop_operand(Some(dst_ty))?;
3393 Ok(())
3394 }
3395 fn visit_memory_fill(&mut self, mem: u32) -> Self::Output {
3396 self.check_enabled(self.features.bulk_memory_opt(), "bulk memory")?;
3397 let ty = self.check_memory_index(mem)?;
3398 self.pop_operand(Some(ty))?;
3399 self.pop_operand(Some(ValType::I32))?;
3400 self.pop_operand(Some(ty))?;
3401 Ok(())
3402 }
3403 fn visit_memory_discard(&mut self, mem: u32) -> Self::Output {
3404 let ty = self.check_memory_index(mem)?;
3405 self.pop_operand(Some(ty))?;
3406 self.pop_operand(Some(ty))?;
3407 Ok(())
3408 }
3409 fn visit_table_init(&mut self, segment: u32, table: u32) -> Self::Output {
3410 let table = self.table_type_at(table)?;
3411 let segment_ty = self.element_type_at(segment)?;
3412 if !self
3413 .resources
3414 .is_subtype(ValType::Ref(segment_ty), ValType::Ref(table.element_type))
3415 {
3416 bail!(self.offset, "type mismatch");
3417 }
3418 self.pop_operand(Some(ValType::I32))?;
3419 self.pop_operand(Some(ValType::I32))?;
3420 self.pop_operand(Some(table.index_type()))?;
3421 Ok(())
3422 }
3423 fn visit_elem_drop(&mut self, segment: u32) -> Self::Output {
3424 self.element_type_at(segment)?;
3425 Ok(())
3426 }
3427 fn visit_table_copy(&mut self, dst_table: u32, src_table: u32) -> Self::Output {
3428 let src = self.table_type_at(src_table)?;
3429 let dst = self.table_type_at(dst_table)?;
3430 if !self.resources.is_subtype(
3431 ValType::Ref(src.element_type),
3432 ValType::Ref(dst.element_type),
3433 ) {
3434 bail!(self.offset, "type mismatch");
3435 }
3436
3437 self.pop_operand(Some(match src.index_type() {
3440 ValType::I32 => ValType::I32,
3441 _ => dst.index_type(),
3442 }))?;
3443
3444 self.pop_operand(Some(src.index_type()))?;
3447 self.pop_operand(Some(dst.index_type()))?;
3448 Ok(())
3449 }
3450 fn visit_table_get(&mut self, table: u32) -> Self::Output {
3451 let table = self.table_type_at(table)?;
3452 debug_assert_type_indices_are_ids(table.element_type.into());
3453 self.pop_operand(Some(table.index_type()))?;
3454 self.push_operand(table.element_type)?;
3455 Ok(())
3456 }
3457 fn visit_table_atomic_get(&mut self, _ordering: Ordering, table: u32) -> Self::Output {
3458 self.visit_table_get(table)?;
3459 let ty = self.table_type_at(table)?.element_type;
3463 let supertype = RefType::ANYREF.shared().unwrap();
3464 if !self.resources.is_subtype(ty.into(), supertype.into()) {
3465 bail!(
3466 self.offset,
3467 "invalid type: `table.atomic.get` only allows subtypes of `anyref`"
3468 );
3469 }
3470 Ok(())
3471 }
3472 fn visit_table_set(&mut self, table: u32) -> Self::Output {
3473 let table = self.table_type_at(table)?;
3474 debug_assert_type_indices_are_ids(table.element_type.into());
3475 self.pop_operand(Some(table.element_type.into()))?;
3476 self.pop_operand(Some(table.index_type()))?;
3477 Ok(())
3478 }
3479 fn visit_table_atomic_set(&mut self, _ordering: Ordering, table: u32) -> Self::Output {
3480 self.visit_table_set(table)?;
3481 let ty = self.table_type_at(table)?.element_type;
3485 let supertype = RefType::ANYREF.shared().unwrap();
3486 if !self.resources.is_subtype(ty.into(), supertype.into()) {
3487 bail!(
3488 self.offset,
3489 "invalid type: `table.atomic.set` only allows subtypes of `anyref`"
3490 );
3491 }
3492 Ok(())
3493 }
3494 fn visit_table_grow(&mut self, table: u32) -> Self::Output {
3495 let table = self.table_type_at(table)?;
3496 debug_assert_type_indices_are_ids(table.element_type.into());
3497 self.pop_operand(Some(table.index_type()))?;
3498 self.pop_operand(Some(table.element_type.into()))?;
3499 self.push_operand(table.index_type())?;
3500 Ok(())
3501 }
3502 fn visit_table_size(&mut self, table: u32) -> Self::Output {
3503 let table = self.table_type_at(table)?;
3504 self.push_operand(table.index_type())?;
3505 Ok(())
3506 }
3507 fn visit_table_fill(&mut self, table: u32) -> Self::Output {
3508 let table = self.table_type_at(table)?;
3509 debug_assert_type_indices_are_ids(table.element_type.into());
3510 self.pop_operand(Some(table.index_type()))?;
3511 self.pop_operand(Some(table.element_type.into()))?;
3512 self.pop_operand(Some(table.index_type()))?;
3513 Ok(())
3514 }
3515 fn visit_table_atomic_rmw_xchg(&mut self, _ordering: Ordering, table: u32) -> Self::Output {
3516 let table = self.table_type_at(table)?;
3517 let elem_ty = table.element_type.into();
3518 debug_assert_type_indices_are_ids(elem_ty);
3519 let supertype = RefType::ANYREF.shared().unwrap();
3520 if !self.resources.is_subtype(elem_ty, supertype.into()) {
3521 bail!(
3522 self.offset,
3523 "invalid type: `table.atomic.rmw.xchg` only allows subtypes of `anyref`"
3524 );
3525 }
3526 self.pop_operand(Some(elem_ty))?;
3527 self.pop_operand(Some(table.index_type()))?;
3528 self.push_operand(elem_ty)?;
3529 Ok(())
3530 }
3531 fn visit_table_atomic_rmw_cmpxchg(&mut self, _ordering: Ordering, table: u32) -> Self::Output {
3532 let table = self.table_type_at(table)?;
3533 let elem_ty = table.element_type.into();
3534 debug_assert_type_indices_are_ids(elem_ty);
3535 let supertype = RefType::EQREF.shared().unwrap();
3536 if !self.resources.is_subtype(elem_ty, supertype.into()) {
3537 bail!(
3538 self.offset,
3539 "invalid type: `table.atomic.rmw.cmpxchg` only allows subtypes of `eqref`"
3540 );
3541 }
3542 self.pop_operand(Some(elem_ty))?;
3543 self.pop_operand(Some(elem_ty))?;
3544 self.pop_operand(Some(table.index_type()))?;
3545 self.push_operand(elem_ty)?;
3546 Ok(())
3547 }
3548 fn visit_struct_new(&mut self, struct_type_index: u32) -> Self::Output {
3549 if let Some(_) = self
3550 .sub_type_at(struct_type_index)?
3551 .composite_type
3552 .descriptor_idx
3553 {
3554 bail!(
3555 self.offset,
3556 "type with descriptor requires descriptor allocation: `struct.new` with type {struct_type_index}"
3557 );
3558 }
3559
3560 let struct_ty = self.struct_type_at(struct_type_index)?;
3561 for ty in struct_ty.fields.iter().rev() {
3562 self.pop_operand(Some(ty.element_type.unpack()))?;
3563 }
3564 self.push_exact_ref_if_available(false, struct_type_index)?;
3565 Ok(())
3566 }
3567 fn visit_struct_new_default(&mut self, type_index: u32) -> Self::Output {
3568 if let Some(_) = self.sub_type_at(type_index)?.composite_type.descriptor_idx {
3569 bail!(
3570 self.offset,
3571 "type with descriptor requires descriptor allocation: `struct.new_default` with type {type_index}"
3572 );
3573 }
3574
3575 let ty = self.struct_type_at(type_index)?;
3576 for field in ty.fields.iter() {
3577 let val_ty = field.element_type.unpack();
3578 if !val_ty.is_defaultable() {
3579 bail!(
3580 self.offset,
3581 "invalid `struct.new_default`: {val_ty} field is not defaultable"
3582 );
3583 }
3584 }
3585 self.push_exact_ref_if_available(false, type_index)?;
3586 Ok(())
3587 }
3588 fn visit_struct_new_desc(&mut self, struct_type_index: u32) -> Self::Output {
3589 if let Some(descriptor_idx) = self
3590 .sub_type_at(struct_type_index)?
3591 .composite_type
3592 .descriptor_idx
3593 {
3594 let ty = ValType::Ref(RefType::exact(true, descriptor_idx));
3595 self.pop_operand(Some(ty))?;
3596 } else {
3597 bail!(
3598 self.offset,
3599 "invalid `struct.new_desc`: type {struct_type_index} is not described"
3600 );
3601 }
3602 let struct_ty = self.struct_type_at(struct_type_index)?;
3603 for ty in struct_ty.fields.iter().rev() {
3604 self.pop_operand(Some(ty.element_type.unpack()))?;
3605 }
3606 self.push_exact_ref_if_available(false, struct_type_index)?;
3607 Ok(())
3608 }
3609 fn visit_struct_new_default_desc(&mut self, type_index: u32) -> Self::Output {
3610 if let Some(descriptor_idx) = self.sub_type_at(type_index)?.composite_type.descriptor_idx {
3611 let ty = ValType::Ref(RefType::exact(true, descriptor_idx));
3612 self.pop_operand(Some(ty))?;
3613 } else {
3614 bail!(
3615 self.offset,
3616 "invalid `struct.new_default_desc`: type {type_index} is not described"
3617 );
3618 }
3619 let ty = self.struct_type_at(type_index)?;
3620 for field in ty.fields.iter() {
3621 let val_ty = field.element_type.unpack();
3622 if !val_ty.is_defaultable() {
3623 bail!(
3624 self.offset,
3625 "invalid `struct.new_default`: {val_ty} field is not defaultable"
3626 );
3627 }
3628 }
3629 self.push_exact_ref_if_available(false, type_index)?;
3630 Ok(())
3631 }
3632 fn visit_struct_get(&mut self, struct_type_index: u32, field_index: u32) -> Self::Output {
3633 let field_ty = self.struct_field_at(struct_type_index, field_index)?;
3634 if field_ty.element_type.is_packed() {
3635 bail!(
3636 self.offset,
3637 "can only use struct `get` with non-packed storage types"
3638 )
3639 }
3640 self.pop_concrete_ref(true, struct_type_index)?;
3641 self.push_operand(field_ty.element_type.unpack())
3642 }
3643 fn visit_struct_atomic_get(
3644 &mut self,
3645 _ordering: Ordering,
3646 struct_type_index: u32,
3647 field_index: u32,
3648 ) -> Self::Output {
3649 self.visit_struct_get(struct_type_index, field_index)?;
3650 let ty = self
3652 .struct_field_at(struct_type_index, field_index)?
3653 .element_type;
3654 let is_valid_type = match ty {
3655 StorageType::Val(ValType::I32) | StorageType::Val(ValType::I64) => true,
3656 StorageType::Val(v) => self
3657 .resources
3658 .is_subtype(v, RefType::ANYREF.shared().unwrap().into()),
3659 _ => false,
3660 };
3661 if !is_valid_type {
3662 bail!(
3663 self.offset,
3664 "invalid type: `struct.atomic.get` only allows `i32`, `i64` and subtypes of `anyref`"
3665 );
3666 }
3667 Ok(())
3668 }
3669 fn visit_struct_get_s(&mut self, struct_type_index: u32, field_index: u32) -> Self::Output {
3670 let field_ty = self.struct_field_at(struct_type_index, field_index)?;
3671 if !field_ty.element_type.is_packed() {
3672 bail!(
3673 self.offset,
3674 "cannot use struct.get_s with non-packed storage types"
3675 )
3676 }
3677 self.pop_concrete_ref(true, struct_type_index)?;
3678 self.push_operand(field_ty.element_type.unpack())
3679 }
3680 fn visit_struct_atomic_get_s(
3681 &mut self,
3682 _ordering: Ordering,
3683 struct_type_index: u32,
3684 field_index: u32,
3685 ) -> Self::Output {
3686 self.visit_struct_get_s(struct_type_index, field_index)?;
3687 debug_assert!(matches!(
3689 self.struct_field_at(struct_type_index, field_index)?
3690 .element_type,
3691 StorageType::I8 | StorageType::I16
3692 ));
3693 Ok(())
3694 }
3695 fn visit_struct_get_u(&mut self, struct_type_index: u32, field_index: u32) -> Self::Output {
3696 let field_ty = self.struct_field_at(struct_type_index, field_index)?;
3697 if !field_ty.element_type.is_packed() {
3698 bail!(
3699 self.offset,
3700 "cannot use struct.get_u with non-packed storage types"
3701 )
3702 }
3703 self.pop_concrete_ref(true, struct_type_index)?;
3704 self.push_operand(field_ty.element_type.unpack())
3705 }
3706 fn visit_struct_atomic_get_u(
3707 &mut self,
3708 _ordering: Ordering,
3709 struct_type_index: u32,
3710 field_index: u32,
3711 ) -> Self::Output {
3712 self.visit_struct_get_s(struct_type_index, field_index)?;
3713 debug_assert!(matches!(
3715 self.struct_field_at(struct_type_index, field_index)?
3716 .element_type,
3717 StorageType::I8 | StorageType::I16
3718 ));
3719 Ok(())
3720 }
3721 fn visit_struct_set(&mut self, struct_type_index: u32, field_index: u32) -> Self::Output {
3722 let field_ty = self.mutable_struct_field_at(struct_type_index, field_index)?;
3723 self.pop_operand(Some(field_ty.element_type.unpack()))?;
3724 self.pop_concrete_ref(true, struct_type_index)?;
3725 Ok(())
3726 }
3727 fn visit_struct_atomic_set(
3728 &mut self,
3729 _ordering: Ordering,
3730 struct_type_index: u32,
3731 field_index: u32,
3732 ) -> Self::Output {
3733 self.visit_struct_set(struct_type_index, field_index)?;
3734 let ty = self
3736 .struct_field_at(struct_type_index, field_index)?
3737 .element_type;
3738 let is_valid_type = match ty {
3739 StorageType::I8 | StorageType::I16 => true,
3740 StorageType::Val(ValType::I32) | StorageType::Val(ValType::I64) => true,
3741 StorageType::Val(v) => self
3742 .resources
3743 .is_subtype(v, RefType::ANYREF.shared().unwrap().into()),
3744 };
3745 if !is_valid_type {
3746 bail!(
3747 self.offset,
3748 "invalid type: `struct.atomic.set` only allows `i8`, `i16`, `i32`, `i64` and subtypes of `anyref`"
3749 );
3750 }
3751 Ok(())
3752 }
3753 fn visit_struct_atomic_rmw_add(
3754 &mut self,
3755 _ordering: Ordering,
3756 struct_type_index: u32,
3757 field_index: u32,
3758 ) -> Self::Output {
3759 self.check_struct_atomic_rmw("add", struct_type_index, field_index)
3760 }
3761 fn visit_struct_atomic_rmw_sub(
3762 &mut self,
3763 _ordering: Ordering,
3764 struct_type_index: u32,
3765 field_index: u32,
3766 ) -> Self::Output {
3767 self.check_struct_atomic_rmw("sub", struct_type_index, field_index)
3768 }
3769 fn visit_struct_atomic_rmw_and(
3770 &mut self,
3771 _ordering: Ordering,
3772 struct_type_index: u32,
3773 field_index: u32,
3774 ) -> Self::Output {
3775 self.check_struct_atomic_rmw("and", struct_type_index, field_index)
3776 }
3777 fn visit_struct_atomic_rmw_or(
3778 &mut self,
3779 _ordering: Ordering,
3780 struct_type_index: u32,
3781 field_index: u32,
3782 ) -> Self::Output {
3783 self.check_struct_atomic_rmw("or", struct_type_index, field_index)
3784 }
3785 fn visit_struct_atomic_rmw_xor(
3786 &mut self,
3787 _ordering: Ordering,
3788 struct_type_index: u32,
3789 field_index: u32,
3790 ) -> Self::Output {
3791 self.check_struct_atomic_rmw("xor", struct_type_index, field_index)
3792 }
3793 fn visit_struct_atomic_rmw_xchg(
3794 &mut self,
3795 _ordering: Ordering,
3796 struct_type_index: u32,
3797 field_index: u32,
3798 ) -> Self::Output {
3799 let field = self.mutable_struct_field_at(struct_type_index, field_index)?;
3800 let is_valid_type = match field.element_type {
3801 StorageType::Val(ValType::I32) | StorageType::Val(ValType::I64) => true,
3802 StorageType::Val(v) => self
3803 .resources
3804 .is_subtype(v, RefType::ANYREF.shared().unwrap().into()),
3805 _ => false,
3806 };
3807 if !is_valid_type {
3808 bail!(
3809 self.offset,
3810 "invalid type: `struct.atomic.rmw.xchg` only allows `i32`, `i64` and subtypes of `anyref`"
3811 );
3812 }
3813 let field_ty = field.element_type.unpack();
3814 self.pop_operand(Some(field_ty))?;
3815 self.pop_concrete_ref(true, struct_type_index)?;
3816 self.push_operand(field_ty)?;
3817 Ok(())
3818 }
3819 fn visit_struct_atomic_rmw_cmpxchg(
3820 &mut self,
3821 _ordering: Ordering,
3822 struct_type_index: u32,
3823 field_index: u32,
3824 ) -> Self::Output {
3825 let field = self.mutable_struct_field_at(struct_type_index, field_index)?;
3826 let is_valid_type = match field.element_type {
3827 StorageType::Val(ValType::I32) | StorageType::Val(ValType::I64) => true,
3828 StorageType::Val(v) => self
3829 .resources
3830 .is_subtype(v, RefType::EQREF.shared().unwrap().into()),
3831 _ => false,
3832 };
3833 if !is_valid_type {
3834 bail!(
3835 self.offset,
3836 "invalid type: `struct.atomic.rmw.cmpxchg` only allows `i32`, `i64` and subtypes of `eqref`"
3837 );
3838 }
3839 let field_ty = field.element_type.unpack();
3840 self.pop_operand(Some(field_ty))?;
3841 self.pop_operand(Some(field_ty))?;
3842 self.pop_concrete_ref(true, struct_type_index)?;
3843 self.push_operand(field_ty)?;
3844 Ok(())
3845 }
3846 fn visit_array_new(&mut self, type_index: u32) -> Self::Output {
3847 let array_ty = self.array_type_at(type_index)?;
3848 self.pop_operand(Some(ValType::I32))?;
3849 self.pop_operand(Some(array_ty.element_type.unpack()))?;
3850 self.push_exact_ref_if_available(false, type_index)
3851 }
3852 fn visit_array_new_default(&mut self, type_index: u32) -> Self::Output {
3853 let ty = self.array_type_at(type_index)?;
3854 let val_ty = ty.element_type.unpack();
3855 if !val_ty.is_defaultable() {
3856 bail!(
3857 self.offset,
3858 "invalid `array.new_default`: {val_ty} field is not defaultable"
3859 );
3860 }
3861 self.pop_operand(Some(ValType::I32))?;
3862 self.push_exact_ref_if_available(false, type_index)
3863 }
3864 fn visit_array_new_fixed(&mut self, type_index: u32, n: u32) -> Self::Output {
3865 let array_ty = self.array_type_at(type_index)?;
3866 let elem_ty = array_ty.element_type.unpack();
3867 for _ in 0..n {
3868 self.pop_operand(Some(elem_ty))?;
3869 }
3870 self.push_exact_ref_if_available(false, type_index)
3871 }
3872 fn visit_array_new_data(&mut self, type_index: u32, data_index: u32) -> Self::Output {
3873 let array_ty = self.array_type_at(type_index)?;
3874 let elem_ty = array_ty.element_type.unpack();
3875 match elem_ty {
3876 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => {}
3877 ValType::Ref(_) => bail!(
3878 self.offset,
3879 "type mismatch: array.new_data can only create arrays with numeric and vector elements"
3880 ),
3881 }
3882 self.check_data_segment(data_index)?;
3883 self.pop_operand(Some(ValType::I32))?;
3884 self.pop_operand(Some(ValType::I32))?;
3885 self.push_exact_ref_if_available(false, type_index)
3886 }
3887 fn visit_array_new_elem(&mut self, type_index: u32, elem_index: u32) -> Self::Output {
3888 let array_ty = self.array_type_at(type_index)?;
3889 let array_ref_ty = match array_ty.element_type.unpack() {
3890 ValType::Ref(rt) => rt,
3891 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => bail!(
3892 self.offset,
3893 "type mismatch: array.new_elem can only create arrays with reference elements"
3894 ),
3895 };
3896 let elem_ref_ty = self.element_type_at(elem_index)?;
3897 if !self
3898 .resources
3899 .is_subtype(elem_ref_ty.into(), array_ref_ty.into())
3900 {
3901 bail!(
3902 self.offset,
3903 "invalid array.new_elem instruction: element segment {elem_index} type mismatch: \
3904 expected {array_ref_ty}, found {elem_ref_ty}"
3905 )
3906 }
3907 self.pop_operand(Some(ValType::I32))?;
3908 self.pop_operand(Some(ValType::I32))?;
3909 self.push_exact_ref_if_available(false, type_index)
3910 }
3911 fn visit_array_get(&mut self, type_index: u32) -> Self::Output {
3912 let array_ty = self.array_type_at(type_index)?;
3913 let elem_ty = array_ty.element_type;
3914 if elem_ty.is_packed() {
3915 bail!(
3916 self.offset,
3917 "cannot use array.get with packed storage types"
3918 )
3919 }
3920 self.pop_operand(Some(ValType::I32))?;
3921 self.pop_concrete_ref(true, type_index)?;
3922 self.push_operand(elem_ty.unpack())
3923 }
3924 fn visit_array_atomic_get(&mut self, _ordering: Ordering, type_index: u32) -> Self::Output {
3925 self.visit_array_get(type_index)?;
3926 let elem_ty = self.array_type_at(type_index)?.element_type;
3928 let is_valid_type = match elem_ty {
3929 StorageType::Val(ValType::I32) | StorageType::Val(ValType::I64) => true,
3930 StorageType::Val(v) => self
3931 .resources
3932 .is_subtype(v, RefType::ANYREF.shared().unwrap().into()),
3933 _ => false,
3934 };
3935 if !is_valid_type {
3936 bail!(
3937 self.offset,
3938 "invalid type: `array.atomic.get` only allows `i32`, `i64` and subtypes of `anyref`"
3939 );
3940 }
3941 Ok(())
3942 }
3943 fn visit_array_get_s(&mut self, type_index: u32) -> Self::Output {
3944 let array_ty = self.array_type_at(type_index)?;
3945 let elem_ty = array_ty.element_type;
3946 if !elem_ty.is_packed() {
3947 bail!(
3948 self.offset,
3949 "cannot use array.get_s with non-packed storage types"
3950 )
3951 }
3952 self.pop_operand(Some(ValType::I32))?;
3953 self.pop_concrete_ref(true, type_index)?;
3954 self.push_operand(elem_ty.unpack())
3955 }
3956 fn visit_array_atomic_get_s(&mut self, _ordering: Ordering, type_index: u32) -> Self::Output {
3957 self.visit_array_get_s(type_index)?;
3958 debug_assert!(matches!(
3960 self.array_type_at(type_index)?.element_type,
3961 StorageType::I8 | StorageType::I16
3962 ));
3963 Ok(())
3964 }
3965 fn visit_array_get_u(&mut self, type_index: u32) -> Self::Output {
3966 let array_ty = self.array_type_at(type_index)?;
3967 let elem_ty = array_ty.element_type;
3968 if !elem_ty.is_packed() {
3969 bail!(
3970 self.offset,
3971 "cannot use array.get_u with non-packed storage types"
3972 )
3973 }
3974 self.pop_operand(Some(ValType::I32))?;
3975 self.pop_concrete_ref(true, type_index)?;
3976 self.push_operand(elem_ty.unpack())
3977 }
3978 fn visit_array_atomic_get_u(&mut self, _ordering: Ordering, type_index: u32) -> Self::Output {
3979 self.visit_array_get_u(type_index)?;
3980 debug_assert!(matches!(
3982 self.array_type_at(type_index)?.element_type,
3983 StorageType::I8 | StorageType::I16
3984 ));
3985 Ok(())
3986 }
3987 fn visit_array_set(&mut self, type_index: u32) -> Self::Output {
3988 let array_ty = self.mutable_array_type_at(type_index)?;
3989 self.pop_operand(Some(array_ty.element_type.unpack()))?;
3990 self.pop_operand(Some(ValType::I32))?;
3991 self.pop_concrete_ref(true, type_index)?;
3992 Ok(())
3993 }
3994 fn visit_array_atomic_set(&mut self, _ordering: Ordering, type_index: u32) -> Self::Output {
3995 self.visit_array_set(type_index)?;
3996 let elem_ty = self.array_type_at(type_index)?.element_type;
3998 let is_valid_type = match elem_ty {
3999 StorageType::I8 | StorageType::I16 => true,
4000 StorageType::Val(ValType::I32) | StorageType::Val(ValType::I64) => true,
4001 StorageType::Val(v) => self
4002 .resources
4003 .is_subtype(v, RefType::ANYREF.shared().unwrap().into()),
4004 };
4005 if !is_valid_type {
4006 bail!(
4007 self.offset,
4008 "invalid type: `array.atomic.set` only allows `i8`, `i16`, `i32`, `i64` and subtypes of `anyref`"
4009 );
4010 }
4011 Ok(())
4012 }
4013 fn visit_array_len(&mut self) -> Self::Output {
4014 self.pop_maybe_shared_ref(AbstractHeapType::Array)?;
4015 self.push_operand(ValType::I32)
4016 }
4017 fn visit_array_fill(&mut self, array_type_index: u32) -> Self::Output {
4018 let array_ty = self.mutable_array_type_at(array_type_index)?;
4019 self.pop_operand(Some(ValType::I32))?;
4020 self.pop_operand(Some(array_ty.element_type.unpack()))?;
4021 self.pop_operand(Some(ValType::I32))?;
4022 self.pop_concrete_ref(true, array_type_index)?;
4023 Ok(())
4024 }
4025 fn visit_array_copy(&mut self, type_index_dst: u32, type_index_src: u32) -> Self::Output {
4026 let array_ty_dst = self.mutable_array_type_at(type_index_dst)?;
4027 let array_ty_src = self.array_type_at(type_index_src)?;
4028 match (array_ty_dst.element_type, array_ty_src.element_type) {
4029 (StorageType::I8, StorageType::I8) => {}
4030 (StorageType::I8, ty) => bail!(
4031 self.offset,
4032 "array types do not match: expected i8, found {ty}"
4033 ),
4034 (StorageType::I16, StorageType::I16) => {}
4035 (StorageType::I16, ty) => bail!(
4036 self.offset,
4037 "array types do not match: expected i16, found {ty}"
4038 ),
4039 (StorageType::Val(dst), StorageType::Val(src)) => {
4040 if !self.resources.is_subtype(src, dst) {
4041 bail!(
4042 self.offset,
4043 "array types do not match: expected {dst}, found {src}"
4044 )
4045 }
4046 }
4047 (StorageType::Val(dst), src) => {
4048 bail!(
4049 self.offset,
4050 "array types do not match: expected {dst}, found {src}"
4051 )
4052 }
4053 }
4054 self.pop_operand(Some(ValType::I32))?;
4055 self.pop_operand(Some(ValType::I32))?;
4056 self.pop_concrete_ref(true, type_index_src)?;
4057 self.pop_operand(Some(ValType::I32))?;
4058 self.pop_concrete_ref(true, type_index_dst)?;
4059 Ok(())
4060 }
4061 fn visit_array_init_data(
4062 &mut self,
4063 array_type_index: u32,
4064 array_data_index: u32,
4065 ) -> Self::Output {
4066 let array_ty = self.mutable_array_type_at(array_type_index)?;
4067 let val_ty = array_ty.element_type.unpack();
4068 match val_ty {
4069 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => {}
4070 ValType::Ref(_) => bail!(
4071 self.offset,
4072 "invalid array.init_data: array type is not numeric or vector"
4073 ),
4074 }
4075 self.check_data_segment(array_data_index)?;
4076 self.pop_operand(Some(ValType::I32))?;
4077 self.pop_operand(Some(ValType::I32))?;
4078 self.pop_operand(Some(ValType::I32))?;
4079 self.pop_concrete_ref(true, array_type_index)?;
4080 Ok(())
4081 }
4082 fn visit_array_init_elem(&mut self, type_index: u32, elem_index: u32) -> Self::Output {
4083 let array_ty = self.mutable_array_type_at(type_index)?;
4084 let array_ref_ty = match array_ty.element_type.unpack() {
4085 ValType::Ref(rt) => rt,
4086 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => bail!(
4087 self.offset,
4088 "type mismatch: array.init_elem can only create arrays with reference elements"
4089 ),
4090 };
4091 let elem_ref_ty = self.element_type_at(elem_index)?;
4092 if !self
4093 .resources
4094 .is_subtype(elem_ref_ty.into(), array_ref_ty.into())
4095 {
4096 bail!(
4097 self.offset,
4098 "invalid array.init_elem instruction: element segment {elem_index} type mismatch: \
4099 expected {array_ref_ty}, found {elem_ref_ty}"
4100 )
4101 }
4102 self.pop_operand(Some(ValType::I32))?;
4103 self.pop_operand(Some(ValType::I32))?;
4104 self.pop_operand(Some(ValType::I32))?;
4105 self.pop_concrete_ref(true, type_index)?;
4106 Ok(())
4107 }
4108 fn visit_array_atomic_rmw_add(&mut self, _ordering: Ordering, type_index: u32) -> Self::Output {
4109 self.check_array_atomic_rmw("add", type_index)
4110 }
4111 fn visit_array_atomic_rmw_sub(&mut self, _ordering: Ordering, type_index: u32) -> Self::Output {
4112 self.check_array_atomic_rmw("sub", type_index)
4113 }
4114 fn visit_array_atomic_rmw_and(&mut self, _ordering: Ordering, type_index: u32) -> Self::Output {
4115 self.check_array_atomic_rmw("and", type_index)
4116 }
4117 fn visit_array_atomic_rmw_or(&mut self, _ordering: Ordering, type_index: u32) -> Self::Output {
4118 self.check_array_atomic_rmw("or", type_index)
4119 }
4120 fn visit_array_atomic_rmw_xor(&mut self, _ordering: Ordering, type_index: u32) -> Self::Output {
4121 self.check_array_atomic_rmw("xor", type_index)
4122 }
4123 fn visit_array_atomic_rmw_xchg(
4124 &mut self,
4125 _ordering: Ordering,
4126 type_index: u32,
4127 ) -> Self::Output {
4128 let field = self.mutable_array_type_at(type_index)?;
4129 let is_valid_type = match field.element_type {
4130 StorageType::Val(ValType::I32) | StorageType::Val(ValType::I64) => true,
4131 StorageType::Val(v) => self
4132 .resources
4133 .is_subtype(v, RefType::ANYREF.shared().unwrap().into()),
4134 _ => false,
4135 };
4136 if !is_valid_type {
4137 bail!(
4138 self.offset,
4139 "invalid type: `array.atomic.rmw.xchg` only allows `i32`, `i64` and subtypes of `anyref`"
4140 );
4141 }
4142 let elem_ty = field.element_type.unpack();
4143 self.pop_operand(Some(elem_ty))?;
4144 self.pop_operand(Some(ValType::I32))?;
4145 self.pop_concrete_ref(true, type_index)?;
4146 self.push_operand(elem_ty)?;
4147 Ok(())
4148 }
4149 fn visit_array_atomic_rmw_cmpxchg(
4150 &mut self,
4151 _ordering: Ordering,
4152 type_index: u32,
4153 ) -> Self::Output {
4154 let field = self.mutable_array_type_at(type_index)?;
4155 let is_valid_type = match field.element_type {
4156 StorageType::Val(ValType::I32) | StorageType::Val(ValType::I64) => true,
4157 StorageType::Val(v) => self
4158 .resources
4159 .is_subtype(v, RefType::EQREF.shared().unwrap().into()),
4160 _ => false,
4161 };
4162 if !is_valid_type {
4163 bail!(
4164 self.offset,
4165 "invalid type: `array.atomic.rmw.cmpxchg` only allows `i32`, `i64` and subtypes of `eqref`"
4166 );
4167 }
4168 let elem_ty = field.element_type.unpack();
4169 self.pop_operand(Some(elem_ty))?;
4170 self.pop_operand(Some(elem_ty))?;
4171 self.pop_operand(Some(ValType::I32))?;
4172 self.pop_concrete_ref(true, type_index)?;
4173 self.push_operand(elem_ty)?;
4174 Ok(())
4175 }
4176 fn visit_any_convert_extern(&mut self) -> Self::Output {
4177 let any_ref = match self.pop_maybe_shared_ref(AbstractHeapType::Extern)? {
4178 MaybeType::Bottom | MaybeType::UnknownRef(_) => {
4179 MaybeType::UnknownRef(Some(AbstractHeapType::Any))
4180 }
4181 MaybeType::Known(ty) => {
4182 let shared = self.resources.is_shared(ty);
4183 let heap_type = HeapType::Abstract {
4184 shared,
4185 ty: AbstractHeapType::Any,
4186 };
4187 let any_ref = RefType::new(ty.is_nullable(), heap_type).unwrap();
4188 MaybeType::Known(any_ref)
4189 }
4190 };
4191 self.push_operand(any_ref)
4192 }
4193 fn visit_extern_convert_any(&mut self) -> Self::Output {
4194 let extern_ref = match self.pop_maybe_shared_ref(AbstractHeapType::Any)? {
4195 MaybeType::Bottom | MaybeType::UnknownRef(_) => {
4196 MaybeType::UnknownRef(Some(AbstractHeapType::Extern))
4197 }
4198 MaybeType::Known(ty) => {
4199 let shared = self.resources.is_shared(ty);
4200 let heap_type = HeapType::Abstract {
4201 shared,
4202 ty: AbstractHeapType::Extern,
4203 };
4204 let extern_ref = RefType::new(ty.is_nullable(), heap_type).unwrap();
4205 MaybeType::Known(extern_ref)
4206 }
4207 };
4208 self.push_operand(extern_ref)
4209 }
4210 fn visit_ref_test_non_null(&mut self, heap_type: HeapType) -> Self::Output {
4211 self.check_ref_test(false, heap_type)
4212 }
4213 fn visit_ref_test_nullable(&mut self, heap_type: HeapType) -> Self::Output {
4214 self.check_ref_test(true, heap_type)
4215 }
4216 fn visit_ref_cast_non_null(&mut self, heap_type: HeapType) -> Self::Output {
4217 self.check_ref_cast(false, heap_type)
4218 }
4219 fn visit_ref_cast_nullable(&mut self, heap_type: HeapType) -> Self::Output {
4220 self.check_ref_cast(true, heap_type)
4221 }
4222 fn visit_br_on_cast(
4223 &mut self,
4224 relative_depth: u32,
4225 mut from_ref_type: RefType,
4226 mut to_ref_type: RefType,
4227 ) -> Self::Output {
4228 self.resources
4229 .check_ref_type(&mut from_ref_type, self.offset)?;
4230 self.resources
4231 .check_ref_type(&mut to_ref_type, self.offset)?;
4232
4233 self.check_br_on_cast_type_hierarchy(from_ref_type, to_ref_type)?;
4234
4235 let (block_ty, frame_kind) = self.jump(relative_depth)?;
4236 let mut label_types = self.label_types(block_ty, frame_kind)?;
4237
4238 match label_types.next_back() {
4239 Some(label_ty) if self.resources.is_subtype(to_ref_type.into(), label_ty) => {
4240 self.pop_operand(Some(from_ref_type.into()))?;
4241 }
4242 Some(label_ty) => bail!(
4243 self.offset,
4244 "type mismatch: casting to type {to_ref_type}, but it does not match \
4245 label result type {label_ty}"
4246 ),
4247 None => bail!(
4248 self.offset,
4249 "type mismatch: br_on_cast to label with empty types, must have a reference type"
4250 ),
4251 };
4252
4253 self.pop_push_label_types(label_types)?;
4254 let diff_ty = RefType::difference(from_ref_type, to_ref_type);
4255 self.push_operand(diff_ty)?;
4256 Ok(())
4257 }
4258 fn visit_br_on_cast_fail(
4259 &mut self,
4260 relative_depth: u32,
4261 mut from_ref_type: RefType,
4262 mut to_ref_type: RefType,
4263 ) -> Self::Output {
4264 self.resources
4265 .check_ref_type(&mut from_ref_type, self.offset)?;
4266 self.resources
4267 .check_ref_type(&mut to_ref_type, self.offset)?;
4268
4269 self.check_br_on_cast_type_hierarchy(from_ref_type, to_ref_type)?;
4270
4271 let (block_ty, frame_kind) = self.jump(relative_depth)?;
4272 let mut label_tys = self.label_types(block_ty, frame_kind)?;
4273
4274 let diff_ty = RefType::difference(from_ref_type, to_ref_type);
4275 match label_tys.next_back() {
4276 Some(label_ty) if self.resources.is_subtype(diff_ty.into(), label_ty) => {
4277 self.pop_operand(Some(from_ref_type.into()))?;
4278 }
4279 Some(label_ty) => bail!(
4280 self.offset,
4281 "type mismatch: expected label result type {label_ty}, found {diff_ty}"
4282 ),
4283 None => bail!(
4284 self.offset,
4285 "type mismatch: expected a reference type, found nothing"
4286 ),
4287 }
4288
4289 self.pop_push_label_types(label_tys)?;
4290 self.push_operand(to_ref_type)?;
4291 Ok(())
4292 }
4293 fn visit_ref_i31(&mut self) -> Self::Output {
4294 self.pop_operand(Some(ValType::I32))?;
4295 self.push_operand(ValType::Ref(RefType::I31))
4296 }
4297 fn visit_ref_i31_shared(&mut self) -> Self::Output {
4298 self.pop_operand(Some(ValType::I32))?;
4299 self.push_operand(ValType::Ref(
4300 RefType::I31.shared().expect("i31 is abstract"),
4301 ))
4302 }
4303 fn visit_i31_get_s(&mut self) -> Self::Output {
4304 self.pop_maybe_shared_ref(AbstractHeapType::I31)?;
4305 self.push_operand(ValType::I32)
4306 }
4307 fn visit_i31_get_u(&mut self) -> Self::Output {
4308 self.pop_maybe_shared_ref(AbstractHeapType::I31)?;
4309 self.push_operand(ValType::I32)
4310 }
4311 fn visit_try(&mut self, mut ty: BlockType) -> Self::Output {
4312 self.check_block_type(&mut ty)?;
4313 for ty in self.params(ty)?.rev() {
4314 self.pop_operand(Some(ty))?;
4315 }
4316 self.push_ctrl(FrameKind::LegacyTry, ty)?;
4317 Ok(())
4318 }
4319 fn visit_catch(&mut self, index: u32) -> Self::Output {
4320 let frame = self.pop_ctrl()?;
4321 debug_assert!(frame.kind == FrameKind::LegacyTry || frame.kind == FrameKind::LegacyCatch);
4322 self.push_bare_ctrl(FrameKind::LegacyCatch, frame.block_type);
4324 let ty = self.exception_tag_at(index)?;
4325 for ty in ty.params() {
4326 self.push_operand(*ty)?;
4327 }
4328 Ok(())
4329 }
4330 fn visit_rethrow(&mut self, relative_depth: u32) -> Self::Output {
4331 let (_, kind) = self.jump(relative_depth)?;
4334 if kind != FrameKind::LegacyCatch && kind != FrameKind::LegacyCatchAll {
4335 bail!(
4336 self.offset,
4337 "invalid rethrow label: target was not a `catch` block"
4338 );
4339 }
4340 self.unreachable()?;
4341 Ok(())
4342 }
4343 fn visit_delegate(&mut self, relative_depth: u32) -> Self::Output {
4344 let frame = self.pop_ctrl()?;
4345 debug_assert_eq!(frame.kind, FrameKind::LegacyTry);
4346 let _ = self.jump(relative_depth)?;
4349 for ty in self.results(frame.block_type)? {
4350 self.push_operand(ty)?;
4351 }
4352 Ok(())
4353 }
4354 fn visit_catch_all(&mut self) -> Self::Output {
4355 let frame = self.pop_ctrl()?;
4356 debug_assert!(frame.kind == FrameKind::LegacyTry || frame.kind == FrameKind::LegacyCatch);
4357 self.push_bare_ctrl(FrameKind::LegacyCatchAll, frame.block_type);
4358 Ok(())
4359 }
4360 fn visit_cont_new(&mut self, type_index: u32) -> Self::Output {
4361 let cont_ty = self.cont_type_at(type_index)?;
4362 let rt = RefType::concrete(true, cont_ty.0);
4363 self.pop_ref(Some(rt))?;
4364 self.push_concrete_ref(false, type_index)?;
4365 Ok(())
4366 }
4367 fn visit_cont_bind(&mut self, argument_index: u32, result_index: u32) -> Self::Output {
4368 let arg_cont = self.cont_type_at(argument_index)?;
4370 let arg_func = self.func_type_of_cont_type(arg_cont);
4371 let res_cont = self.cont_type_at(result_index)?;
4373 let res_func = self.func_type_of_cont_type(res_cont);
4374
4375 if arg_func.params().len() < res_func.params().len() {
4378 bail!(self.offset, "type mismatch in continuation arguments");
4379 }
4380
4381 let argcnt = arg_func.params().len() - res_func.params().len();
4382
4383 if !self.is_subtype_many(res_func.params(), &arg_func.params()[argcnt..])
4385 || arg_func.results().len() != res_func.results().len()
4386 || !self.is_subtype_many(arg_func.results(), res_func.results())
4387 {
4388 bail!(self.offset, "type mismatch in continuation types");
4389 }
4390
4391 self.pop_concrete_ref(true, argument_index)?;
4393
4394 for &ty in arg_func.params().iter().take(argcnt).rev() {
4396 self.pop_operand(Some(ty))?;
4397 }
4398
4399 self.push_concrete_ref(false, result_index)?;
4401
4402 Ok(())
4403 }
4404 fn visit_suspend(&mut self, tag_index: u32) -> Self::Output {
4405 let ft = &self.tag_at(tag_index)?;
4406 for &ty in ft.params().iter().rev() {
4407 self.pop_operand(Some(ty))?;
4408 }
4409 for &ty in ft.results() {
4410 self.push_operand(ty)?;
4411 }
4412 Ok(())
4413 }
4414 fn visit_resume(&mut self, type_index: u32, table: ResumeTable) -> Self::Output {
4415 let ft = self.check_resume_table(table, type_index)?;
4417 self.pop_concrete_ref(true, type_index)?;
4418 for &ty in ft.params().iter().rev() {
4420 self.pop_operand(Some(ty))?;
4421 }
4422
4423 for &ty in ft.results() {
4425 self.push_operand(ty)?;
4426 }
4427 Ok(())
4428 }
4429 fn visit_resume_throw(
4430 &mut self,
4431 type_index: u32,
4432 tag_index: u32,
4433 table: ResumeTable,
4434 ) -> Self::Output {
4435 let ft = self.check_resume_table(table, type_index)?;
4437 let tag_ty = self.exception_tag_at(tag_index)?;
4439 if tag_ty.results().len() != 0 {
4440 bail!(self.offset, "type mismatch: non-empty tag result type")
4441 }
4442 self.pop_concrete_ref(true, type_index)?;
4443 for &ty in tag_ty.params().iter().rev() {
4445 self.pop_operand(Some(ty))?;
4446 }
4447
4448 for &ty in ft.results() {
4450 self.push_operand(ty)?;
4451 }
4452 Ok(())
4453 }
4454 fn visit_resume_throw_ref(&mut self, type_index: u32, table: ResumeTable) -> Self::Output {
4455 let ft = self.check_resume_table(table, type_index)?;
4456 self.pop_concrete_ref(true, type_index)?;
4457 self.pop_operand(Some(ValType::EXNREF))?;
4458
4459 for &ty in ft.results() {
4460 self.push_operand(ty)?
4461 }
4462 Ok(())
4463 }
4464 fn visit_switch(&mut self, type_index: u32, tag_index: u32) -> Self::Output {
4465 let cont_ty = self.cont_type_at(type_index)?;
4467 let func_ty = self.func_type_of_cont_type(cont_ty);
4468 let tag_ty = self.tag_at(tag_index)?;
4470 if tag_ty.params().len() != 0 {
4471 bail!(self.offset, "type mismatch: non-empty tag parameter type")
4472 }
4473 match func_ty.params().last() {
4475 Some(ValType::Ref(rt)) if rt.is_concrete_type_ref() => {
4476 let other_cont_id = rt
4477 .type_index()
4478 .unwrap()
4479 .unpack()
4480 .as_core_type_id()
4481 .expect("expected canonicalized index");
4482 let sub_ty = self.resources.sub_type_at_id(other_cont_id);
4483 let other_cont_ty =
4484 if let CompositeInnerType::Cont(cont) = &sub_ty.composite_type.inner {
4485 cont
4486 } else {
4487 bail!(self.offset, "non-continuation type");
4488 };
4489 let other_func_ty = self.func_type_of_cont_type(&other_cont_ty);
4490 if func_ty.results().len() != tag_ty.results().len()
4491 || !self.is_subtype_many(func_ty.results(), tag_ty.results())
4492 || other_func_ty.results().len() != tag_ty.results().len()
4493 || !self.is_subtype_many(tag_ty.results(), other_func_ty.results())
4494 {
4495 bail!(self.offset, "type mismatch in continuation types")
4496 }
4497
4498 self.pop_concrete_ref(true, type_index)?;
4500
4501 for &ty in func_ty.params().iter().rev().skip(1) {
4504 self.pop_operand(Some(ty))?;
4505 }
4506
4507 for &ty in other_func_ty.params() {
4509 self.push_operand(ty)?;
4510 }
4511 }
4512 Some(ty) => bail!(
4513 self.offset,
4514 "type mismatch: expected a continuation reference, found {}",
4515 ty_to_str(*ty)
4516 ),
4517 None => bail!(
4518 self.offset,
4519 "type mismatch: instruction requires a continuation reference"
4520 ),
4521 }
4522 Ok(())
4523 }
4524 fn visit_i64_add128(&mut self) -> Result<()> {
4525 self.check_binop128()
4526 }
4527 fn visit_i64_sub128(&mut self) -> Result<()> {
4528 self.check_binop128()
4529 }
4530 fn visit_i64_mul_wide_s(&mut self) -> Result<()> {
4531 self.check_i64_mul_wide()
4532 }
4533 fn visit_i64_mul_wide_u(&mut self) -> Result<()> {
4534 self.check_i64_mul_wide()
4535 }
4536
4537 fn visit_ref_get_desc(&mut self, type_index: u32) -> Self::Output {
4538 let (_, is_exact) = self.pop_concrete_or_exact_ref(true, type_index)?;
4539 match self.sub_type_at(type_index)?.composite_type.descriptor_idx {
4540 Some(descriptor_idx) => {
4541 let ref_ty = if is_exact {
4542 RefType::exact(false, descriptor_idx)
4543 } else {
4544 RefType::concrete(false, descriptor_idx)
4545 };
4546 self.push_operand(ref_ty)
4547 }
4548 None => bail!(self.offset, "expected type with descriptor"),
4549 }
4550 }
4551
4552 fn visit_ref_cast_desc_eq_non_null(&mut self, heap_type: HeapType) -> Self::Output {
4553 self.check_ref_cast_desc_eq(false, heap_type)
4554 }
4555 fn visit_ref_cast_desc_eq_nullable(&mut self, heap_type: HeapType) -> Self::Output {
4556 self.check_ref_cast_desc_eq(true, heap_type)
4557 }
4558 fn visit_br_on_cast_desc_eq(
4559 &mut self,
4560 relative_depth: u32,
4561 mut from_ref_type: RefType,
4562 mut to_ref_type: RefType,
4563 ) -> Self::Output {
4564 let described_ty = to_ref_type.heap_type();
4565
4566 self.resources
4567 .check_ref_type(&mut from_ref_type, self.offset)?;
4568 self.resources
4569 .check_ref_type(&mut to_ref_type, self.offset)?;
4570
4571 self.check_br_on_cast_type_hierarchy(from_ref_type, to_ref_type)?;
4572
4573 self.check_maybe_exact_descriptor_ref(described_ty)?;
4574
4575 let (block_ty, frame_kind) = self.jump(relative_depth)?;
4576 let mut label_types = self.label_types(block_ty, frame_kind)?;
4577
4578 match label_types.next_back() {
4579 Some(label_ty) if self.resources.is_subtype(to_ref_type.into(), label_ty) => {
4580 self.pop_operand(Some(from_ref_type.into()))?;
4581 }
4582 Some(label_ty) => bail!(
4583 self.offset,
4584 "type mismatch: casting to type {to_ref_type}, but it does not match \
4585 label result type {label_ty}"
4586 ),
4587 None => bail!(
4588 self.offset,
4589 "type mismatch: br_on_cast to label with empty types, must have a reference type"
4590 ),
4591 };
4592
4593 self.pop_push_label_types(label_types)?;
4594 let diff_ty = RefType::difference(from_ref_type, to_ref_type);
4595 self.push_operand(diff_ty)?;
4596 Ok(())
4597 }
4598 fn visit_br_on_cast_desc_eq_fail(
4599 &mut self,
4600 relative_depth: u32,
4601 mut from_ref_type: RefType,
4602 mut to_ref_type: RefType,
4603 ) -> Self::Output {
4604 let described_ty = to_ref_type.heap_type();
4605
4606 self.resources
4607 .check_ref_type(&mut from_ref_type, self.offset)?;
4608 self.resources
4609 .check_ref_type(&mut to_ref_type, self.offset)?;
4610
4611 self.check_br_on_cast_type_hierarchy(from_ref_type, to_ref_type)?;
4612
4613 self.check_maybe_exact_descriptor_ref(described_ty)?;
4614
4615 let (block_ty, frame_kind) = self.jump(relative_depth)?;
4616 let mut label_tys = self.label_types(block_ty, frame_kind)?;
4617
4618 let diff_ty = RefType::difference(from_ref_type, to_ref_type);
4619 match label_tys.next_back() {
4620 Some(label_ty) if self.resources.is_subtype(diff_ty.into(), label_ty) => {
4621 self.pop_operand(Some(from_ref_type.into()))?;
4622 }
4623 Some(label_ty) => bail!(
4624 self.offset,
4625 "type mismatch: expected label result type {label_ty}, found {diff_ty}"
4626 ),
4627 None => bail!(
4628 self.offset,
4629 "type mismatch: expected a reference type, found nothing"
4630 ),
4631 }
4632
4633 self.pop_push_label_types(label_tys)?;
4634 self.push_operand(to_ref_type)?;
4635 Ok(())
4636 }
4637}
4638
4639#[derive(Clone, Debug)]
4640enum Either<A, B> {
4641 A(A),
4642 B(B),
4643}
4644
4645impl<A, B> Iterator for Either<A, B>
4646where
4647 A: Iterator,
4648 B: Iterator<Item = A::Item>,
4649{
4650 type Item = A::Item;
4651 fn next(&mut self) -> Option<A::Item> {
4652 match self {
4653 Either::A(a) => a.next(),
4654 Either::B(b) => b.next(),
4655 }
4656 }
4657}
4658
4659impl<A, B> DoubleEndedIterator for Either<A, B>
4660where
4661 A: DoubleEndedIterator,
4662 B: DoubleEndedIterator<Item = A::Item>,
4663{
4664 fn next_back(&mut self) -> Option<A::Item> {
4665 match self {
4666 Either::A(a) => a.next_back(),
4667 Either::B(b) => b.next_back(),
4668 }
4669 }
4670}
4671
4672impl<A, B> ExactSizeIterator for Either<A, B>
4673where
4674 A: ExactSizeIterator,
4675 B: ExactSizeIterator<Item = A::Item>,
4676{
4677 fn len(&self) -> usize {
4678 match self {
4679 Either::A(a) => a.len(),
4680 Either::B(b) => b.len(),
4681 }
4682 }
4683}
4684
4685trait PreciseIterator: ExactSizeIterator + DoubleEndedIterator + Clone + core::fmt::Debug {}
4686impl<T: ExactSizeIterator + DoubleEndedIterator + Clone + core::fmt::Debug> PreciseIterator for T {}
4687
4688impl Locals {
4689 fn define(&mut self, count: u32, ty: ValType) -> bool {
4695 if count == 0 {
4696 return true;
4697 }
4698 let vacant_first = MAX_LOCALS_TO_TRACK.saturating_sub(self.num_locals);
4699 match self.num_locals.checked_add(count) {
4700 Some(num_locals) if num_locals > MAX_WASM_FUNCTION_LOCALS => return false,
4701 None => return false,
4702 Some(num_locals) => self.num_locals = num_locals,
4703 };
4704 let push_to_first = cmp::min(vacant_first, count);
4705 self.first
4706 .extend(iter::repeat(ty).take(push_to_first as usize));
4707 let num_uncached = count - push_to_first;
4708 if num_uncached > 0 {
4709 let max_uncached_idx = self.num_locals - 1;
4710 self.uncached.push((max_uncached_idx, ty));
4711 }
4712 true
4713 }
4714
4715 pub(super) fn len_locals(&self) -> u32 {
4717 self.num_locals
4718 }
4719
4720 #[inline]
4722 pub(super) fn get(&self, idx: u32) -> Option<ValType> {
4723 match self.first.get(idx as usize) {
4724 Some(ty) => Some(*ty),
4725 None => self.get_bsearch(idx),
4726 }
4727 }
4728
4729 fn get_bsearch(&self, idx: u32) -> Option<ValType> {
4730 match self.uncached.binary_search_by_key(&idx, |(idx, _)| *idx) {
4731 Err(i) if i == self.uncached.len() => None,
4734
4735 Ok(i) | Err(i) => Some(self.uncached[i].1),
4741 }
4742 }
4743}
4744
4745impl<R> ModuleArity for WasmProposalValidator<'_, '_, R>
4746where
4747 R: WasmModuleResources,
4748{
4749 fn tag_type_arity(&self, at: u32) -> Option<(u32, u32)> {
4750 self.0
4751 .resources
4752 .tag_at(at)
4753 .map(|x| (x.params().len() as u32, x.results().len() as u32))
4754 }
4755
4756 fn type_index_of_function(&self, function_idx: u32) -> Option<u32> {
4757 self.0.resources.type_index_of_function(function_idx)
4758 }
4759
4760 fn sub_type_at(&self, type_idx: u32) -> Option<&SubType> {
4761 Some(self.0.sub_type_at(type_idx).ok()?)
4762 }
4763
4764 fn func_type_of_cont_type(&self, c: &ContType) -> Option<&FuncType> {
4765 Some(self.0.func_type_of_cont_type(c))
4766 }
4767
4768 fn sub_type_of_ref_type(&self, rt: &RefType) -> Option<&SubType> {
4769 let id = rt.type_index()?.as_core_type_id()?;
4770 Some(self.0.resources.sub_type_at_id(id))
4771 }
4772
4773 fn control_stack_height(&self) -> u32 {
4774 self.0.control.len() as u32
4775 }
4776
4777 fn label_block(&self, depth: u32) -> Option<(BlockType, FrameKind)> {
4778 self.0.jump(depth).ok()
4779 }
4780}
4781
4782impl<R> FrameStack for WasmProposalValidator<'_, '_, R>
4783where
4784 R: WasmModuleResources,
4785{
4786 fn current_frame(&self) -> Option<FrameKind> {
4787 Some(self.0.control.last()?.kind)
4788 }
4789}