1 /* Copyright 2019 Mozilla Foundation
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 use core::cmp::min;
17 use core::result;
18 use std::str;
19 use std::vec::Vec;
20 
21 use crate::primitives::{
22     FuncType, GlobalType, MemoryImmediate, MemoryType, Operator, SIMDLaneIndex, TableType, Type,
23     TypeOrFuncType,
24 };
25 
26 /// Test if `subtype` is a subtype of `supertype`.
is_subtype_supertype(subtype: Type, supertype: Type) -> bool27 pub(crate) fn is_subtype_supertype(subtype: Type, supertype: Type) -> bool {
28     match supertype {
29         Type::AnyRef => {
30             subtype == Type::AnyRef || subtype == Type::AnyFunc || subtype == Type::Null
31         }
32         Type::AnyFunc => subtype == Type::AnyFunc || subtype == Type::Null,
33         _ => subtype == supertype,
34     }
35 }
36 
37 #[derive(Debug)]
38 struct BlockState {
39     start_types: Vec<Type>,
40     return_types: Vec<Type>,
41     stack_starts_at: usize,
42     jump_to_top: bool,
43     is_else_allowed: bool,
44     is_dead_code: bool,
45     polymorphic_values: Option<usize>,
46 }
47 
48 impl BlockState {
is_stack_polymorphic(&self) -> bool49     fn is_stack_polymorphic(&self) -> bool {
50         self.polymorphic_values.is_some()
51     }
52 }
53 
54 #[derive(Debug)]
55 struct FuncState {
56     local_types: Vec<Type>,
57     blocks: Vec<BlockState>,
58     stack_types: Vec<Type>,
59     end_function: bool,
60 }
61 
62 impl FuncState {
block_at(&self, depth: usize) -> &BlockState63     fn block_at(&self, depth: usize) -> &BlockState {
64         assert!(depth < self.blocks.len());
65         &self.blocks[self.blocks.len() - 1 - depth]
66     }
last_block(&self) -> &BlockState67     fn last_block(&self) -> &BlockState {
68         self.blocks.last().unwrap()
69     }
assert_stack_type_at(&self, index: usize, expected: Type) -> bool70     fn assert_stack_type_at(&self, index: usize, expected: Type) -> bool {
71         let stack_starts_at = self.last_block().stack_starts_at;
72         if self.last_block().is_stack_polymorphic()
73             && stack_starts_at + index >= self.stack_types.len()
74         {
75             return true;
76         }
77         assert!(stack_starts_at + index < self.stack_types.len());
78         is_subtype_supertype(
79             self.stack_types[self.stack_types.len() - 1 - index],
80             expected,
81         )
82     }
assert_block_stack_len(&self, depth: usize, minimal_len: usize) -> bool83     fn assert_block_stack_len(&self, depth: usize, minimal_len: usize) -> bool {
84         assert!(depth < self.blocks.len());
85         let blocks_end = self.blocks.len();
86         let block_offset = blocks_end - 1 - depth;
87         for i in block_offset..blocks_end {
88             if self.blocks[i].is_stack_polymorphic() {
89                 return true;
90             }
91         }
92         let block_starts_at = self.blocks[block_offset].stack_starts_at;
93         self.stack_types.len() >= block_starts_at + minimal_len
94     }
assert_last_block_stack_len_exact(&self, len: usize) -> bool95     fn assert_last_block_stack_len_exact(&self, len: usize) -> bool {
96         let block_starts_at = self.last_block().stack_starts_at;
97         if self.last_block().is_stack_polymorphic() {
98             let polymorphic_values = self.last_block().polymorphic_values.unwrap();
99             self.stack_types.len() + polymorphic_values <= block_starts_at + len
100         } else {
101             self.stack_types.len() == block_starts_at + len
102         }
103     }
remove_frame_stack_types(&mut self, remove_count: usize) -> OperatorValidatorResult<()>104     fn remove_frame_stack_types(&mut self, remove_count: usize) -> OperatorValidatorResult<()> {
105         if remove_count == 0 {
106             return Ok(());
107         }
108         let last_block = self.blocks.last_mut().unwrap();
109         if last_block.is_stack_polymorphic() {
110             let len = self.stack_types.len();
111             let remove_non_polymorphic = len
112                 .checked_sub(last_block.stack_starts_at)
113                 .ok_or("invalid block signature")?
114                 .min(remove_count);
115             self.stack_types.truncate(len - remove_non_polymorphic);
116             let polymorphic_values = last_block.polymorphic_values.unwrap();
117             let remove_polymorphic = min(remove_count - remove_non_polymorphic, polymorphic_values);
118             last_block.polymorphic_values = Some(polymorphic_values - remove_polymorphic);
119         } else {
120             assert!(self.stack_types.len() >= last_block.stack_starts_at + remove_count);
121             let keep = self.stack_types.len() - remove_count;
122             self.stack_types.truncate(keep);
123         }
124         Ok(())
125     }
push_block( &mut self, ty: TypeOrFuncType, block_type: BlockType, resources: &dyn WasmModuleResources, ) -> OperatorValidatorResult<()>126     fn push_block(
127         &mut self,
128         ty: TypeOrFuncType,
129         block_type: BlockType,
130         resources: &dyn WasmModuleResources,
131     ) -> OperatorValidatorResult<()> {
132         let (start_types, return_types) = match ty {
133             TypeOrFuncType::Type(Type::EmptyBlockType) => (vec![], vec![]),
134             TypeOrFuncType::Type(ty) => (vec![], vec![ty]),
135             TypeOrFuncType::FuncType(idx) => {
136                 let ty = &resources.types()[idx as usize];
137                 (ty.params.clone().into_vec(), ty.returns.clone().into_vec())
138             }
139         };
140         if block_type == BlockType::If {
141             let last_block = self.blocks.last().unwrap();
142             if !last_block.is_stack_polymorphic()
143                 || self.stack_types.len() > last_block.stack_starts_at
144             {
145                 self.stack_types.pop();
146             }
147             assert!(self.stack_types.len() >= last_block.stack_starts_at);
148         }
149         for (i, ty) in start_types.iter().rev().enumerate() {
150             if !self.assert_stack_type_at(i, *ty) {
151                 return Err("stack operand type mismatch");
152             }
153         }
154         let stack_starts_at = self.stack_types.len() - start_types.len();
155         self.blocks.push(BlockState {
156             start_types,
157             return_types,
158             stack_starts_at,
159             jump_to_top: block_type == BlockType::Loop,
160             is_else_allowed: block_type == BlockType::If,
161             is_dead_code: false,
162             polymorphic_values: None,
163         });
164         Ok(())
165     }
pop_block(&mut self)166     fn pop_block(&mut self) {
167         assert!(self.blocks.len() > 1);
168         let last_block = self.blocks.pop().unwrap();
169         if last_block.is_stack_polymorphic() {
170             assert!(
171                 self.stack_types.len()
172                     <= last_block.return_types.len() + last_block.stack_starts_at
173             );
174         } else {
175             assert!(
176                 self.stack_types.len()
177                     == last_block.return_types.len() + last_block.stack_starts_at
178             );
179         }
180         let keep = last_block.stack_starts_at;
181         self.stack_types.truncate(keep);
182         self.stack_types.extend_from_slice(&last_block.return_types);
183     }
reset_block(&mut self)184     fn reset_block(&mut self) {
185         assert!(self.last_block().is_else_allowed);
186         let last_block = self.blocks.last_mut().unwrap();
187         let keep = last_block.stack_starts_at;
188         self.stack_types.truncate(keep);
189         self.stack_types
190             .extend(last_block.start_types.iter().cloned());
191         last_block.is_else_allowed = false;
192         last_block.polymorphic_values = None;
193     }
change_frame(&mut self, remove_count: usize) -> OperatorValidatorResult<()>194     fn change_frame(&mut self, remove_count: usize) -> OperatorValidatorResult<()> {
195         self.remove_frame_stack_types(remove_count)
196     }
change_frame_with_type( &mut self, remove_count: usize, ty: Type, ) -> OperatorValidatorResult<()>197     fn change_frame_with_type(
198         &mut self,
199         remove_count: usize,
200         ty: Type,
201     ) -> OperatorValidatorResult<()> {
202         self.remove_frame_stack_types(remove_count)?;
203         self.stack_types.push(ty);
204         Ok(())
205     }
change_frame_with_types( &mut self, remove_count: usize, new_items: &[Type], ) -> OperatorValidatorResult<()>206     fn change_frame_with_types(
207         &mut self,
208         remove_count: usize,
209         new_items: &[Type],
210     ) -> OperatorValidatorResult<()> {
211         self.remove_frame_stack_types(remove_count)?;
212         if new_items.is_empty() {
213             return Ok(());
214         }
215         self.stack_types.extend_from_slice(new_items);
216         Ok(())
217     }
change_frame_to_exact_types_from(&mut self, depth: usize) -> OperatorValidatorResult<()>218     fn change_frame_to_exact_types_from(&mut self, depth: usize) -> OperatorValidatorResult<()> {
219         let types = self.block_at(depth).return_types.clone();
220         let last_block = self.blocks.last_mut().unwrap();
221         let keep = last_block.stack_starts_at;
222         self.stack_types.truncate(keep);
223         self.stack_types.extend_from_slice(&types);
224         last_block.polymorphic_values = None;
225         Ok(())
226     }
change_frame_after_select(&mut self, ty: Option<Type>) -> OperatorValidatorResult<()>227     fn change_frame_after_select(&mut self, ty: Option<Type>) -> OperatorValidatorResult<()> {
228         self.remove_frame_stack_types(3)?;
229         if ty.is_none() {
230             let last_block = self.blocks.last_mut().unwrap();
231             assert!(last_block.is_stack_polymorphic());
232             last_block.polymorphic_values = Some(last_block.polymorphic_values.unwrap() + 1);
233             return Ok(());
234         }
235         self.stack_types.push(ty.unwrap());
236         Ok(())
237     }
start_dead_code(&mut self)238     fn start_dead_code(&mut self) {
239         let last_block = self.blocks.last_mut().unwrap();
240         let keep = last_block.stack_starts_at;
241         self.stack_types.truncate(keep);
242         last_block.is_dead_code = true;
243         last_block.polymorphic_values = Some(0);
244     }
end_function(&mut self)245     fn end_function(&mut self) {
246         self.end_function = true;
247     }
248 }
249 
250 #[derive(Copy, Clone, PartialEq, Eq)]
251 enum BlockType {
252     Block,
253     Loop,
254     If,
255 }
256 
257 pub trait WasmModuleResources {
types(&self) -> &[FuncType]258     fn types(&self) -> &[FuncType];
tables(&self) -> &[TableType]259     fn tables(&self) -> &[TableType];
memories(&self) -> &[MemoryType]260     fn memories(&self) -> &[MemoryType];
globals(&self) -> &[GlobalType]261     fn globals(&self) -> &[GlobalType];
func_type_indices(&self) -> &[u32]262     fn func_type_indices(&self) -> &[u32];
element_count(&self) -> u32263     fn element_count(&self) -> u32;
data_count(&self) -> u32264     fn data_count(&self) -> u32;
265 }
266 
267 pub enum FunctionEnd {
268     No,
269     Yes,
270 }
271 
272 type OperatorValidatorResult<T> = result::Result<T, &'static str>;
273 
274 #[derive(Copy, Clone, Debug)]
275 pub struct OperatorValidatorConfig {
276     pub enable_threads: bool,
277     pub enable_reference_types: bool,
278     pub enable_simd: bool,
279     pub enable_bulk_memory: bool,
280     pub enable_multi_value: bool,
281 
282     #[cfg(feature = "deterministic")]
283     pub deterministic_only: bool,
284 }
285 
286 pub(crate) const DEFAULT_OPERATOR_VALIDATOR_CONFIG: OperatorValidatorConfig =
287     OperatorValidatorConfig {
288         enable_threads: false,
289         enable_reference_types: false,
290         enable_simd: false,
291         enable_bulk_memory: false,
292         enable_multi_value: false,
293 
294         #[cfg(feature = "deterministic")]
295         deterministic_only: true,
296     };
297 
298 #[derive(Debug)]
299 pub(crate) struct OperatorValidator {
300     func_state: FuncState,
301     config: OperatorValidatorConfig,
302 }
303 
304 impl OperatorValidator {
new( func_type: &FuncType, locals: &[(u32, Type)], config: OperatorValidatorConfig, ) -> OperatorValidator305     pub fn new(
306         func_type: &FuncType,
307         locals: &[(u32, Type)],
308         config: OperatorValidatorConfig,
309     ) -> OperatorValidator {
310         let mut local_types = Vec::new();
311         local_types.extend_from_slice(&*func_type.params);
312         for local in locals {
313             for _ in 0..local.0 {
314                 local_types.push(local.1);
315             }
316         }
317 
318         let mut blocks = Vec::new();
319         let mut last_returns = Vec::new();
320         last_returns.extend_from_slice(&*func_type.returns);
321         blocks.push(BlockState {
322             start_types: vec![],
323             return_types: last_returns,
324             stack_starts_at: 0,
325             jump_to_top: false,
326             is_else_allowed: false,
327             is_dead_code: false,
328             polymorphic_values: None,
329         });
330 
331         OperatorValidator {
332             func_state: FuncState {
333                 local_types,
334                 blocks,
335                 stack_types: Vec::new(),
336                 end_function: false,
337             },
338             config,
339         }
340     }
341 
is_dead_code(&self) -> bool342     pub fn is_dead_code(&self) -> bool {
343         self.func_state.last_block().is_dead_code
344     }
345 
check_frame_size(&self, require_count: usize) -> OperatorValidatorResult<()>346     fn check_frame_size(&self, require_count: usize) -> OperatorValidatorResult<()> {
347         if !self.func_state.assert_block_stack_len(0, require_count) {
348             Err("not enough operands")
349         } else {
350             Ok(())
351         }
352     }
353 
check_operands_1(&self, operand: Type) -> OperatorValidatorResult<()>354     fn check_operands_1(&self, operand: Type) -> OperatorValidatorResult<()> {
355         self.check_frame_size(1)?;
356         if !self.func_state.assert_stack_type_at(0, operand) {
357             return Err("stack operand type mismatch");
358         }
359         Ok(())
360     }
361 
check_operands_2(&self, operand1: Type, operand2: Type) -> OperatorValidatorResult<()>362     fn check_operands_2(&self, operand1: Type, operand2: Type) -> OperatorValidatorResult<()> {
363         self.check_frame_size(2)?;
364         if !self.func_state.assert_stack_type_at(1, operand1) {
365             return Err("stack operand type mismatch");
366         }
367         if !self.func_state.assert_stack_type_at(0, operand2) {
368             return Err("stack operand type mismatch");
369         }
370         Ok(())
371     }
372 
check_operands(&self, expected_types: &[Type]) -> OperatorValidatorResult<()>373     fn check_operands(&self, expected_types: &[Type]) -> OperatorValidatorResult<()> {
374         let len = expected_types.len();
375         self.check_frame_size(len)?;
376         for i in 0..len {
377             if !self
378                 .func_state
379                 .assert_stack_type_at(len - 1 - i, expected_types[i])
380             {
381                 return Err("stack operand type mismatch");
382             }
383         }
384         Ok(())
385     }
386 
check_block_return_types( &self, block: &BlockState, reserve_items: usize, ) -> OperatorValidatorResult<()>387     fn check_block_return_types(
388         &self,
389         block: &BlockState,
390         reserve_items: usize,
391     ) -> OperatorValidatorResult<()> {
392         if !self.config.enable_multi_value && block.return_types.len() > 1 {
393             return Err("blocks, loops, and ifs may only return at most one \
394                         value when multi-value is not enabled");
395         }
396         let len = block.return_types.len();
397         for i in 0..len {
398             if !self
399                 .func_state
400                 .assert_stack_type_at(len - 1 - i + reserve_items, block.return_types[i])
401             {
402                 return Err("stack item type does not match block item type");
403             }
404         }
405         Ok(())
406     }
407 
check_block_return(&self) -> OperatorValidatorResult<()>408     fn check_block_return(&self) -> OperatorValidatorResult<()> {
409         let len = self.func_state.last_block().return_types.len();
410         if !self.func_state.assert_last_block_stack_len_exact(len) {
411             return Err("stack size does not match block type");
412         }
413         self.check_block_return_types(self.func_state.last_block(), 0)
414     }
415 
check_jump_from_block( &self, relative_depth: u32, reserve_items: usize, ) -> OperatorValidatorResult<()>416     fn check_jump_from_block(
417         &self,
418         relative_depth: u32,
419         reserve_items: usize,
420     ) -> OperatorValidatorResult<()> {
421         if relative_depth as usize >= self.func_state.blocks.len() {
422             return Err("invalid block depth");
423         }
424         let block = self.func_state.block_at(relative_depth as usize);
425         if block.jump_to_top {
426             if !self.func_state.assert_block_stack_len(0, reserve_items) {
427                 return Err("stack size does not match target loop type");
428             }
429             return Ok(());
430         }
431 
432         let len = block.return_types.len();
433         if !self
434             .func_state
435             .assert_block_stack_len(0, len + reserve_items)
436         {
437             return Err("stack size does not match target block type");
438         }
439         self.check_block_return_types(block, reserve_items)
440     }
441 
match_block_return(&self, depth1: u32, depth2: u32) -> OperatorValidatorResult<()>442     fn match_block_return(&self, depth1: u32, depth2: u32) -> OperatorValidatorResult<()> {
443         if depth1 as usize >= self.func_state.blocks.len() {
444             return Err("invalid block depth");
445         }
446         if depth2 as usize >= self.func_state.blocks.len() {
447             return Err("invalid block depth");
448         }
449         let block1 = self.func_state.block_at(depth1 as usize);
450         let block2 = self.func_state.block_at(depth2 as usize);
451         let return_types1 = &block1.return_types;
452         let return_types2 = &block2.return_types;
453         if block1.jump_to_top || block2.jump_to_top {
454             if block1.jump_to_top {
455                 if !block2.jump_to_top && !return_types2.is_empty() {
456                     return Err("block types do not match");
457                 }
458             } else if !return_types1.is_empty() {
459                 return Err("block types do not match");
460             }
461         } else if *return_types1 != *return_types2 {
462             return Err("block types do not match");
463         }
464         Ok(())
465     }
466 
check_memory_index( &self, memory_index: u32, resources: &dyn WasmModuleResources, ) -> OperatorValidatorResult<()>467     fn check_memory_index(
468         &self,
469         memory_index: u32,
470         resources: &dyn WasmModuleResources,
471     ) -> OperatorValidatorResult<()> {
472         if memory_index as usize >= resources.memories().len() {
473             return Err("no linear memories are present");
474         }
475         Ok(())
476     }
477 
check_shared_memory_index( &self, memory_index: u32, resources: &dyn WasmModuleResources, ) -> OperatorValidatorResult<()>478     fn check_shared_memory_index(
479         &self,
480         memory_index: u32,
481         resources: &dyn WasmModuleResources,
482     ) -> OperatorValidatorResult<()> {
483         if memory_index as usize >= resources.memories().len() {
484             return Err("no linear memories are present");
485         }
486         if !resources.memories()[memory_index as usize].shared {
487             return Err("atomic accesses require shared memory");
488         }
489         Ok(())
490     }
491 
check_memarg( &self, memarg: &MemoryImmediate, max_align: u32, resources: &dyn WasmModuleResources, ) -> OperatorValidatorResult<()>492     fn check_memarg(
493         &self,
494         memarg: &MemoryImmediate,
495         max_align: u32,
496         resources: &dyn WasmModuleResources,
497     ) -> OperatorValidatorResult<()> {
498         self.check_memory_index(0, resources)?;
499         let align = memarg.flags;
500         if align > max_align {
501             return Err("align is required to be at most the number of accessed bytes");
502         }
503         Ok(())
504     }
505 
506     #[cfg(feature = "deterministic")]
check_non_deterministic_enabled(&self) -> OperatorValidatorResult<()>507     fn check_non_deterministic_enabled(&self) -> OperatorValidatorResult<()> {
508         if !self.config.deterministic_only {
509             return Err("deterministic_only support is not enabled");
510         }
511         Ok(())
512     }
513 
514     #[inline(always)]
515     #[cfg(not(feature = "deterministic"))]
check_non_deterministic_enabled(&self) -> OperatorValidatorResult<()>516     fn check_non_deterministic_enabled(&self) -> OperatorValidatorResult<()> {
517         Ok(())
518     }
519 
check_threads_enabled(&self) -> OperatorValidatorResult<()>520     fn check_threads_enabled(&self) -> OperatorValidatorResult<()> {
521         if !self.config.enable_threads {
522             return Err("threads support is not enabled");
523         }
524         Ok(())
525     }
526 
check_reference_types_enabled(&self) -> OperatorValidatorResult<()>527     fn check_reference_types_enabled(&self) -> OperatorValidatorResult<()> {
528         if !self.config.enable_reference_types {
529             return Err("reference types support is not enabled");
530         }
531         Ok(())
532     }
533 
check_simd_enabled(&self) -> OperatorValidatorResult<()>534     fn check_simd_enabled(&self) -> OperatorValidatorResult<()> {
535         if !self.config.enable_simd {
536             return Err("SIMD support is not enabled");
537         }
538         Ok(())
539     }
540 
check_bulk_memory_enabled(&self) -> OperatorValidatorResult<()>541     fn check_bulk_memory_enabled(&self) -> OperatorValidatorResult<()> {
542         if !self.config.enable_bulk_memory {
543             return Err("bulk memory support is not enabled");
544         }
545         Ok(())
546     }
547 
check_shared_memarg_wo_align( &self, _: &MemoryImmediate, resources: &dyn WasmModuleResources, ) -> OperatorValidatorResult<()>548     fn check_shared_memarg_wo_align(
549         &self,
550         _: &MemoryImmediate,
551         resources: &dyn WasmModuleResources,
552     ) -> OperatorValidatorResult<()> {
553         self.check_shared_memory_index(0, resources)?;
554         Ok(())
555     }
556 
check_simd_lane_index(&self, index: SIMDLaneIndex, max: u8) -> OperatorValidatorResult<()>557     fn check_simd_lane_index(&self, index: SIMDLaneIndex, max: u8) -> OperatorValidatorResult<()> {
558         if index >= max {
559             return Err("SIMD index out of bounds");
560         }
561         Ok(())
562     }
563 
check_block_type( &self, ty: TypeOrFuncType, resources: &dyn WasmModuleResources, ) -> OperatorValidatorResult<()>564     fn check_block_type(
565         &self,
566         ty: TypeOrFuncType,
567         resources: &dyn WasmModuleResources,
568     ) -> OperatorValidatorResult<()> {
569         match ty {
570             TypeOrFuncType::Type(Type::EmptyBlockType)
571             | TypeOrFuncType::Type(Type::I32)
572             | TypeOrFuncType::Type(Type::I64)
573             | TypeOrFuncType::Type(Type::F32)
574             | TypeOrFuncType::Type(Type::F64) => Ok(()),
575             TypeOrFuncType::Type(Type::V128) => self.check_simd_enabled(),
576             TypeOrFuncType::FuncType(idx) => {
577                 let idx = idx as usize;
578                 let types = resources.types();
579                 if idx >= types.len() {
580                     return Err("type index out of bounds");
581                 }
582                 let ty = &types[idx];
583                 if !self.config.enable_multi_value {
584                     if ty.returns.len() > 1 {
585                         return Err("blocks, loops, and ifs may only return at most one \
586                                     value when multi-value is not enabled");
587                     }
588                     if ty.params.len() > 0 {
589                         return Err("blocks, loops, and ifs accept no parameters \
590                                     when multi-value is not enabled");
591                     }
592                 }
593                 Ok(())
594             }
595             _ => Err("invalid block return type"),
596         }
597     }
598 
check_block_params( &self, ty: TypeOrFuncType, resources: &dyn WasmModuleResources, skip: usize, ) -> OperatorValidatorResult<()>599     fn check_block_params(
600         &self,
601         ty: TypeOrFuncType,
602         resources: &dyn WasmModuleResources,
603         skip: usize,
604     ) -> OperatorValidatorResult<()> {
605         if let TypeOrFuncType::FuncType(idx) = ty {
606             let func_ty = &resources.types()[idx as usize];
607             let len = func_ty.params.len();
608             self.check_frame_size(len + skip)?;
609             for i in 0..len {
610                 if !self
611                     .func_state
612                     .assert_stack_type_at(len - 1 - i + skip, func_ty.params[i])
613                 {
614                     return Err("stack operand type mismatch for block");
615                 }
616             }
617         }
618         Ok(())
619     }
620 
check_select(&self) -> OperatorValidatorResult<Option<Type>>621     fn check_select(&self) -> OperatorValidatorResult<Option<Type>> {
622         self.check_frame_size(3)?;
623         let func_state = &self.func_state;
624         let last_block = func_state.last_block();
625         Ok(if last_block.is_stack_polymorphic() {
626             match func_state.stack_types.len() - last_block.stack_starts_at {
627                 0 => None,
628                 1 => {
629                     self.check_operands_1(Type::I32)?;
630                     None
631                 }
632                 2 => {
633                     self.check_operands_1(Type::I32)?;
634                     Some(func_state.stack_types[func_state.stack_types.len() - 2])
635                 }
636                 _ => {
637                     let ty = func_state.stack_types[func_state.stack_types.len() - 3];
638                     self.check_operands_2(ty, Type::I32)?;
639                     Some(ty)
640                 }
641             }
642         } else {
643             let ty = func_state.stack_types[func_state.stack_types.len() - 3];
644             self.check_operands_2(ty, Type::I32)?;
645             Some(ty)
646         })
647     }
648 
process_operator( &mut self, operator: &Operator, resources: &dyn WasmModuleResources, ) -> OperatorValidatorResult<FunctionEnd>649     pub(crate) fn process_operator(
650         &mut self,
651         operator: &Operator,
652         resources: &dyn WasmModuleResources,
653     ) -> OperatorValidatorResult<FunctionEnd> {
654         if self.func_state.end_function {
655             return Err("unexpected operator");
656         }
657         match *operator {
658             Operator::Unreachable => self.func_state.start_dead_code(),
659             Operator::Nop => (),
660             Operator::Block { ty } => {
661                 self.check_block_type(ty, resources)?;
662                 self.check_block_params(ty, resources, 0)?;
663                 self.func_state
664                     .push_block(ty, BlockType::Block, resources)?;
665             }
666             Operator::Loop { ty } => {
667                 self.check_block_type(ty, resources)?;
668                 self.check_block_params(ty, resources, 0)?;
669                 self.func_state.push_block(ty, BlockType::Loop, resources)?;
670             }
671             Operator::If { ty } => {
672                 self.check_block_type(ty, resources)?;
673                 self.check_operands_1(Type::I32)?;
674                 self.check_block_params(ty, resources, 1)?;
675                 self.func_state.push_block(ty, BlockType::If, resources)?;
676             }
677             Operator::Else => {
678                 if !self.func_state.last_block().is_else_allowed {
679                     return Err("unexpected else: if block is not started");
680                 }
681                 self.check_block_return()?;
682                 self.func_state.reset_block()
683             }
684             Operator::End => {
685                 self.check_block_return()?;
686                 if self.func_state.blocks.len() == 1 {
687                     self.func_state.end_function();
688                     return Ok(FunctionEnd::Yes);
689                 }
690                 if {
691                     let last_block = &self.func_state.last_block();
692                     last_block.is_else_allowed && !last_block.return_types.is_empty()
693                 } {
694                     return Err("else is expected: if block has type");
695                 }
696                 self.func_state.pop_block()
697             }
698             Operator::Br { relative_depth } => {
699                 self.check_jump_from_block(relative_depth, 0)?;
700                 self.func_state.start_dead_code()
701             }
702             Operator::BrIf { relative_depth } => {
703                 self.check_operands_1(Type::I32)?;
704                 self.check_jump_from_block(relative_depth, 1)?;
705                 if self.func_state.last_block().is_stack_polymorphic() {
706                     self.func_state
707                         .change_frame_to_exact_types_from(relative_depth as usize)?;
708                 } else {
709                     self.func_state.change_frame(1)?;
710                 }
711             }
712             Operator::BrTable { ref table } => {
713                 self.check_operands_1(Type::I32)?;
714                 let mut depth0: Option<u32> = None;
715                 for relative_depth in table {
716                     if depth0.is_none() {
717                         self.check_jump_from_block(relative_depth, 1)?;
718                         depth0 = Some(relative_depth);
719                         continue;
720                     }
721                     self.match_block_return(relative_depth, depth0.unwrap())?;
722                 }
723                 self.func_state.start_dead_code()
724             }
725             Operator::Return => {
726                 let depth = (self.func_state.blocks.len() - 1) as u32;
727                 self.check_jump_from_block(depth, 0)?;
728                 self.func_state.start_dead_code()
729             }
730             Operator::Call { function_index } => {
731                 if function_index as usize >= resources.func_type_indices().len() {
732                     return Err("function index out of bounds");
733                 }
734                 let type_index = resources.func_type_indices()[function_index as usize];
735                 let ty = &resources.types()[type_index as usize];
736                 self.check_operands(&ty.params)?;
737                 self.func_state
738                     .change_frame_with_types(ty.params.len(), &ty.returns)?;
739             }
740             Operator::CallIndirect { index, table_index } => {
741                 if table_index as usize >= resources.tables().len() {
742                     return Err("table index out of bounds");
743                 }
744                 if index as usize >= resources.types().len() {
745                     return Err("type index out of bounds");
746                 }
747                 let ty = &resources.types()[index as usize];
748                 let mut types = Vec::with_capacity(ty.params.len() + 1);
749                 types.extend_from_slice(&ty.params);
750                 types.push(Type::I32);
751                 self.check_operands(&types)?;
752                 self.func_state
753                     .change_frame_with_types(ty.params.len() + 1, &ty.returns)?;
754             }
755             Operator::Drop => {
756                 self.check_frame_size(1)?;
757                 self.func_state.change_frame(1)?;
758             }
759             Operator::Select => {
760                 let ty = self.check_select()?;
761                 self.func_state.change_frame_after_select(ty)?;
762             }
763             Operator::GetLocal { local_index } => {
764                 if local_index as usize >= self.func_state.local_types.len() {
765                     return Err("local index out of bounds");
766                 }
767                 let local_type = self.func_state.local_types[local_index as usize];
768                 self.func_state.change_frame_with_type(0, local_type)?;
769             }
770             Operator::SetLocal { local_index } => {
771                 if local_index as usize >= self.func_state.local_types.len() {
772                     return Err("local index out of bounds");
773                 }
774                 let local_type = self.func_state.local_types[local_index as usize];
775                 self.check_operands_1(local_type)?;
776                 self.func_state.change_frame(1)?;
777             }
778             Operator::TeeLocal { local_index } => {
779                 if local_index as usize >= self.func_state.local_types.len() {
780                     return Err("local index out of bounds");
781                 }
782                 let local_type = self.func_state.local_types[local_index as usize];
783                 self.check_operands_1(local_type)?;
784                 self.func_state.change_frame_with_type(1, local_type)?;
785             }
786             Operator::GetGlobal { global_index } => {
787                 if global_index as usize >= resources.globals().len() {
788                     return Err("global index out of bounds");
789                 }
790                 let ty = &resources.globals()[global_index as usize];
791                 self.func_state.change_frame_with_type(0, ty.content_type)?;
792             }
793             Operator::SetGlobal { global_index } => {
794                 if global_index as usize >= resources.globals().len() {
795                     return Err("global index out of bounds");
796                 }
797                 let ty = &resources.globals()[global_index as usize];
798                 if !ty.mutable {
799                     return Err("global expected to be mutable");
800                 }
801                 self.check_operands_1(ty.content_type)?;
802                 self.func_state.change_frame(1)?;
803             }
804             Operator::I32Load { ref memarg } => {
805                 self.check_memarg(memarg, 2, resources)?;
806                 self.check_operands_1(Type::I32)?;
807                 self.func_state.change_frame_with_type(1, Type::I32)?;
808             }
809             Operator::I64Load { ref memarg } => {
810                 self.check_memarg(memarg, 3, resources)?;
811                 self.check_operands_1(Type::I32)?;
812                 self.func_state.change_frame_with_type(1, Type::I64)?;
813             }
814             Operator::F32Load { ref memarg } => {
815                 self.check_non_deterministic_enabled()?;
816                 self.check_memarg(memarg, 2, resources)?;
817                 self.check_operands_1(Type::I32)?;
818                 self.func_state.change_frame_with_type(1, Type::F32)?;
819             }
820             Operator::F64Load { ref memarg } => {
821                 self.check_non_deterministic_enabled()?;
822                 self.check_memarg(memarg, 3, resources)?;
823                 self.check_operands_1(Type::I32)?;
824                 self.func_state.change_frame_with_type(1, Type::F64)?;
825             }
826             Operator::I32Load8S { ref memarg } => {
827                 self.check_memarg(memarg, 0, resources)?;
828                 self.check_operands_1(Type::I32)?;
829                 self.func_state.change_frame_with_type(1, Type::I32)?;
830             }
831             Operator::I32Load8U { ref memarg } => {
832                 self.check_memarg(memarg, 0, resources)?;
833                 self.check_operands_1(Type::I32)?;
834                 self.func_state.change_frame_with_type(1, Type::I32)?;
835             }
836             Operator::I32Load16S { ref memarg } => {
837                 self.check_memarg(memarg, 1, resources)?;
838                 self.check_operands_1(Type::I32)?;
839                 self.func_state.change_frame_with_type(1, Type::I32)?;
840             }
841             Operator::I32Load16U { ref memarg } => {
842                 self.check_memarg(memarg, 1, resources)?;
843                 self.check_operands_1(Type::I32)?;
844                 self.func_state.change_frame_with_type(1, Type::I32)?;
845             }
846             Operator::I64Load8S { ref memarg } => {
847                 self.check_memarg(memarg, 0, resources)?;
848                 self.check_operands_1(Type::I32)?;
849                 self.func_state.change_frame_with_type(1, Type::I64)?;
850             }
851             Operator::I64Load8U { ref memarg } => {
852                 self.check_memarg(memarg, 0, resources)?;
853                 self.check_operands_1(Type::I32)?;
854                 self.func_state.change_frame_with_type(1, Type::I64)?;
855             }
856             Operator::I64Load16S { ref memarg } => {
857                 self.check_memarg(memarg, 1, resources)?;
858                 self.check_operands_1(Type::I32)?;
859                 self.func_state.change_frame_with_type(1, Type::I64)?;
860             }
861             Operator::I64Load16U { ref memarg } => {
862                 self.check_memarg(memarg, 1, resources)?;
863                 self.check_operands_1(Type::I32)?;
864                 self.func_state.change_frame_with_type(1, Type::I64)?;
865             }
866             Operator::I64Load32S { ref memarg } => {
867                 self.check_memarg(memarg, 2, resources)?;
868                 self.check_operands_1(Type::I32)?;
869                 self.func_state.change_frame_with_type(1, Type::I64)?;
870             }
871             Operator::I64Load32U { ref memarg } => {
872                 self.check_memarg(memarg, 2, resources)?;
873                 self.check_operands_1(Type::I32)?;
874                 self.func_state.change_frame_with_type(1, Type::I64)?;
875             }
876             Operator::I32Store { ref memarg } => {
877                 self.check_memarg(memarg, 2, resources)?;
878                 self.check_operands_2(Type::I32, Type::I32)?;
879                 self.func_state.change_frame(2)?;
880             }
881             Operator::I64Store { ref memarg } => {
882                 self.check_memarg(memarg, 3, resources)?;
883                 self.check_operands_2(Type::I32, Type::I64)?;
884                 self.func_state.change_frame(2)?;
885             }
886             Operator::F32Store { ref memarg } => {
887                 self.check_non_deterministic_enabled()?;
888                 self.check_memarg(memarg, 2, resources)?;
889                 self.check_operands_2(Type::I32, Type::F32)?;
890                 self.func_state.change_frame(2)?;
891             }
892             Operator::F64Store { ref memarg } => {
893                 self.check_non_deterministic_enabled()?;
894                 self.check_memarg(memarg, 3, resources)?;
895                 self.check_operands_2(Type::I32, Type::F64)?;
896                 self.func_state.change_frame(2)?;
897             }
898             Operator::I32Store8 { ref memarg } => {
899                 self.check_memarg(memarg, 0, resources)?;
900                 self.check_operands_2(Type::I32, Type::I32)?;
901                 self.func_state.change_frame(2)?;
902             }
903             Operator::I32Store16 { ref memarg } => {
904                 self.check_memarg(memarg, 1, resources)?;
905                 self.check_operands_2(Type::I32, Type::I32)?;
906                 self.func_state.change_frame(2)?;
907             }
908             Operator::I64Store8 { ref memarg } => {
909                 self.check_memarg(memarg, 0, resources)?;
910                 self.check_operands_2(Type::I32, Type::I64)?;
911                 self.func_state.change_frame(2)?;
912             }
913             Operator::I64Store16 { ref memarg } => {
914                 self.check_memarg(memarg, 1, resources)?;
915                 self.check_operands_2(Type::I32, Type::I64)?;
916                 self.func_state.change_frame(2)?;
917             }
918             Operator::I64Store32 { ref memarg } => {
919                 self.check_memarg(memarg, 2, resources)?;
920                 self.check_operands_2(Type::I32, Type::I64)?;
921                 self.func_state.change_frame(2)?;
922             }
923             Operator::MemorySize {
924                 reserved: memory_index,
925             } => {
926                 self.check_memory_index(memory_index, resources)?;
927                 self.func_state.change_frame_with_type(0, Type::I32)?;
928             }
929             Operator::MemoryGrow {
930                 reserved: memory_index,
931             } => {
932                 self.check_memory_index(memory_index, resources)?;
933                 self.check_operands_1(Type::I32)?;
934                 self.func_state.change_frame_with_type(1, Type::I32)?;
935             }
936             Operator::I32Const { .. } => self.func_state.change_frame_with_type(0, Type::I32)?,
937             Operator::I64Const { .. } => self.func_state.change_frame_with_type(0, Type::I64)?,
938             Operator::F32Const { .. } => {
939                 self.check_non_deterministic_enabled()?;
940                 self.func_state.change_frame_with_type(0, Type::F32)?;
941             }
942             Operator::F64Const { .. } => {
943                 self.check_non_deterministic_enabled()?;
944                 self.func_state.change_frame_with_type(0, Type::F64)?;
945             }
946             Operator::I32Eqz => {
947                 self.check_operands_1(Type::I32)?;
948                 self.func_state.change_frame_with_type(1, Type::I32)?;
949             }
950             Operator::I32Eq
951             | Operator::I32Ne
952             | Operator::I32LtS
953             | Operator::I32LtU
954             | Operator::I32GtS
955             | Operator::I32GtU
956             | Operator::I32LeS
957             | Operator::I32LeU
958             | Operator::I32GeS
959             | Operator::I32GeU => {
960                 self.check_operands_2(Type::I32, Type::I32)?;
961                 self.func_state.change_frame_with_type(2, Type::I32)?;
962             }
963             Operator::I64Eqz => {
964                 self.check_operands_1(Type::I64)?;
965                 self.func_state.change_frame_with_type(1, Type::I32)?;
966             }
967             Operator::I64Eq
968             | Operator::I64Ne
969             | Operator::I64LtS
970             | Operator::I64LtU
971             | Operator::I64GtS
972             | Operator::I64GtU
973             | Operator::I64LeS
974             | Operator::I64LeU
975             | Operator::I64GeS
976             | Operator::I64GeU => {
977                 self.check_operands_2(Type::I64, Type::I64)?;
978                 self.func_state.change_frame_with_type(2, Type::I32)?;
979             }
980             Operator::F32Eq
981             | Operator::F32Ne
982             | Operator::F32Lt
983             | Operator::F32Gt
984             | Operator::F32Le
985             | Operator::F32Ge => {
986                 self.check_non_deterministic_enabled()?;
987                 self.check_operands_2(Type::F32, Type::F32)?;
988                 self.func_state.change_frame_with_type(2, Type::I32)?;
989             }
990             Operator::F64Eq
991             | Operator::F64Ne
992             | Operator::F64Lt
993             | Operator::F64Gt
994             | Operator::F64Le
995             | Operator::F64Ge => {
996                 self.check_non_deterministic_enabled()?;
997                 self.check_operands_2(Type::F64, Type::F64)?;
998                 self.func_state.change_frame_with_type(2, Type::I32)?;
999             }
1000             Operator::I32Clz | Operator::I32Ctz | Operator::I32Popcnt => {
1001                 self.check_operands_1(Type::I32)?;
1002                 self.func_state.change_frame_with_type(1, Type::I32)?;
1003             }
1004             Operator::I32Add
1005             | Operator::I32Sub
1006             | Operator::I32Mul
1007             | Operator::I32DivS
1008             | Operator::I32DivU
1009             | Operator::I32RemS
1010             | Operator::I32RemU
1011             | Operator::I32And
1012             | Operator::I32Or
1013             | Operator::I32Xor
1014             | Operator::I32Shl
1015             | Operator::I32ShrS
1016             | Operator::I32ShrU
1017             | Operator::I32Rotl
1018             | Operator::I32Rotr => {
1019                 self.check_operands_2(Type::I32, Type::I32)?;
1020                 self.func_state.change_frame_with_type(2, Type::I32)?;
1021             }
1022             Operator::I64Clz | Operator::I64Ctz | Operator::I64Popcnt => {
1023                 self.check_operands_1(Type::I64)?;
1024                 self.func_state.change_frame_with_type(1, Type::I64)?;
1025             }
1026             Operator::I64Add
1027             | Operator::I64Sub
1028             | Operator::I64Mul
1029             | Operator::I64DivS
1030             | Operator::I64DivU
1031             | Operator::I64RemS
1032             | Operator::I64RemU
1033             | Operator::I64And
1034             | Operator::I64Or
1035             | Operator::I64Xor
1036             | Operator::I64Shl
1037             | Operator::I64ShrS
1038             | Operator::I64ShrU
1039             | Operator::I64Rotl
1040             | Operator::I64Rotr => {
1041                 self.check_operands_2(Type::I64, Type::I64)?;
1042                 self.func_state.change_frame_with_type(2, Type::I64)?;
1043             }
1044             Operator::F32Abs
1045             | Operator::F32Neg
1046             | Operator::F32Ceil
1047             | Operator::F32Floor
1048             | Operator::F32Trunc
1049             | Operator::F32Nearest
1050             | Operator::F32Sqrt => {
1051                 self.check_non_deterministic_enabled()?;
1052                 self.check_operands_1(Type::F32)?;
1053                 self.func_state.change_frame_with_type(1, Type::F32)?;
1054             }
1055             Operator::F32Add
1056             | Operator::F32Sub
1057             | Operator::F32Mul
1058             | Operator::F32Div
1059             | Operator::F32Min
1060             | Operator::F32Max
1061             | Operator::F32Copysign => {
1062                 self.check_non_deterministic_enabled()?;
1063                 self.check_operands_2(Type::F32, Type::F32)?;
1064                 self.func_state.change_frame_with_type(2, Type::F32)?;
1065             }
1066             Operator::F64Abs
1067             | Operator::F64Neg
1068             | Operator::F64Ceil
1069             | Operator::F64Floor
1070             | Operator::F64Trunc
1071             | Operator::F64Nearest
1072             | Operator::F64Sqrt => {
1073                 self.check_non_deterministic_enabled()?;
1074                 self.check_operands_1(Type::F64)?;
1075                 self.func_state.change_frame_with_type(1, Type::F64)?;
1076             }
1077             Operator::F64Add
1078             | Operator::F64Sub
1079             | Operator::F64Mul
1080             | Operator::F64Div
1081             | Operator::F64Min
1082             | Operator::F64Max
1083             | Operator::F64Copysign => {
1084                 self.check_non_deterministic_enabled()?;
1085                 self.check_operands_2(Type::F64, Type::F64)?;
1086                 self.func_state.change_frame_with_type(2, Type::F64)?;
1087             }
1088             Operator::I32WrapI64 => {
1089                 self.check_operands_1(Type::I64)?;
1090                 self.func_state.change_frame_with_type(1, Type::I32)?;
1091             }
1092             Operator::I32TruncSF32 | Operator::I32TruncUF32 => {
1093                 self.check_operands_1(Type::F32)?;
1094                 self.func_state.change_frame_with_type(1, Type::I32)?;
1095             }
1096             Operator::I32TruncSF64 | Operator::I32TruncUF64 => {
1097                 self.check_operands_1(Type::F64)?;
1098                 self.func_state.change_frame_with_type(1, Type::I32)?;
1099             }
1100             Operator::I64ExtendSI32 | Operator::I64ExtendUI32 => {
1101                 self.check_operands_1(Type::I32)?;
1102                 self.func_state.change_frame_with_type(1, Type::I64)?;
1103             }
1104             Operator::I64TruncSF32 | Operator::I64TruncUF32 => {
1105                 self.check_operands_1(Type::F32)?;
1106                 self.func_state.change_frame_with_type(1, Type::I64)?;
1107             }
1108             Operator::I64TruncSF64 | Operator::I64TruncUF64 => {
1109                 self.check_operands_1(Type::F64)?;
1110                 self.func_state.change_frame_with_type(1, Type::I64)?;
1111             }
1112             Operator::F32ConvertSI32 | Operator::F32ConvertUI32 => {
1113                 self.check_non_deterministic_enabled()?;
1114                 self.check_operands_1(Type::I32)?;
1115                 self.func_state.change_frame_with_type(1, Type::F32)?;
1116             }
1117             Operator::F32ConvertSI64 | Operator::F32ConvertUI64 => {
1118                 self.check_non_deterministic_enabled()?;
1119                 self.check_operands_1(Type::I64)?;
1120                 self.func_state.change_frame_with_type(1, Type::F32)?;
1121             }
1122             Operator::F32DemoteF64 => {
1123                 self.check_non_deterministic_enabled()?;
1124                 self.check_operands_1(Type::F64)?;
1125                 self.func_state.change_frame_with_type(1, Type::F32)?;
1126             }
1127             Operator::F64ConvertSI32 | Operator::F64ConvertUI32 => {
1128                 self.check_non_deterministic_enabled()?;
1129                 self.check_operands_1(Type::I32)?;
1130                 self.func_state.change_frame_with_type(1, Type::F64)?;
1131             }
1132             Operator::F64ConvertSI64 | Operator::F64ConvertUI64 => {
1133                 self.check_non_deterministic_enabled()?;
1134                 self.check_operands_1(Type::I64)?;
1135                 self.func_state.change_frame_with_type(1, Type::F64)?;
1136             }
1137             Operator::F64PromoteF32 => {
1138                 self.check_non_deterministic_enabled()?;
1139                 self.check_operands_1(Type::F32)?;
1140                 self.func_state.change_frame_with_type(1, Type::F64)?;
1141             }
1142             Operator::I32ReinterpretF32 => {
1143                 self.check_operands_1(Type::F32)?;
1144                 self.func_state.change_frame_with_type(1, Type::I32)?;
1145             }
1146             Operator::I64ReinterpretF64 => {
1147                 self.check_operands_1(Type::F64)?;
1148                 self.func_state.change_frame_with_type(1, Type::I64)?;
1149             }
1150             Operator::F32ReinterpretI32 => {
1151                 self.check_non_deterministic_enabled()?;
1152                 self.check_operands_1(Type::I32)?;
1153                 self.func_state.change_frame_with_type(1, Type::F32)?;
1154             }
1155             Operator::F64ReinterpretI64 => {
1156                 self.check_non_deterministic_enabled()?;
1157                 self.check_operands_1(Type::I64)?;
1158                 self.func_state.change_frame_with_type(1, Type::F64)?;
1159             }
1160             Operator::I32TruncSSatF32 | Operator::I32TruncUSatF32 => {
1161                 self.check_operands_1(Type::F32)?;
1162                 self.func_state.change_frame_with_type(1, Type::I32)?;
1163             }
1164             Operator::I32TruncSSatF64 | Operator::I32TruncUSatF64 => {
1165                 self.check_operands_1(Type::F64)?;
1166                 self.func_state.change_frame_with_type(1, Type::I32)?;
1167             }
1168             Operator::I64TruncSSatF32 | Operator::I64TruncUSatF32 => {
1169                 self.check_operands_1(Type::F32)?;
1170                 self.func_state.change_frame_with_type(1, Type::I64)?;
1171             }
1172             Operator::I64TruncSSatF64 | Operator::I64TruncUSatF64 => {
1173                 self.check_operands_1(Type::F64)?;
1174                 self.func_state.change_frame_with_type(1, Type::I64)?;
1175             }
1176             Operator::I32Extend16S | Operator::I32Extend8S => {
1177                 self.check_operands_1(Type::I32)?;
1178                 self.func_state.change_frame_with_type(1, Type::I32)?;
1179             }
1180 
1181             Operator::I64Extend32S | Operator::I64Extend16S | Operator::I64Extend8S => {
1182                 self.check_operands_1(Type::I64)?;
1183                 self.func_state.change_frame_with_type(1, Type::I64)?;
1184             }
1185 
1186             Operator::I32AtomicLoad { ref memarg }
1187             | Operator::I32AtomicLoad16U { ref memarg }
1188             | Operator::I32AtomicLoad8U { ref memarg } => {
1189                 self.check_threads_enabled()?;
1190                 self.check_shared_memarg_wo_align(memarg, resources)?;
1191                 self.check_operands_1(Type::I32)?;
1192                 self.func_state.change_frame_with_type(1, Type::I32)?;
1193             }
1194             Operator::I64AtomicLoad { ref memarg }
1195             | Operator::I64AtomicLoad32U { ref memarg }
1196             | Operator::I64AtomicLoad16U { ref memarg }
1197             | Operator::I64AtomicLoad8U { ref memarg } => {
1198                 self.check_threads_enabled()?;
1199                 self.check_shared_memarg_wo_align(memarg, resources)?;
1200                 self.check_operands_1(Type::I32)?;
1201                 self.func_state.change_frame_with_type(1, Type::I64)?;
1202             }
1203             Operator::I32AtomicStore { ref memarg }
1204             | Operator::I32AtomicStore16 { ref memarg }
1205             | Operator::I32AtomicStore8 { ref memarg } => {
1206                 self.check_threads_enabled()?;
1207                 self.check_shared_memarg_wo_align(memarg, resources)?;
1208                 self.check_operands_2(Type::I32, Type::I32)?;
1209                 self.func_state.change_frame(2)?;
1210             }
1211             Operator::I64AtomicStore { ref memarg }
1212             | Operator::I64AtomicStore32 { ref memarg }
1213             | Operator::I64AtomicStore16 { ref memarg }
1214             | Operator::I64AtomicStore8 { ref memarg } => {
1215                 self.check_threads_enabled()?;
1216                 self.check_shared_memarg_wo_align(memarg, resources)?;
1217                 self.check_operands_2(Type::I32, Type::I64)?;
1218                 self.func_state.change_frame(2)?;
1219             }
1220             Operator::I32AtomicRmwAdd { ref memarg }
1221             | Operator::I32AtomicRmwSub { ref memarg }
1222             | Operator::I32AtomicRmwAnd { ref memarg }
1223             | Operator::I32AtomicRmwOr { ref memarg }
1224             | Operator::I32AtomicRmwXor { ref memarg }
1225             | Operator::I32AtomicRmw16UAdd { ref memarg }
1226             | Operator::I32AtomicRmw16USub { ref memarg }
1227             | Operator::I32AtomicRmw16UAnd { ref memarg }
1228             | Operator::I32AtomicRmw16UOr { ref memarg }
1229             | Operator::I32AtomicRmw16UXor { ref memarg }
1230             | Operator::I32AtomicRmw8UAdd { ref memarg }
1231             | Operator::I32AtomicRmw8USub { ref memarg }
1232             | Operator::I32AtomicRmw8UAnd { ref memarg }
1233             | Operator::I32AtomicRmw8UOr { ref memarg }
1234             | Operator::I32AtomicRmw8UXor { ref memarg } => {
1235                 self.check_threads_enabled()?;
1236                 self.check_shared_memarg_wo_align(memarg, resources)?;
1237                 self.check_operands_2(Type::I32, Type::I32)?;
1238                 self.func_state.change_frame_with_type(2, Type::I32)?;
1239             }
1240             Operator::I64AtomicRmwAdd { ref memarg }
1241             | Operator::I64AtomicRmwSub { ref memarg }
1242             | Operator::I64AtomicRmwAnd { ref memarg }
1243             | Operator::I64AtomicRmwOr { ref memarg }
1244             | Operator::I64AtomicRmwXor { ref memarg }
1245             | Operator::I64AtomicRmw32UAdd { ref memarg }
1246             | Operator::I64AtomicRmw32USub { ref memarg }
1247             | Operator::I64AtomicRmw32UAnd { ref memarg }
1248             | Operator::I64AtomicRmw32UOr { ref memarg }
1249             | Operator::I64AtomicRmw32UXor { ref memarg }
1250             | Operator::I64AtomicRmw16UAdd { ref memarg }
1251             | Operator::I64AtomicRmw16USub { ref memarg }
1252             | Operator::I64AtomicRmw16UAnd { ref memarg }
1253             | Operator::I64AtomicRmw16UOr { ref memarg }
1254             | Operator::I64AtomicRmw16UXor { ref memarg }
1255             | Operator::I64AtomicRmw8UAdd { ref memarg }
1256             | Operator::I64AtomicRmw8USub { ref memarg }
1257             | Operator::I64AtomicRmw8UAnd { ref memarg }
1258             | Operator::I64AtomicRmw8UOr { ref memarg }
1259             | Operator::I64AtomicRmw8UXor { ref memarg } => {
1260                 self.check_threads_enabled()?;
1261                 self.check_shared_memarg_wo_align(memarg, resources)?;
1262                 self.check_operands_2(Type::I32, Type::I64)?;
1263                 self.func_state.change_frame_with_type(2, Type::I64)?;
1264             }
1265             Operator::I32AtomicRmwXchg { ref memarg }
1266             | Operator::I32AtomicRmw16UXchg { ref memarg }
1267             | Operator::I32AtomicRmw8UXchg { ref memarg } => {
1268                 self.check_threads_enabled()?;
1269                 self.check_shared_memarg_wo_align(memarg, resources)?;
1270                 self.check_operands_2(Type::I32, Type::I32)?;
1271                 self.func_state.change_frame_with_type(2, Type::I32)?;
1272             }
1273             Operator::I32AtomicRmwCmpxchg { ref memarg }
1274             | Operator::I32AtomicRmw16UCmpxchg { ref memarg }
1275             | Operator::I32AtomicRmw8UCmpxchg { ref memarg } => {
1276                 self.check_threads_enabled()?;
1277                 self.check_shared_memarg_wo_align(memarg, resources)?;
1278                 self.check_operands(&[Type::I32, Type::I32, Type::I32])?;
1279                 self.func_state.change_frame_with_type(3, Type::I32)?;
1280             }
1281             Operator::I64AtomicRmwXchg { ref memarg }
1282             | Operator::I64AtomicRmw32UXchg { ref memarg }
1283             | Operator::I64AtomicRmw16UXchg { ref memarg }
1284             | Operator::I64AtomicRmw8UXchg { ref memarg } => {
1285                 self.check_threads_enabled()?;
1286                 self.check_shared_memarg_wo_align(memarg, resources)?;
1287                 self.check_operands_2(Type::I32, Type::I64)?;
1288                 self.func_state.change_frame_with_type(2, Type::I64)?;
1289             }
1290             Operator::I64AtomicRmwCmpxchg { ref memarg }
1291             | Operator::I64AtomicRmw32UCmpxchg { ref memarg }
1292             | Operator::I64AtomicRmw16UCmpxchg { ref memarg }
1293             | Operator::I64AtomicRmw8UCmpxchg { ref memarg } => {
1294                 self.check_threads_enabled()?;
1295                 self.check_shared_memarg_wo_align(memarg, resources)?;
1296                 self.check_operands(&[Type::I32, Type::I64, Type::I64])?;
1297                 self.func_state.change_frame_with_type(3, Type::I64)?;
1298             }
1299             Operator::Wake { ref memarg } => {
1300                 self.check_threads_enabled()?;
1301                 self.check_shared_memarg_wo_align(memarg, resources)?;
1302                 self.check_operands_2(Type::I32, Type::I32)?;
1303                 self.func_state.change_frame_with_type(2, Type::I32)?;
1304             }
1305             Operator::I32Wait { ref memarg } => {
1306                 self.check_threads_enabled()?;
1307                 self.check_shared_memarg_wo_align(memarg, resources)?;
1308                 self.check_operands(&[Type::I32, Type::I32, Type::I64])?;
1309                 self.func_state.change_frame_with_type(3, Type::I32)?;
1310             }
1311             Operator::I64Wait { ref memarg } => {
1312                 self.check_threads_enabled()?;
1313                 self.check_shared_memarg_wo_align(memarg, resources)?;
1314                 self.check_operands(&[Type::I32, Type::I64, Type::I64])?;
1315                 self.func_state.change_frame_with_type(3, Type::I32)?;
1316             }
1317             Operator::Fence { ref flags } => {
1318                 self.check_threads_enabled()?;
1319                 if *flags != 0 {
1320                     return Err("non-zero flags for fence not supported yet");
1321                 }
1322             }
1323             Operator::RefNull => {
1324                 self.check_reference_types_enabled()?;
1325                 self.func_state.change_frame_with_type(0, Type::Null)?;
1326             }
1327             Operator::RefIsNull => {
1328                 self.check_reference_types_enabled()?;
1329                 self.check_operands(&[Type::AnyRef])?;
1330                 self.func_state.change_frame_with_type(1, Type::I32)?;
1331             }
1332             Operator::V128Load { ref memarg } => {
1333                 self.check_simd_enabled()?;
1334                 self.check_memarg(memarg, 4, resources)?;
1335                 self.check_operands_1(Type::I32)?;
1336                 self.func_state.change_frame_with_type(1, Type::V128)?;
1337             }
1338             Operator::V128Store { ref memarg } => {
1339                 self.check_simd_enabled()?;
1340                 self.check_memarg(memarg, 4, resources)?;
1341                 self.check_operands_2(Type::I32, Type::V128)?;
1342                 self.func_state.change_frame(2)?;
1343             }
1344             Operator::V128Const { .. } => {
1345                 self.check_simd_enabled()?;
1346                 self.func_state.change_frame_with_type(0, Type::V128)?;
1347             }
1348             Operator::I8x16Splat | Operator::I16x8Splat | Operator::I32x4Splat => {
1349                 self.check_simd_enabled()?;
1350                 self.check_operands_1(Type::I32)?;
1351                 self.func_state.change_frame_with_type(1, Type::V128)?;
1352             }
1353             Operator::I64x2Splat => {
1354                 self.check_simd_enabled()?;
1355                 self.check_operands_1(Type::I64)?;
1356                 self.func_state.change_frame_with_type(1, Type::V128)?;
1357             }
1358             Operator::F32x4Splat => {
1359                 self.check_non_deterministic_enabled()?;
1360                 self.check_simd_enabled()?;
1361                 self.check_operands_1(Type::F32)?;
1362                 self.func_state.change_frame_with_type(1, Type::V128)?;
1363             }
1364             Operator::F64x2Splat => {
1365                 self.check_non_deterministic_enabled()?;
1366                 self.check_simd_enabled()?;
1367                 self.check_operands_1(Type::F64)?;
1368                 self.func_state.change_frame_with_type(1, Type::V128)?;
1369             }
1370             Operator::I8x16ExtractLaneS { lane } | Operator::I8x16ExtractLaneU { lane } => {
1371                 self.check_simd_enabled()?;
1372                 self.check_simd_lane_index(lane, 16)?;
1373                 self.check_operands_1(Type::V128)?;
1374                 self.func_state.change_frame_with_type(1, Type::I32)?;
1375             }
1376             Operator::I16x8ExtractLaneS { lane } | Operator::I16x8ExtractLaneU { lane } => {
1377                 self.check_simd_enabled()?;
1378                 self.check_simd_lane_index(lane, 8)?;
1379                 self.check_operands_1(Type::V128)?;
1380                 self.func_state.change_frame_with_type(1, Type::I32)?;
1381             }
1382             Operator::I32x4ExtractLane { lane } => {
1383                 self.check_simd_enabled()?;
1384                 self.check_simd_lane_index(lane, 4)?;
1385                 self.check_operands_1(Type::V128)?;
1386                 self.func_state.change_frame_with_type(1, Type::I32)?;
1387             }
1388             Operator::I8x16ReplaceLane { lane } => {
1389                 self.check_simd_enabled()?;
1390                 self.check_simd_lane_index(lane, 16)?;
1391                 self.check_operands_2(Type::V128, Type::I32)?;
1392                 self.func_state.change_frame_with_type(2, Type::V128)?;
1393             }
1394             Operator::I16x8ReplaceLane { lane } => {
1395                 self.check_simd_enabled()?;
1396                 self.check_simd_lane_index(lane, 8)?;
1397                 self.check_operands_2(Type::V128, Type::I32)?;
1398                 self.func_state.change_frame_with_type(2, Type::V128)?;
1399             }
1400             Operator::I32x4ReplaceLane { lane } => {
1401                 self.check_simd_enabled()?;
1402                 self.check_simd_lane_index(lane, 4)?;
1403                 self.check_operands_2(Type::V128, Type::I32)?;
1404                 self.func_state.change_frame_with_type(2, Type::V128)?;
1405             }
1406             Operator::I64x2ExtractLane { lane } => {
1407                 self.check_simd_enabled()?;
1408                 self.check_simd_lane_index(lane, 2)?;
1409                 self.check_operands_1(Type::V128)?;
1410                 self.func_state.change_frame_with_type(1, Type::I64)?;
1411             }
1412             Operator::I64x2ReplaceLane { lane } => {
1413                 self.check_simd_enabled()?;
1414                 self.check_simd_lane_index(lane, 2)?;
1415                 self.check_operands_2(Type::V128, Type::I64)?;
1416                 self.func_state.change_frame_with_type(2, Type::V128)?;
1417             }
1418             Operator::F32x4ExtractLane { lane } => {
1419                 self.check_non_deterministic_enabled()?;
1420                 self.check_simd_enabled()?;
1421                 self.check_simd_lane_index(lane, 4)?;
1422                 self.check_operands_1(Type::V128)?;
1423                 self.func_state.change_frame_with_type(1, Type::F32)?;
1424             }
1425             Operator::F32x4ReplaceLane { lane } => {
1426                 self.check_non_deterministic_enabled()?;
1427                 self.check_simd_enabled()?;
1428                 self.check_simd_lane_index(lane, 4)?;
1429                 self.check_operands_2(Type::V128, Type::F32)?;
1430                 self.func_state.change_frame_with_type(2, Type::V128)?;
1431             }
1432             Operator::F64x2ExtractLane { lane } => {
1433                 self.check_non_deterministic_enabled()?;
1434                 self.check_simd_enabled()?;
1435                 self.check_simd_lane_index(lane, 2)?;
1436                 self.check_operands_1(Type::V128)?;
1437                 self.func_state.change_frame_with_type(1, Type::F64)?;
1438             }
1439             Operator::F64x2ReplaceLane { lane } => {
1440                 self.check_non_deterministic_enabled()?;
1441                 self.check_simd_enabled()?;
1442                 self.check_simd_lane_index(lane, 2)?;
1443                 self.check_operands_2(Type::V128, Type::F64)?;
1444                 self.func_state.change_frame_with_type(2, Type::V128)?;
1445             }
1446             Operator::F32x4Eq
1447             | Operator::F32x4Ne
1448             | Operator::F32x4Lt
1449             | Operator::F32x4Gt
1450             | Operator::F32x4Le
1451             | Operator::F32x4Ge
1452             | Operator::F64x2Eq
1453             | Operator::F64x2Ne
1454             | Operator::F64x2Lt
1455             | Operator::F64x2Gt
1456             | Operator::F64x2Le
1457             | Operator::F64x2Ge
1458             | Operator::F32x4Add
1459             | Operator::F32x4Sub
1460             | Operator::F32x4Mul
1461             | Operator::F32x4Div
1462             | Operator::F32x4Min
1463             | Operator::F32x4Max
1464             | Operator::F64x2Add
1465             | Operator::F64x2Sub
1466             | Operator::F64x2Mul
1467             | Operator::F64x2Div
1468             | Operator::F64x2Min
1469             | Operator::F64x2Max => {
1470                 self.check_non_deterministic_enabled()?;
1471                 self.check_simd_enabled()?;
1472                 self.check_operands_2(Type::V128, Type::V128)?;
1473                 self.func_state.change_frame_with_type(2, Type::V128)?;
1474             }
1475             Operator::I8x16Eq
1476             | Operator::I8x16Ne
1477             | Operator::I8x16LtS
1478             | Operator::I8x16LtU
1479             | Operator::I8x16GtS
1480             | Operator::I8x16GtU
1481             | Operator::I8x16LeS
1482             | Operator::I8x16LeU
1483             | Operator::I8x16GeS
1484             | Operator::I8x16GeU
1485             | Operator::I16x8Eq
1486             | Operator::I16x8Ne
1487             | Operator::I16x8LtS
1488             | Operator::I16x8LtU
1489             | Operator::I16x8GtS
1490             | Operator::I16x8GtU
1491             | Operator::I16x8LeS
1492             | Operator::I16x8LeU
1493             | Operator::I16x8GeS
1494             | Operator::I16x8GeU
1495             | Operator::I32x4Eq
1496             | Operator::I32x4Ne
1497             | Operator::I32x4LtS
1498             | Operator::I32x4LtU
1499             | Operator::I32x4GtS
1500             | Operator::I32x4GtU
1501             | Operator::I32x4LeS
1502             | Operator::I32x4LeU
1503             | Operator::I32x4GeS
1504             | Operator::I32x4GeU
1505             | Operator::V128And
1506             | Operator::V128Or
1507             | Operator::V128Xor
1508             | Operator::I8x16Add
1509             | Operator::I8x16AddSaturateS
1510             | Operator::I8x16AddSaturateU
1511             | Operator::I8x16Sub
1512             | Operator::I8x16SubSaturateS
1513             | Operator::I8x16SubSaturateU
1514             | Operator::I8x16Mul
1515             | Operator::I16x8Add
1516             | Operator::I16x8AddSaturateS
1517             | Operator::I16x8AddSaturateU
1518             | Operator::I16x8Sub
1519             | Operator::I16x8SubSaturateS
1520             | Operator::I16x8SubSaturateU
1521             | Operator::I16x8Mul
1522             | Operator::I32x4Add
1523             | Operator::I32x4Sub
1524             | Operator::I32x4Mul
1525             | Operator::I64x2Add
1526             | Operator::I64x2Sub => {
1527                 self.check_simd_enabled()?;
1528                 self.check_operands_2(Type::V128, Type::V128)?;
1529                 self.func_state.change_frame_with_type(2, Type::V128)?;
1530             }
1531             Operator::F32x4Abs
1532             | Operator::F32x4Neg
1533             | Operator::F32x4Sqrt
1534             | Operator::F64x2Abs
1535             | Operator::F64x2Neg
1536             | Operator::F64x2Sqrt
1537             | Operator::F32x4ConvertSI32x4
1538             | Operator::F32x4ConvertUI32x4
1539             | Operator::F64x2ConvertSI64x2
1540             | Operator::F64x2ConvertUI64x2 => {
1541                 self.check_non_deterministic_enabled()?;
1542                 self.check_simd_enabled()?;
1543                 self.check_operands_1(Type::V128)?;
1544                 self.func_state.change_frame_with_type(1, Type::V128)?;
1545             }
1546             Operator::V128Not
1547             | Operator::I8x16Neg
1548             | Operator::I16x8Neg
1549             | Operator::I32x4Neg
1550             | Operator::I64x2Neg
1551             | Operator::I32x4TruncSF32x4Sat
1552             | Operator::I32x4TruncUF32x4Sat
1553             | Operator::I64x2TruncSF64x2Sat
1554             | Operator::I64x2TruncUF64x2Sat => {
1555                 self.check_simd_enabled()?;
1556                 self.check_operands_1(Type::V128)?;
1557                 self.func_state.change_frame_with_type(1, Type::V128)?;
1558             }
1559             Operator::V128Bitselect => {
1560                 self.check_simd_enabled()?;
1561                 self.check_operands(&[Type::V128, Type::V128, Type::V128])?;
1562                 self.func_state.change_frame_with_type(3, Type::V128)?;
1563             }
1564             Operator::I8x16AnyTrue
1565             | Operator::I8x16AllTrue
1566             | Operator::I16x8AnyTrue
1567             | Operator::I16x8AllTrue
1568             | Operator::I32x4AnyTrue
1569             | Operator::I32x4AllTrue
1570             | Operator::I64x2AnyTrue
1571             | Operator::I64x2AllTrue => {
1572                 self.check_simd_enabled()?;
1573                 self.check_operands_1(Type::V128)?;
1574                 self.func_state.change_frame_with_type(1, Type::I32)?;
1575             }
1576             Operator::I8x16Shl
1577             | Operator::I8x16ShrS
1578             | Operator::I8x16ShrU
1579             | Operator::I16x8Shl
1580             | Operator::I16x8ShrS
1581             | Operator::I16x8ShrU
1582             | Operator::I32x4Shl
1583             | Operator::I32x4ShrS
1584             | Operator::I32x4ShrU
1585             | Operator::I64x2Shl
1586             | Operator::I64x2ShrS
1587             | Operator::I64x2ShrU => {
1588                 self.check_simd_enabled()?;
1589                 self.check_operands_2(Type::V128, Type::I32)?;
1590                 self.func_state.change_frame_with_type(2, Type::V128)?;
1591             }
1592             Operator::V8x16Swizzle => {
1593                 self.check_simd_enabled()?;
1594                 self.check_operands_2(Type::V128, Type::V128)?;
1595                 self.func_state.change_frame_with_type(2, Type::V128)?;
1596             }
1597             Operator::V8x16Shuffle { ref lanes } => {
1598                 self.check_simd_enabled()?;
1599                 self.check_operands_2(Type::V128, Type::V128)?;
1600                 for i in lanes {
1601                     self.check_simd_lane_index(*i, 32)?;
1602                 }
1603                 self.func_state.change_frame_with_type(2, Type::V128)?;
1604             }
1605             Operator::I8x16LoadSplat { ref memarg }
1606             | Operator::I16x8LoadSplat { ref memarg }
1607             | Operator::I32x4LoadSplat { ref memarg }
1608             | Operator::I64x2LoadSplat { ref memarg } => {
1609                 self.check_simd_enabled()?;
1610                 self.check_memarg(memarg, 4, resources)?;
1611                 self.func_state.change_frame_with_type(1, Type::V128)?;
1612             }
1613 
1614             Operator::MemoryInit { segment } => {
1615                 self.check_bulk_memory_enabled()?;
1616                 if segment >= resources.data_count() {
1617                     return Err("segment index out of bounds");
1618                 }
1619                 self.check_memory_index(0, resources)?;
1620                 self.check_operands(&[Type::I32, Type::I32, Type::I32])?;
1621                 self.func_state.change_frame(3)?;
1622             }
1623             Operator::DataDrop { segment } => {
1624                 self.check_bulk_memory_enabled()?;
1625                 if segment >= resources.data_count() {
1626                     return Err("segment index out of bounds");
1627                 }
1628             }
1629             Operator::MemoryCopy | Operator::MemoryFill => {
1630                 self.check_bulk_memory_enabled()?;
1631                 self.check_memory_index(0, resources)?;
1632                 self.check_operands(&[Type::I32, Type::I32, Type::I32])?;
1633                 self.func_state.change_frame(3)?;
1634             }
1635             Operator::TableInit { segment } => {
1636                 self.check_bulk_memory_enabled()?;
1637                 if segment >= resources.element_count() {
1638                     return Err("segment index out of bounds");
1639                 }
1640                 if 0 >= resources.tables().len() {
1641                     return Err("table index out of bounds");
1642                 }
1643                 self.check_operands(&[Type::I32, Type::I32, Type::I32])?;
1644                 self.func_state.change_frame(3)?;
1645             }
1646             Operator::ElemDrop { segment } => {
1647                 self.check_bulk_memory_enabled()?;
1648                 if segment >= resources.element_count() {
1649                     return Err("segment index out of bounds");
1650                 }
1651             }
1652             Operator::TableCopy => {
1653                 self.check_bulk_memory_enabled()?;
1654                 if 0 >= resources.tables().len() {
1655                     return Err("table index out of bounds");
1656                 }
1657                 self.check_operands(&[Type::I32, Type::I32, Type::I32])?;
1658                 self.func_state.change_frame(3)?;
1659             }
1660             Operator::TableGet { table } => {
1661                 self.check_reference_types_enabled()?;
1662                 if table as usize >= resources.tables().len() {
1663                     return Err("table index out of bounds");
1664                 }
1665                 self.check_operands(&[Type::I32])?;
1666                 self.func_state.change_frame_with_type(1, Type::AnyRef)?;
1667             }
1668             Operator::TableSet { table } => {
1669                 self.check_reference_types_enabled()?;
1670                 if table as usize >= resources.tables().len() {
1671                     return Err("table index out of bounds");
1672                 }
1673                 self.check_operands(&[Type::I32, Type::AnyRef])?;
1674                 self.func_state.change_frame(2)?;
1675             }
1676             Operator::TableGrow { table } => {
1677                 self.check_reference_types_enabled()?;
1678                 if table as usize >= resources.tables().len() {
1679                     return Err("table index out of bounds");
1680                 }
1681                 self.check_operands(&[Type::I32])?;
1682                 self.func_state.change_frame_with_type(1, Type::I32)?;
1683             }
1684             Operator::TableSize { table } => {
1685                 self.check_reference_types_enabled()?;
1686                 if table as usize >= resources.tables().len() {
1687                     return Err("table index out of bounds");
1688                 }
1689                 self.func_state.change_frame_with_type(1, Type::I32)?;
1690             }
1691         }
1692         Ok(FunctionEnd::No)
1693     }
1694 
process_end_function(&self) -> OperatorValidatorResult<()>1695     pub(crate) fn process_end_function(&self) -> OperatorValidatorResult<()> {
1696         if !self.func_state.end_function {
1697             return Err("expected end of function");
1698         }
1699         Ok(())
1700     }
1701 }
1702