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 // The basic validation algorithm here is copied from the "Validation
17 // Algorithm" section of the WebAssembly specification -
18 // https://webassembly.github.io/spec/core/appendix/algorithm.html.
19 //
20 // That algorithm is followed pretty closely here, namely `push_operand`,
21 // `pop_operand`, `push_ctrl`, and `pop_ctrl`. If anything here is a bit
22 // confusing it's recomended to read over that section to see how it maps to
23 // the various methods here.
24
25 use crate::limits::MAX_WASM_FUNCTION_LOCALS;
26 use crate::primitives::{MemoryImmediate, Operator, SIMDLaneIndex, Type, TypeOrFuncType};
27 use crate::{BinaryReaderError, Result, WasmFeatures, WasmFuncType, WasmModuleResources};
28
29 /// A wrapper around a `BinaryReaderError` where the inner error's offset is a
30 /// temporary placeholder value. This can be converted into a proper
31 /// `BinaryReaderError` via the `set_offset` method, which replaces the
32 /// placeholder offset with an actual offset.
33 pub(crate) struct OperatorValidatorError(pub(crate) BinaryReaderError);
34
35 /// Create an `OperatorValidatorError` with a format string.
36 macro_rules! format_op_err {
37 ( $( $arg:expr ),* $(,)* ) => {
38 OperatorValidatorError::new(format!( $( $arg ),* ))
39 }
40 }
41
42 /// Early return an `Err(OperatorValidatorError)` with a format string.
43 macro_rules! bail_op_err {
44 ( $( $arg:expr ),* $(,)* ) => {
45 return Err(format_op_err!( $( $arg ),* ));
46 }
47 }
48
49 impl OperatorValidatorError {
50 /// Create a new `OperatorValidatorError` with a placeholder offset.
new(message: impl Into<String>) -> Self51 pub(crate) fn new(message: impl Into<String>) -> Self {
52 let offset = std::usize::MAX;
53 let e = BinaryReaderError::new(message, offset);
54 OperatorValidatorError(e)
55 }
56
57 /// Convert this `OperatorValidatorError` into a `BinaryReaderError` by
58 /// supplying an actual offset to replace the internal placeholder offset.
set_offset(mut self, offset: usize) -> BinaryReaderError59 pub(crate) fn set_offset(mut self, offset: usize) -> BinaryReaderError {
60 debug_assert_eq!(self.0.inner.offset, std::usize::MAX);
61 self.0.inner.offset = offset;
62 self.0
63 }
64 }
65
66 type OperatorValidatorResult<T> = std::result::Result<T, OperatorValidatorError>;
67
68 pub(crate) struct OperatorValidator {
69 // The total number of locals that this function contains
70 num_locals: u32,
71 // This is a "compressed" list of locals for this function. The list of
72 // locals are represented as a list of tuples. The second element is the
73 // type of the local, and the first element is monotonically increasing as
74 // you visit elements of this list. The first element is the maximum index
75 // of the local, after the previous index, of the type specified.
76 //
77 // This allows us to do a binary search on the list for a local's index for
78 // `local.{get,set,tee}`. We do a binary search for the index desired, and
79 // it either lies in a "hole" where the maximum index is specified later,
80 // or it's at the end of the list meaning it's out of bounds.
81 locals: Vec<(u32, Type)>,
82
83 // The `operands` is the current type stack, and the `control` list is the
84 // list of blocks that we're currently in.
85 pub(crate) operands: Vec<Option<Type>>,
86 control: Vec<Frame>,
87
88 // This is a list of flags for wasm features which are used to gate various
89 // instructions.
90 features: WasmFeatures,
91 }
92
93 // This structure corresponds to `ctrl_frame` as specified at in the validation
94 // appendix of the wasm spec
95 struct Frame {
96 // Indicator for what kind of instruction pushed this frame.
97 kind: FrameKind,
98 // The type signature of this frame, represented as a singular return type
99 // or a type index pointing into the module's types.
100 block_type: TypeOrFuncType,
101 // The index, below which, this frame cannot modify the operand stack.
102 height: usize,
103 // Whether this frame is unreachable so far.
104 unreachable: bool,
105 }
106
107 #[derive(PartialEq, Copy, Clone)]
108 enum FrameKind {
109 Block,
110 If,
111 Else,
112 Loop,
113 Try,
114 Catch,
115 CatchAll,
116 Unwind,
117 }
118
119 impl OperatorValidator {
new( ty: u32, offset: usize, features: &WasmFeatures, resources: &impl WasmModuleResources, ) -> Result<OperatorValidator>120 pub fn new(
121 ty: u32,
122 offset: usize,
123 features: &WasmFeatures,
124 resources: &impl WasmModuleResources,
125 ) -> Result<OperatorValidator> {
126 let locals = func_type_at(resources, ty)
127 .map_err(|e| e.set_offset(offset))?
128 .inputs()
129 .enumerate()
130 .map(|(i, ty)| (i as u32, ty))
131 .collect::<Vec<_>>();
132 Ok(OperatorValidator {
133 num_locals: locals.len() as u32,
134 locals,
135 operands: Vec::new(),
136 control: vec![Frame {
137 kind: FrameKind::Block,
138 block_type: TypeOrFuncType::FuncType(ty),
139 height: 0,
140 unreachable: false,
141 }],
142 features: *features,
143 })
144 }
145
define_locals(&mut self, offset: usize, count: u32, ty: Type) -> Result<()>146 pub fn define_locals(&mut self, offset: usize, count: u32, ty: Type) -> Result<()> {
147 self.features
148 .check_value_type(ty)
149 .map_err(|e| BinaryReaderError::new(e, offset))?;
150 if count == 0 {
151 return Ok(());
152 }
153 match self.num_locals.checked_add(count) {
154 Some(n) => self.num_locals = n,
155 None => return Err(BinaryReaderError::new("locals overflow", offset)),
156 }
157 if self.num_locals > (MAX_WASM_FUNCTION_LOCALS as u32) {
158 return Err(BinaryReaderError::new("locals exceed maximum", offset));
159 }
160 self.locals.push((self.num_locals - 1, ty));
161 Ok(())
162 }
163
164 /// Fetches the type for the local at `idx`, returning an error if it's out
165 /// of bounds.
local(&self, idx: u32) -> OperatorValidatorResult<Type>166 fn local(&self, idx: u32) -> OperatorValidatorResult<Type> {
167 match self.locals.binary_search_by_key(&idx, |(idx, _)| *idx) {
168 // If this index would be inserted at the end of the list, then the
169 // index is out of bounds and we return an error.
170 Err(i) if i == self.locals.len() => {
171 bail_op_err!("unknown local {}: local index out of bounds", idx)
172 }
173 // If `Ok` is returned we found the index exactly, or if `Err` is
174 // returned the position is the one which is the least index
175 // greater thatn `idx`, which is still the type of `idx` according
176 // to our "compressed" representation. In both cases we access the
177 // list at index `i`.
178 Ok(i) | Err(i) => Ok(self.locals[i].1),
179 }
180 }
181
182 /// Pushes a type onto the operand stack.
183 ///
184 /// This is used by instructions to represent a value that is pushed to the
185 /// operand stack. This can fail, but only if `Type` is feature gated.
186 /// Otherwise the push operation always succeeds.
push_operand(&mut self, ty: Type) -> OperatorValidatorResult<()>187 fn push_operand(&mut self, ty: Type) -> OperatorValidatorResult<()> {
188 self.features
189 .check_value_type(ty)
190 .map_err(OperatorValidatorError::new)?;
191 self.operands.push(Some(ty));
192 Ok(())
193 }
194
195 /// Attempts to pop a type from the operand stack.
196 ///
197 /// This function is used to remove types from the operand stack. The
198 /// `expected` argument can be used to indicate that a type is required, or
199 /// simply that something is needed to be popped.
200 ///
201 /// If `expected` is `Some(T)` then this will be guaranteed to return
202 /// `Some(T)`, and it will only return success if the current block is
203 /// unreachable or if `T` was found at the top of the operand stack.
204 ///
205 /// If `expected` is `None` then it indicates that something must be on the
206 /// operand stack, but it doesn't matter what's on the operand stack. This
207 /// is useful for polymorphic instructions like `select`.
208 ///
209 /// If `Some(T)` is returned then `T` was popped from the operand stack and
210 /// matches `expected`. If `None` is returned then it means that `None` was
211 /// expected and a type was successfully popped, but its exact type is
212 /// indeterminate because the current block is unreachable.
pop_operand(&mut self, expected: Option<Type>) -> OperatorValidatorResult<Option<Type>>213 fn pop_operand(&mut self, expected: Option<Type>) -> OperatorValidatorResult<Option<Type>> {
214 let control = self.control.last().unwrap();
215 let actual = if self.operands.len() == control.height {
216 if control.unreachable {
217 None
218 } else {
219 let desc = match expected {
220 Some(ty) => ty_to_str(ty),
221 None => "a type",
222 };
223 bail_op_err!("type mismatch: expected {} but nothing on stack", desc)
224 }
225 } else {
226 self.operands.pop().unwrap()
227 };
228 let actual_ty = match actual {
229 Some(ty) => ty,
230 None => return Ok(expected),
231 };
232 let expected_ty = match expected {
233 Some(ty) => ty,
234 None => return Ok(actual),
235 };
236 if actual_ty != expected_ty {
237 bail_op_err!(
238 "type mismatch: expected {}, found {}",
239 ty_to_str(expected_ty),
240 ty_to_str(actual_ty)
241 )
242 } else {
243 Ok(actual)
244 }
245 }
246
247 /// Flags the current control frame as unreachable, additionally truncating
248 /// the currently active operand stack.
unreachable(&mut self)249 fn unreachable(&mut self) {
250 let control = self.control.last_mut().unwrap();
251 self.operands.truncate(control.height);
252 control.unreachable = true;
253 }
254
255 /// Pushes a new frame onto the control stack.
256 ///
257 /// This operation is used when entering a new block such as an if, loop,
258 /// or block itself. The `kind` of block is specified which indicates how
259 /// breaks interact with this block's type. Additionally the type signature
260 /// of the block is specified by `ty`.
push_ctrl( &mut self, kind: FrameKind, ty: TypeOrFuncType, resources: &impl WasmModuleResources, ) -> OperatorValidatorResult<()>261 fn push_ctrl(
262 &mut self,
263 kind: FrameKind,
264 ty: TypeOrFuncType,
265 resources: &impl WasmModuleResources,
266 ) -> OperatorValidatorResult<()> {
267 // Push a new frame which has a snapshot of the height of the current
268 // operand stack.
269 self.control.push(Frame {
270 kind,
271 block_type: ty,
272 height: self.operands.len(),
273 unreachable: false,
274 });
275 // All of the parameters are now also available in this control frame,
276 // so we push them here in order.
277 for ty in params(ty, resources)? {
278 self.push_operand(ty)?;
279 }
280 Ok(())
281 }
282
283 /// Pops a frame from the control stack.
284 ///
285 /// This function is used when exiting a block and leaves a block scope.
286 /// Internally this will validate that blocks have the correct result type.
pop_ctrl(&mut self, resources: &impl WasmModuleResources) -> OperatorValidatorResult<Frame>287 fn pop_ctrl(&mut self, resources: &impl WasmModuleResources) -> OperatorValidatorResult<Frame> {
288 // Read the expected type and expected height of the operand stack the
289 // end of the frame.
290 let frame = self.control.last().unwrap();
291 // The end of an `unwind` should check against the empty block type.
292 let ty = if frame.kind == FrameKind::Unwind {
293 TypeOrFuncType::Type(Type::EmptyBlockType)
294 } else {
295 frame.block_type
296 };
297 let height = frame.height;
298
299 // Pop all the result types, in reverse order, from the operand stack.
300 // These types will, possibly, be transferred to the next frame.
301 for ty in results(ty, resources)?.rev() {
302 self.pop_operand(Some(ty))?;
303 }
304
305 // Make sure that the operand stack has returned to is original
306 // height...
307 if self.operands.len() != height {
308 bail_op_err!("type mismatch: values remaining on stack at end of block");
309 }
310
311 // And then we can remove it!
312 Ok(self.control.pop().unwrap())
313 }
314
315 /// Validates a relative jump to the `depth` specified.
316 ///
317 /// Returns the type signature of the block that we're jumping to as well
318 /// as the kind of block if the jump is valid. Otherwise returns an error.
jump(&self, depth: u32) -> OperatorValidatorResult<(TypeOrFuncType, FrameKind)>319 fn jump(&self, depth: u32) -> OperatorValidatorResult<(TypeOrFuncType, FrameKind)> {
320 match (self.control.len() - 1).checked_sub(depth as usize) {
321 Some(i) => {
322 let frame = &self.control[i];
323 Ok((frame.block_type, frame.kind))
324 }
325 None => bail_op_err!("unknown label: branch depth too large"),
326 }
327 }
328
329 /// Validates that `memory_index` is valid in this module, and returns the
330 /// type of address used to index the memory specified.
check_memory_index( &self, memory_index: u32, resources: impl WasmModuleResources, ) -> OperatorValidatorResult<Type>331 fn check_memory_index(
332 &self,
333 memory_index: u32,
334 resources: impl WasmModuleResources,
335 ) -> OperatorValidatorResult<Type> {
336 if memory_index > 0 && !self.features.multi_memory {
337 return Err(OperatorValidatorError::new(
338 "multi-memory support is not enabled",
339 ));
340 }
341 match resources.memory_at(memory_index) {
342 Some(mem) => Ok(mem.index_type()),
343 None => bail_op_err!("unknown memory {}", memory_index),
344 }
345 }
346
347 /// Validates a `memarg for alignment and such (also the memory it
348 /// references), and returns the type of index used to address the memory.
check_memarg( &self, memarg: MemoryImmediate, max_align: u8, resources: impl WasmModuleResources, ) -> OperatorValidatorResult<Type>349 fn check_memarg(
350 &self,
351 memarg: MemoryImmediate,
352 max_align: u8,
353 resources: impl WasmModuleResources,
354 ) -> OperatorValidatorResult<Type> {
355 let index_ty = self.check_memory_index(memarg.memory, resources)?;
356 let align = memarg.align;
357 if align > max_align {
358 return Err(OperatorValidatorError::new(
359 "alignment must not be larger than natural",
360 ));
361 }
362 Ok(index_ty)
363 }
364
365 #[cfg(feature = "deterministic")]
check_non_deterministic_enabled(&self) -> OperatorValidatorResult<()>366 fn check_non_deterministic_enabled(&self) -> OperatorValidatorResult<()> {
367 if !self.features.deterministic_only {
368 return Err(OperatorValidatorError::new(
369 "deterministic_only support is not enabled",
370 ));
371 }
372 Ok(())
373 }
374
375 #[inline(always)]
376 #[cfg(not(feature = "deterministic"))]
check_non_deterministic_enabled(&self) -> OperatorValidatorResult<()>377 fn check_non_deterministic_enabled(&self) -> OperatorValidatorResult<()> {
378 Ok(())
379 }
380
check_threads_enabled(&self) -> OperatorValidatorResult<()>381 fn check_threads_enabled(&self) -> OperatorValidatorResult<()> {
382 if !self.features.threads {
383 return Err(OperatorValidatorError::new(
384 "threads support is not enabled",
385 ));
386 }
387 Ok(())
388 }
389
check_reference_types_enabled(&self) -> OperatorValidatorResult<()>390 fn check_reference_types_enabled(&self) -> OperatorValidatorResult<()> {
391 if !self.features.reference_types {
392 return Err(OperatorValidatorError::new(
393 "reference types support is not enabled",
394 ));
395 }
396 Ok(())
397 }
398
check_simd_enabled(&self) -> OperatorValidatorResult<()>399 fn check_simd_enabled(&self) -> OperatorValidatorResult<()> {
400 if !self.features.simd {
401 return Err(OperatorValidatorError::new("SIMD support is not enabled"));
402 }
403 Ok(())
404 }
405
check_exceptions_enabled(&self) -> OperatorValidatorResult<()>406 fn check_exceptions_enabled(&self) -> OperatorValidatorResult<()> {
407 if !self.features.exceptions {
408 return Err(OperatorValidatorError::new(
409 "Exceptions support is not enabled",
410 ));
411 }
412 Ok(())
413 }
414
check_bulk_memory_enabled(&self) -> OperatorValidatorResult<()>415 fn check_bulk_memory_enabled(&self) -> OperatorValidatorResult<()> {
416 if !self.features.bulk_memory {
417 return Err(OperatorValidatorError::new(
418 "bulk memory support is not enabled",
419 ));
420 }
421 Ok(())
422 }
423
check_shared_memarg_wo_align( &self, memarg: MemoryImmediate, resources: impl WasmModuleResources, ) -> OperatorValidatorResult<Type>424 fn check_shared_memarg_wo_align(
425 &self,
426 memarg: MemoryImmediate,
427 resources: impl WasmModuleResources,
428 ) -> OperatorValidatorResult<Type> {
429 self.check_memory_index(memarg.memory, resources)
430 }
431
check_simd_lane_index(&self, index: SIMDLaneIndex, max: u8) -> OperatorValidatorResult<()>432 fn check_simd_lane_index(&self, index: SIMDLaneIndex, max: u8) -> OperatorValidatorResult<()> {
433 if index >= max {
434 return Err(OperatorValidatorError::new("SIMD index out of bounds"));
435 }
436 Ok(())
437 }
438
439 /// Validates a block type, primarily with various in-flight proposals.
check_block_type( &self, ty: TypeOrFuncType, resources: impl WasmModuleResources, ) -> OperatorValidatorResult<()>440 fn check_block_type(
441 &self,
442 ty: TypeOrFuncType,
443 resources: impl WasmModuleResources,
444 ) -> OperatorValidatorResult<()> {
445 match ty {
446 TypeOrFuncType::Type(Type::EmptyBlockType)
447 | TypeOrFuncType::Type(Type::I32)
448 | TypeOrFuncType::Type(Type::I64)
449 | TypeOrFuncType::Type(Type::F32)
450 | TypeOrFuncType::Type(Type::F64) => Ok(()),
451 TypeOrFuncType::Type(Type::ExternRef) | TypeOrFuncType::Type(Type::FuncRef) => {
452 self.check_reference_types_enabled()
453 }
454 TypeOrFuncType::Type(Type::V128) => self.check_simd_enabled(),
455 TypeOrFuncType::FuncType(idx) => {
456 let ty = func_type_at(&resources, idx)?;
457 if !self.features.multi_value {
458 if ty.len_outputs() > 1 {
459 return Err(OperatorValidatorError::new(
460 "blocks, loops, and ifs may only return at most one \
461 value when multi-value is not enabled",
462 ));
463 }
464 if ty.len_inputs() > 0 {
465 return Err(OperatorValidatorError::new(
466 "blocks, loops, and ifs accept no parameters \
467 when multi-value is not enabled",
468 ));
469 }
470 }
471 Ok(())
472 }
473 _ => Err(OperatorValidatorError::new("invalid block return type")),
474 }
475 }
476
477 /// Validates a `call` instruction, ensuring that the function index is
478 /// in-bounds and the right types are on the stack to call the function.
check_call( &mut self, function_index: u32, resources: &impl WasmModuleResources, ) -> OperatorValidatorResult<()>479 fn check_call(
480 &mut self,
481 function_index: u32,
482 resources: &impl WasmModuleResources,
483 ) -> OperatorValidatorResult<()> {
484 let ty = match resources.type_of_function(function_index) {
485 Some(i) => i,
486 None => {
487 bail_op_err!(
488 "unknown function {}: function index out of bounds",
489 function_index
490 );
491 }
492 };
493 for ty in ty.inputs().rev() {
494 self.pop_operand(Some(ty))?;
495 }
496 for ty in ty.outputs() {
497 self.push_operand(ty)?;
498 }
499 Ok(())
500 }
501
502 /// Validates a call to an indirect function, very similar to `check_call`.
check_call_indirect( &mut self, index: u32, table_index: u32, resources: &impl WasmModuleResources, ) -> OperatorValidatorResult<()>503 fn check_call_indirect(
504 &mut self,
505 index: u32,
506 table_index: u32,
507 resources: &impl WasmModuleResources,
508 ) -> OperatorValidatorResult<()> {
509 match resources.table_at(table_index) {
510 None => {
511 return Err(OperatorValidatorError::new(
512 "unknown table: table index out of bounds",
513 ));
514 }
515 Some(tab) => {
516 if tab.element_type != Type::FuncRef {
517 return Err(OperatorValidatorError::new(
518 "indirect calls must go through a table of funcref",
519 ));
520 }
521 }
522 }
523 let ty = func_type_at(&resources, index)?;
524 self.pop_operand(Some(Type::I32))?;
525 for ty in ty.inputs().rev() {
526 self.pop_operand(Some(ty))?;
527 }
528 for ty in ty.outputs() {
529 self.push_operand(ty)?;
530 }
531 Ok(())
532 }
533
534 /// Validates a `return` instruction, popping types from the operand
535 /// stack that the function needs.
check_return( &mut self, resources: &impl WasmModuleResources, ) -> OperatorValidatorResult<()>536 fn check_return(
537 &mut self,
538 resources: &impl WasmModuleResources,
539 ) -> OperatorValidatorResult<()> {
540 for ty in results(self.control[0].block_type, resources)?.rev() {
541 self.pop_operand(Some(ty))?;
542 }
543 self.unreachable();
544 Ok(())
545 }
546
process_operator( &mut self, operator: &Operator, resources: &impl WasmModuleResources, ) -> OperatorValidatorResult<()>547 pub fn process_operator(
548 &mut self,
549 operator: &Operator,
550 resources: &impl WasmModuleResources,
551 ) -> OperatorValidatorResult<()> {
552 if self.control.len() == 0 {
553 bail_op_err!("operators remaining after end of function");
554 }
555 match *operator {
556 Operator::Nop => {}
557
558 // Note that the handling of these control flow operators are the
559 // same as specified in the "Validation Algorithm" appendix of the
560 // online wasm specification (referenced at the top of this module).
561 Operator::Unreachable => self.unreachable(),
562 Operator::Block { ty } => {
563 self.check_block_type(ty, resources)?;
564 for ty in params(ty, resources)?.rev() {
565 self.pop_operand(Some(ty))?;
566 }
567 self.push_ctrl(FrameKind::Block, ty, resources)?;
568 }
569 Operator::Loop { ty } => {
570 self.check_block_type(ty, resources)?;
571 for ty in params(ty, resources)?.rev() {
572 self.pop_operand(Some(ty))?;
573 }
574 self.push_ctrl(FrameKind::Loop, ty, resources)?;
575 }
576 Operator::If { ty } => {
577 self.check_block_type(ty, resources)?;
578 self.pop_operand(Some(Type::I32))?;
579 for ty in params(ty, resources)?.rev() {
580 self.pop_operand(Some(ty))?;
581 }
582 self.push_ctrl(FrameKind::If, ty, resources)?;
583 }
584 Operator::Else => {
585 let frame = self.pop_ctrl(resources)?;
586 if frame.kind != FrameKind::If {
587 bail_op_err!("else found outside of an `if` block");
588 }
589 self.push_ctrl(FrameKind::Else, frame.block_type, resources)?
590 }
591 Operator::Try { ty } => {
592 self.check_exceptions_enabled()?;
593 self.check_block_type(ty, resources)?;
594 for ty in params(ty, resources)?.rev() {
595 self.pop_operand(Some(ty))?;
596 }
597 self.push_ctrl(FrameKind::Try, ty, resources)?;
598 }
599 Operator::Catch { index } => {
600 self.check_exceptions_enabled()?;
601 let frame = self.pop_ctrl(resources)?;
602 if frame.kind != FrameKind::Try && frame.kind != FrameKind::Catch {
603 bail_op_err!("catch found outside of an `try` block");
604 }
605 // Start a new frame and push `exnref` value.
606 self.control.push(Frame {
607 kind: FrameKind::Catch,
608 block_type: frame.block_type,
609 height: self.operands.len(),
610 unreachable: false,
611 });
612 // Push exception argument types.
613 let ty = event_at(&resources, index)?;
614 for ty in ty.inputs() {
615 self.push_operand(ty)?;
616 }
617 }
618 Operator::Throw { index } => {
619 self.check_exceptions_enabled()?;
620 // Check values associated with the exception.
621 let ty = event_at(&resources, index)?;
622 for ty in ty.inputs().rev() {
623 self.pop_operand(Some(ty))?;
624 }
625 if ty.outputs().len() > 0 {
626 bail_op_err!("result type expected to be empty for exception");
627 }
628 self.unreachable();
629 }
630 Operator::Rethrow { relative_depth } => {
631 self.check_exceptions_enabled()?;
632 // This is not a jump, but we need to check that the `rethrow`
633 // targets an actual `catch` to get the exception.
634 let (_, kind) = self.jump(relative_depth)?;
635 if kind != FrameKind::Catch && kind != FrameKind::CatchAll {
636 bail_op_err!("rethrow target was not a `catch` block");
637 }
638 self.unreachable();
639 }
640 Operator::Unwind => {
641 self.check_exceptions_enabled()?;
642 // Switch from `try` to an `unwind` frame.
643 let frame = self.pop_ctrl(resources)?;
644 if frame.kind != FrameKind::Try {
645 bail_op_err!("unwind found outside of an `try` block");
646 }
647 self.control.push(Frame {
648 kind: FrameKind::Unwind,
649 block_type: frame.block_type,
650 height: self.operands.len(),
651 unreachable: false,
652 });
653 }
654 Operator::Delegate { relative_depth } => {
655 self.check_exceptions_enabled()?;
656 let frame = self.pop_ctrl(resources)?;
657 if frame.kind != FrameKind::Try {
658 bail_op_err!("delegate found outside of an `try` block");
659 }
660 // This operation is not a jump, but we need to check the
661 // depth for validity and that it targets a `try`.
662 let (_, kind) = self.jump(relative_depth)?;
663 if kind != FrameKind::Try
664 && (kind != FrameKind::Block
665 || self.control.len() != relative_depth as usize + 1)
666 {
667 bail_op_err!("must delegate to a try block or caller");
668 }
669 for ty in results(frame.block_type, resources)? {
670 self.push_operand(ty)?;
671 }
672 }
673 Operator::CatchAll => {
674 self.check_exceptions_enabled()?;
675 let frame = self.pop_ctrl(resources)?;
676 if frame.kind == FrameKind::CatchAll {
677 bail_op_err!("only one catch_all allowed per `try` block");
678 } else if frame.kind != FrameKind::Try && frame.kind != FrameKind::Catch {
679 bail_op_err!("catch_all found outside of a `try` block");
680 }
681 self.control.push(Frame {
682 kind: FrameKind::CatchAll,
683 block_type: frame.block_type,
684 height: self.operands.len(),
685 unreachable: false,
686 });
687 }
688 Operator::End => {
689 let mut frame = self.pop_ctrl(resources)?;
690
691 // Note that this `if` isn't included in the appendix right
692 // now, but it's used to allow for `if` statements that are
693 // missing an `else` block which have the same parameter/return
694 // types on the block (since that's valid).
695 match frame.kind {
696 FrameKind::If => {
697 self.push_ctrl(FrameKind::Else, frame.block_type, resources)?;
698 frame = self.pop_ctrl(resources)?;
699 }
700 FrameKind::Try => {
701 bail_op_err!("expected catch block");
702 }
703 _ => (),
704 }
705
706 for ty in results(frame.block_type, resources)? {
707 self.push_operand(ty)?;
708 }
709 }
710 Operator::Br { relative_depth } => {
711 let (ty, kind) = self.jump(relative_depth)?;
712 for ty in label_types(ty, resources, kind)?.rev() {
713 self.pop_operand(Some(ty))?;
714 }
715 self.unreachable();
716 }
717 Operator::BrIf { relative_depth } => {
718 self.pop_operand(Some(Type::I32))?;
719 let (ty, kind) = self.jump(relative_depth)?;
720 for ty in label_types(ty, resources, kind)?.rev() {
721 self.pop_operand(Some(ty))?;
722 }
723 for ty in label_types(ty, resources, kind)? {
724 self.push_operand(ty)?;
725 }
726 }
727 Operator::BrTable { ref table } => {
728 self.pop_operand(Some(Type::I32))?;
729 let mut label = None;
730 for element in table.targets() {
731 let (relative_depth, _is_default) = element.map_err(|mut e| {
732 e.inner.offset = usize::max_value();
733 OperatorValidatorError(e)
734 })?;
735 let block = self.jump(relative_depth)?;
736 match label {
737 None => label = Some(block),
738 Some(prev) => {
739 let a = label_types(block.0, resources, block.1)?;
740 let b = label_types(prev.0, resources, prev.1)?;
741 if a.ne(b) {
742 bail_op_err!(
743 "type mismatch: br_table target labels have different types"
744 );
745 }
746 }
747 }
748 }
749 let (ty, kind) = label.unwrap();
750 for ty in label_types(ty, resources, kind)?.rev() {
751 self.pop_operand(Some(ty))?;
752 }
753 self.unreachable();
754 }
755 Operator::Return => self.check_return(resources)?,
756 Operator::Call { function_index } => self.check_call(function_index, resources)?,
757 Operator::ReturnCall { function_index } => {
758 if !self.features.tail_call {
759 return Err(OperatorValidatorError::new(
760 "tail calls support is not enabled",
761 ));
762 }
763 self.check_call(function_index, resources)?;
764 self.check_return(resources)?;
765 }
766 Operator::CallIndirect { index, table_index } => {
767 self.check_call_indirect(index, table_index, resources)?
768 }
769 Operator::ReturnCallIndirect { index, table_index } => {
770 if !self.features.tail_call {
771 return Err(OperatorValidatorError::new(
772 "tail calls support is not enabled",
773 ));
774 }
775 self.check_call_indirect(index, table_index, resources)?;
776 self.check_return(resources)?;
777 }
778 Operator::Drop => {
779 self.pop_operand(None)?;
780 }
781 Operator::Select => {
782 self.pop_operand(Some(Type::I32))?;
783 let ty = self.pop_operand(None)?;
784 match self.pop_operand(ty)? {
785 ty @ Some(Type::I32)
786 | ty @ Some(Type::I64)
787 | ty @ Some(Type::F32)
788 | ty @ Some(Type::F64) => self.operands.push(ty),
789 ty @ Some(Type::V128) => {
790 self.check_simd_enabled()?;
791 self.operands.push(ty)
792 }
793 None => self.operands.push(None),
794 Some(_) => bail_op_err!("type mismatch: select only takes integral types"),
795 }
796 }
797 Operator::TypedSelect { ty } => {
798 self.pop_operand(Some(Type::I32))?;
799 self.pop_operand(Some(ty))?;
800 self.pop_operand(Some(ty))?;
801 self.push_operand(ty)?;
802 }
803 Operator::LocalGet { local_index } => {
804 let ty = self.local(local_index)?;
805 self.push_operand(ty)?;
806 }
807 Operator::LocalSet { local_index } => {
808 let ty = self.local(local_index)?;
809 self.pop_operand(Some(ty))?;
810 }
811 Operator::LocalTee { local_index } => {
812 let ty = self.local(local_index)?;
813 self.pop_operand(Some(ty))?;
814 self.push_operand(ty)?;
815 }
816 Operator::GlobalGet { global_index } => {
817 if let Some(ty) = resources.global_at(global_index) {
818 self.push_operand(ty.content_type)?;
819 } else {
820 return Err(OperatorValidatorError::new(
821 "unknown global: global index out of bounds",
822 ));
823 };
824 }
825 Operator::GlobalSet { global_index } => {
826 if let Some(ty) = resources.global_at(global_index) {
827 if !ty.mutable {
828 return Err(OperatorValidatorError::new(
829 "global is immutable: cannot modify it with `global.set`",
830 ));
831 }
832 self.pop_operand(Some(ty.content_type))?;
833 } else {
834 return Err(OperatorValidatorError::new(
835 "unknown global: global index out of bounds",
836 ));
837 };
838 }
839 Operator::I32Load { memarg } => {
840 let ty = self.check_memarg(memarg, 2, resources)?;
841 self.pop_operand(Some(ty))?;
842 self.push_operand(Type::I32)?;
843 }
844 Operator::I64Load { memarg } => {
845 let ty = self.check_memarg(memarg, 3, resources)?;
846 self.pop_operand(Some(ty))?;
847 self.push_operand(Type::I64)?;
848 }
849 Operator::F32Load { memarg } => {
850 self.check_non_deterministic_enabled()?;
851 let ty = self.check_memarg(memarg, 2, resources)?;
852 self.pop_operand(Some(ty))?;
853 self.push_operand(Type::F32)?;
854 }
855 Operator::F64Load { memarg } => {
856 self.check_non_deterministic_enabled()?;
857 let ty = self.check_memarg(memarg, 3, resources)?;
858 self.pop_operand(Some(ty))?;
859 self.push_operand(Type::F64)?;
860 }
861 Operator::I32Load8S { memarg } | Operator::I32Load8U { memarg } => {
862 let ty = self.check_memarg(memarg, 0, resources)?;
863 self.pop_operand(Some(ty))?;
864 self.push_operand(Type::I32)?;
865 }
866 Operator::I32Load16S { memarg } | Operator::I32Load16U { memarg } => {
867 let ty = self.check_memarg(memarg, 1, resources)?;
868 self.pop_operand(Some(ty))?;
869 self.push_operand(Type::I32)?;
870 }
871 Operator::I64Load8S { memarg } | Operator::I64Load8U { memarg } => {
872 let ty = self.check_memarg(memarg, 0, resources)?;
873 self.pop_operand(Some(ty))?;
874 self.push_operand(Type::I64)?;
875 }
876 Operator::I64Load16S { memarg } | Operator::I64Load16U { memarg } => {
877 let ty = self.check_memarg(memarg, 1, resources)?;
878 self.pop_operand(Some(ty))?;
879 self.push_operand(Type::I64)?;
880 }
881 Operator::I64Load32S { memarg } | Operator::I64Load32U { memarg } => {
882 let ty = self.check_memarg(memarg, 2, resources)?;
883 self.pop_operand(Some(ty))?;
884 self.push_operand(Type::I64)?;
885 }
886 Operator::I32Store { memarg } => {
887 let ty = self.check_memarg(memarg, 2, resources)?;
888 self.pop_operand(Some(Type::I32))?;
889 self.pop_operand(Some(ty))?;
890 }
891 Operator::I64Store { memarg } => {
892 let ty = self.check_memarg(memarg, 3, resources)?;
893 self.pop_operand(Some(Type::I64))?;
894 self.pop_operand(Some(ty))?;
895 }
896 Operator::F32Store { memarg } => {
897 self.check_non_deterministic_enabled()?;
898 let ty = self.check_memarg(memarg, 2, resources)?;
899 self.pop_operand(Some(Type::F32))?;
900 self.pop_operand(Some(ty))?;
901 }
902 Operator::F64Store { memarg } => {
903 self.check_non_deterministic_enabled()?;
904 let ty = self.check_memarg(memarg, 3, resources)?;
905 self.pop_operand(Some(Type::F64))?;
906 self.pop_operand(Some(ty))?;
907 }
908 Operator::I32Store8 { memarg } => {
909 let ty = self.check_memarg(memarg, 0, resources)?;
910 self.pop_operand(Some(Type::I32))?;
911 self.pop_operand(Some(ty))?;
912 }
913 Operator::I32Store16 { memarg } => {
914 let ty = self.check_memarg(memarg, 1, resources)?;
915 self.pop_operand(Some(Type::I32))?;
916 self.pop_operand(Some(ty))?;
917 }
918 Operator::I64Store8 { memarg } => {
919 let ty = self.check_memarg(memarg, 0, resources)?;
920 self.pop_operand(Some(Type::I64))?;
921 self.pop_operand(Some(ty))?;
922 }
923 Operator::I64Store16 { memarg } => {
924 let ty = self.check_memarg(memarg, 1, resources)?;
925 self.pop_operand(Some(Type::I64))?;
926 self.pop_operand(Some(ty))?;
927 }
928 Operator::I64Store32 { memarg } => {
929 let ty = self.check_memarg(memarg, 2, resources)?;
930 self.pop_operand(Some(Type::I64))?;
931 self.pop_operand(Some(ty))?;
932 }
933 Operator::MemorySize { mem, mem_byte } => {
934 if mem_byte != 0 && !self.features.multi_memory {
935 return Err(OperatorValidatorError::new("multi-memory not enabled"));
936 }
937 let index_ty = self.check_memory_index(mem, resources)?;
938 self.push_operand(index_ty)?;
939 }
940 Operator::MemoryGrow { mem, mem_byte } => {
941 if mem_byte != 0 && !self.features.multi_memory {
942 return Err(OperatorValidatorError::new("multi-memory not enabled"));
943 }
944 let index_ty = self.check_memory_index(mem, resources)?;
945 self.pop_operand(Some(index_ty))?;
946 self.push_operand(index_ty)?;
947 }
948 Operator::I32Const { .. } => self.push_operand(Type::I32)?,
949 Operator::I64Const { .. } => self.push_operand(Type::I64)?,
950 Operator::F32Const { .. } => {
951 self.check_non_deterministic_enabled()?;
952 self.push_operand(Type::F32)?;
953 }
954 Operator::F64Const { .. } => {
955 self.check_non_deterministic_enabled()?;
956 self.push_operand(Type::F64)?;
957 }
958 Operator::I32Eqz => {
959 self.pop_operand(Some(Type::I32))?;
960 self.push_operand(Type::I32)?;
961 }
962 Operator::I32Eq
963 | Operator::I32Ne
964 | Operator::I32LtS
965 | Operator::I32LtU
966 | Operator::I32GtS
967 | Operator::I32GtU
968 | Operator::I32LeS
969 | Operator::I32LeU
970 | Operator::I32GeS
971 | Operator::I32GeU => {
972 self.pop_operand(Some(Type::I32))?;
973 self.pop_operand(Some(Type::I32))?;
974 self.push_operand(Type::I32)?;
975 }
976 Operator::I64Eqz => {
977 self.pop_operand(Some(Type::I64))?;
978 self.push_operand(Type::I32)?;
979 }
980 Operator::I64Eq
981 | Operator::I64Ne
982 | Operator::I64LtS
983 | Operator::I64LtU
984 | Operator::I64GtS
985 | Operator::I64GtU
986 | Operator::I64LeS
987 | Operator::I64LeU
988 | Operator::I64GeS
989 | Operator::I64GeU => {
990 self.pop_operand(Some(Type::I64))?;
991 self.pop_operand(Some(Type::I64))?;
992 self.push_operand(Type::I32)?;
993 }
994 Operator::F32Eq
995 | Operator::F32Ne
996 | Operator::F32Lt
997 | Operator::F32Gt
998 | Operator::F32Le
999 | Operator::F32Ge => {
1000 self.check_non_deterministic_enabled()?;
1001 self.pop_operand(Some(Type::F32))?;
1002 self.pop_operand(Some(Type::F32))?;
1003 self.push_operand(Type::I32)?;
1004 }
1005 Operator::F64Eq
1006 | Operator::F64Ne
1007 | Operator::F64Lt
1008 | Operator::F64Gt
1009 | Operator::F64Le
1010 | Operator::F64Ge => {
1011 self.check_non_deterministic_enabled()?;
1012 self.pop_operand(Some(Type::F64))?;
1013 self.pop_operand(Some(Type::F64))?;
1014 self.push_operand(Type::I32)?;
1015 }
1016 Operator::I32Clz | Operator::I32Ctz | Operator::I32Popcnt => {
1017 self.pop_operand(Some(Type::I32))?;
1018 self.push_operand(Type::I32)?;
1019 }
1020 Operator::I32Add
1021 | Operator::I32Sub
1022 | Operator::I32Mul
1023 | Operator::I32DivS
1024 | Operator::I32DivU
1025 | Operator::I32RemS
1026 | Operator::I32RemU
1027 | Operator::I32And
1028 | Operator::I32Or
1029 | Operator::I32Xor
1030 | Operator::I32Shl
1031 | Operator::I32ShrS
1032 | Operator::I32ShrU
1033 | Operator::I32Rotl
1034 | Operator::I32Rotr => {
1035 self.pop_operand(Some(Type::I32))?;
1036 self.pop_operand(Some(Type::I32))?;
1037 self.push_operand(Type::I32)?;
1038 }
1039 Operator::I64Clz | Operator::I64Ctz | Operator::I64Popcnt => {
1040 self.pop_operand(Some(Type::I64))?;
1041 self.push_operand(Type::I64)?;
1042 }
1043 Operator::I64Add
1044 | Operator::I64Sub
1045 | Operator::I64Mul
1046 | Operator::I64DivS
1047 | Operator::I64DivU
1048 | Operator::I64RemS
1049 | Operator::I64RemU
1050 | Operator::I64And
1051 | Operator::I64Or
1052 | Operator::I64Xor
1053 | Operator::I64Shl
1054 | Operator::I64ShrS
1055 | Operator::I64ShrU
1056 | Operator::I64Rotl
1057 | Operator::I64Rotr => {
1058 self.pop_operand(Some(Type::I64))?;
1059 self.pop_operand(Some(Type::I64))?;
1060 self.push_operand(Type::I64)?;
1061 }
1062 Operator::F32Abs
1063 | Operator::F32Neg
1064 | Operator::F32Ceil
1065 | Operator::F32Floor
1066 | Operator::F32Trunc
1067 | Operator::F32Nearest
1068 | Operator::F32Sqrt => {
1069 self.check_non_deterministic_enabled()?;
1070 self.pop_operand(Some(Type::F32))?;
1071 self.push_operand(Type::F32)?;
1072 }
1073 Operator::F32Add
1074 | Operator::F32Sub
1075 | Operator::F32Mul
1076 | Operator::F32Div
1077 | Operator::F32Min
1078 | Operator::F32Max
1079 | Operator::F32Copysign => {
1080 self.check_non_deterministic_enabled()?;
1081 self.pop_operand(Some(Type::F32))?;
1082 self.pop_operand(Some(Type::F32))?;
1083 self.push_operand(Type::F32)?;
1084 }
1085 Operator::F64Abs
1086 | Operator::F64Neg
1087 | Operator::F64Ceil
1088 | Operator::F64Floor
1089 | Operator::F64Trunc
1090 | Operator::F64Nearest
1091 | Operator::F64Sqrt => {
1092 self.check_non_deterministic_enabled()?;
1093 self.pop_operand(Some(Type::F64))?;
1094 self.push_operand(Type::F64)?;
1095 }
1096 Operator::F64Add
1097 | Operator::F64Sub
1098 | Operator::F64Mul
1099 | Operator::F64Div
1100 | Operator::F64Min
1101 | Operator::F64Max
1102 | Operator::F64Copysign => {
1103 self.check_non_deterministic_enabled()?;
1104 self.pop_operand(Some(Type::F64))?;
1105 self.pop_operand(Some(Type::F64))?;
1106 self.push_operand(Type::F64)?;
1107 }
1108 Operator::I32WrapI64 => {
1109 self.pop_operand(Some(Type::I64))?;
1110 self.push_operand(Type::I32)?;
1111 }
1112 Operator::I32TruncF32S | Operator::I32TruncF32U => {
1113 self.pop_operand(Some(Type::F32))?;
1114 self.push_operand(Type::I32)?;
1115 }
1116 Operator::I32TruncF64S | Operator::I32TruncF64U => {
1117 self.pop_operand(Some(Type::F64))?;
1118 self.push_operand(Type::I32)?;
1119 }
1120 Operator::I64ExtendI32S | Operator::I64ExtendI32U => {
1121 self.pop_operand(Some(Type::I32))?;
1122 self.push_operand(Type::I64)?;
1123 }
1124 Operator::I64TruncF32S | Operator::I64TruncF32U => {
1125 self.pop_operand(Some(Type::F32))?;
1126 self.push_operand(Type::I64)?;
1127 }
1128 Operator::I64TruncF64S | Operator::I64TruncF64U => {
1129 self.pop_operand(Some(Type::F64))?;
1130 self.push_operand(Type::I64)?;
1131 }
1132 Operator::F32ConvertI32S | Operator::F32ConvertI32U => {
1133 self.check_non_deterministic_enabled()?;
1134 self.pop_operand(Some(Type::I32))?;
1135 self.push_operand(Type::F32)?;
1136 }
1137 Operator::F32ConvertI64S | Operator::F32ConvertI64U => {
1138 self.check_non_deterministic_enabled()?;
1139 self.pop_operand(Some(Type::I64))?;
1140 self.push_operand(Type::F32)?;
1141 }
1142 Operator::F32DemoteF64 => {
1143 self.check_non_deterministic_enabled()?;
1144 self.pop_operand(Some(Type::F64))?;
1145 self.push_operand(Type::F32)?;
1146 }
1147 Operator::F64ConvertI32S | Operator::F64ConvertI32U => {
1148 self.check_non_deterministic_enabled()?;
1149 self.pop_operand(Some(Type::I32))?;
1150 self.push_operand(Type::F64)?;
1151 }
1152 Operator::F64ConvertI64S | Operator::F64ConvertI64U => {
1153 self.check_non_deterministic_enabled()?;
1154 self.pop_operand(Some(Type::I64))?;
1155 self.push_operand(Type::F64)?;
1156 }
1157 Operator::F64PromoteF32 => {
1158 self.check_non_deterministic_enabled()?;
1159 self.pop_operand(Some(Type::F32))?;
1160 self.push_operand(Type::F64)?;
1161 }
1162 Operator::I32ReinterpretF32 => {
1163 self.pop_operand(Some(Type::F32))?;
1164 self.push_operand(Type::I32)?;
1165 }
1166 Operator::I64ReinterpretF64 => {
1167 self.pop_operand(Some(Type::F64))?;
1168 self.push_operand(Type::I64)?;
1169 }
1170 Operator::F32ReinterpretI32 => {
1171 self.check_non_deterministic_enabled()?;
1172 self.pop_operand(Some(Type::I32))?;
1173 self.push_operand(Type::F32)?;
1174 }
1175 Operator::F64ReinterpretI64 => {
1176 self.check_non_deterministic_enabled()?;
1177 self.pop_operand(Some(Type::I64))?;
1178 self.push_operand(Type::F64)?;
1179 }
1180 Operator::I32TruncSatF32S | Operator::I32TruncSatF32U => {
1181 self.pop_operand(Some(Type::F32))?;
1182 self.push_operand(Type::I32)?;
1183 }
1184 Operator::I32TruncSatF64S | Operator::I32TruncSatF64U => {
1185 self.pop_operand(Some(Type::F64))?;
1186 self.push_operand(Type::I32)?;
1187 }
1188 Operator::I64TruncSatF32S | Operator::I64TruncSatF32U => {
1189 self.pop_operand(Some(Type::F32))?;
1190 self.push_operand(Type::I64)?;
1191 }
1192 Operator::I64TruncSatF64S | Operator::I64TruncSatF64U => {
1193 self.pop_operand(Some(Type::F64))?;
1194 self.push_operand(Type::I64)?;
1195 }
1196 Operator::I32Extend16S | Operator::I32Extend8S => {
1197 self.pop_operand(Some(Type::I32))?;
1198 self.push_operand(Type::I32)?;
1199 }
1200
1201 Operator::I64Extend32S | Operator::I64Extend16S | Operator::I64Extend8S => {
1202 self.pop_operand(Some(Type::I64))?;
1203 self.push_operand(Type::I64)?;
1204 }
1205
1206 Operator::I32AtomicLoad { memarg }
1207 | Operator::I32AtomicLoad16U { memarg }
1208 | Operator::I32AtomicLoad8U { memarg } => {
1209 self.check_threads_enabled()?;
1210 let ty = self.check_shared_memarg_wo_align(memarg, resources)?;
1211 self.pop_operand(Some(ty))?;
1212 self.push_operand(Type::I32)?;
1213 }
1214 Operator::I64AtomicLoad { memarg }
1215 | Operator::I64AtomicLoad32U { memarg }
1216 | Operator::I64AtomicLoad16U { memarg }
1217 | Operator::I64AtomicLoad8U { memarg } => {
1218 self.check_threads_enabled()?;
1219 let ty = self.check_shared_memarg_wo_align(memarg, resources)?;
1220 self.pop_operand(Some(ty))?;
1221 self.push_operand(Type::I64)?;
1222 }
1223 Operator::I32AtomicStore { memarg }
1224 | Operator::I32AtomicStore16 { memarg }
1225 | Operator::I32AtomicStore8 { memarg } => {
1226 self.check_threads_enabled()?;
1227 let ty = self.check_shared_memarg_wo_align(memarg, resources)?;
1228 self.pop_operand(Some(Type::I32))?;
1229 self.pop_operand(Some(ty))?;
1230 }
1231 Operator::I64AtomicStore { memarg }
1232 | Operator::I64AtomicStore32 { memarg }
1233 | Operator::I64AtomicStore16 { memarg }
1234 | Operator::I64AtomicStore8 { memarg } => {
1235 self.check_threads_enabled()?;
1236 let ty = self.check_shared_memarg_wo_align(memarg, resources)?;
1237 self.pop_operand(Some(Type::I64))?;
1238 self.pop_operand(Some(ty))?;
1239 }
1240 Operator::I32AtomicRmwAdd { memarg }
1241 | Operator::I32AtomicRmwSub { memarg }
1242 | Operator::I32AtomicRmwAnd { memarg }
1243 | Operator::I32AtomicRmwOr { memarg }
1244 | Operator::I32AtomicRmwXor { memarg }
1245 | Operator::I32AtomicRmw16AddU { memarg }
1246 | Operator::I32AtomicRmw16SubU { memarg }
1247 | Operator::I32AtomicRmw16AndU { memarg }
1248 | Operator::I32AtomicRmw16OrU { memarg }
1249 | Operator::I32AtomicRmw16XorU { memarg }
1250 | Operator::I32AtomicRmw8AddU { memarg }
1251 | Operator::I32AtomicRmw8SubU { memarg }
1252 | Operator::I32AtomicRmw8AndU { memarg }
1253 | Operator::I32AtomicRmw8OrU { memarg }
1254 | Operator::I32AtomicRmw8XorU { memarg } => {
1255 self.check_threads_enabled()?;
1256 let ty = self.check_shared_memarg_wo_align(memarg, resources)?;
1257 self.pop_operand(Some(Type::I32))?;
1258 self.pop_operand(Some(ty))?;
1259 self.push_operand(Type::I32)?;
1260 }
1261 Operator::I64AtomicRmwAdd { memarg }
1262 | Operator::I64AtomicRmwSub { memarg }
1263 | Operator::I64AtomicRmwAnd { memarg }
1264 | Operator::I64AtomicRmwOr { memarg }
1265 | Operator::I64AtomicRmwXor { memarg }
1266 | Operator::I64AtomicRmw32AddU { memarg }
1267 | Operator::I64AtomicRmw32SubU { memarg }
1268 | Operator::I64AtomicRmw32AndU { memarg }
1269 | Operator::I64AtomicRmw32OrU { memarg }
1270 | Operator::I64AtomicRmw32XorU { memarg }
1271 | Operator::I64AtomicRmw16AddU { memarg }
1272 | Operator::I64AtomicRmw16SubU { memarg }
1273 | Operator::I64AtomicRmw16AndU { memarg }
1274 | Operator::I64AtomicRmw16OrU { memarg }
1275 | Operator::I64AtomicRmw16XorU { memarg }
1276 | Operator::I64AtomicRmw8AddU { memarg }
1277 | Operator::I64AtomicRmw8SubU { memarg }
1278 | Operator::I64AtomicRmw8AndU { memarg }
1279 | Operator::I64AtomicRmw8OrU { memarg }
1280 | Operator::I64AtomicRmw8XorU { memarg } => {
1281 self.check_threads_enabled()?;
1282 let ty = self.check_shared_memarg_wo_align(memarg, resources)?;
1283 self.pop_operand(Some(Type::I64))?;
1284 self.pop_operand(Some(ty))?;
1285 self.push_operand(Type::I64)?;
1286 }
1287 Operator::I32AtomicRmwXchg { memarg }
1288 | Operator::I32AtomicRmw16XchgU { memarg }
1289 | Operator::I32AtomicRmw8XchgU { memarg } => {
1290 self.check_threads_enabled()?;
1291 let ty = self.check_shared_memarg_wo_align(memarg, resources)?;
1292 self.pop_operand(Some(Type::I32))?;
1293 self.pop_operand(Some(ty))?;
1294 self.push_operand(Type::I32)?;
1295 }
1296 Operator::I32AtomicRmwCmpxchg { memarg }
1297 | Operator::I32AtomicRmw16CmpxchgU { memarg }
1298 | Operator::I32AtomicRmw8CmpxchgU { memarg } => {
1299 self.check_threads_enabled()?;
1300 let ty = self.check_shared_memarg_wo_align(memarg, resources)?;
1301 self.pop_operand(Some(Type::I32))?;
1302 self.pop_operand(Some(Type::I32))?;
1303 self.pop_operand(Some(ty))?;
1304 self.push_operand(Type::I32)?;
1305 }
1306 Operator::I64AtomicRmwXchg { memarg }
1307 | Operator::I64AtomicRmw32XchgU { memarg }
1308 | Operator::I64AtomicRmw16XchgU { memarg }
1309 | Operator::I64AtomicRmw8XchgU { memarg } => {
1310 self.check_threads_enabled()?;
1311 let ty = self.check_shared_memarg_wo_align(memarg, resources)?;
1312 self.pop_operand(Some(Type::I64))?;
1313 self.pop_operand(Some(ty))?;
1314 self.push_operand(Type::I64)?;
1315 }
1316 Operator::I64AtomicRmwCmpxchg { memarg }
1317 | Operator::I64AtomicRmw32CmpxchgU { memarg }
1318 | Operator::I64AtomicRmw16CmpxchgU { memarg }
1319 | Operator::I64AtomicRmw8CmpxchgU { memarg } => {
1320 self.check_threads_enabled()?;
1321 let ty = self.check_shared_memarg_wo_align(memarg, resources)?;
1322 self.pop_operand(Some(Type::I64))?;
1323 self.pop_operand(Some(Type::I64))?;
1324 self.pop_operand(Some(ty))?;
1325 self.push_operand(Type::I64)?;
1326 }
1327 Operator::MemoryAtomicNotify { memarg } => {
1328 self.check_threads_enabled()?;
1329 let ty = self.check_shared_memarg_wo_align(memarg, resources)?;
1330 self.pop_operand(Some(Type::I32))?;
1331 self.pop_operand(Some(ty))?;
1332 self.push_operand(Type::I32)?;
1333 }
1334 Operator::MemoryAtomicWait32 { memarg } => {
1335 self.check_threads_enabled()?;
1336 let ty = self.check_shared_memarg_wo_align(memarg, resources)?;
1337 self.pop_operand(Some(Type::I64))?;
1338 self.pop_operand(Some(Type::I32))?;
1339 self.pop_operand(Some(ty))?;
1340 self.push_operand(Type::I32)?;
1341 }
1342 Operator::MemoryAtomicWait64 { memarg } => {
1343 self.check_threads_enabled()?;
1344 let ty = self.check_shared_memarg_wo_align(memarg, resources)?;
1345 self.pop_operand(Some(Type::I64))?;
1346 self.pop_operand(Some(Type::I64))?;
1347 self.pop_operand(Some(ty))?;
1348 self.push_operand(Type::I32)?;
1349 }
1350 Operator::AtomicFence { ref flags } => {
1351 self.check_threads_enabled()?;
1352 if *flags != 0 {
1353 return Err(OperatorValidatorError::new(
1354 "non-zero flags for fence not supported yet",
1355 ));
1356 }
1357 }
1358 Operator::RefNull { ty } => {
1359 self.check_reference_types_enabled()?;
1360 match ty {
1361 Type::FuncRef | Type::ExternRef => {}
1362 _ => {
1363 return Err(OperatorValidatorError::new(
1364 "invalid reference type in ref.null",
1365 ))
1366 }
1367 }
1368 self.push_operand(ty)?;
1369 }
1370 Operator::RefIsNull => {
1371 self.check_reference_types_enabled()?;
1372 match self.pop_operand(None)? {
1373 None | Some(Type::FuncRef) | Some(Type::ExternRef) => {}
1374 _ => {
1375 return Err(OperatorValidatorError::new(
1376 "type mismatch: invalid reference type in ref.is_null",
1377 ))
1378 }
1379 }
1380 self.push_operand(Type::I32)?;
1381 }
1382 Operator::RefFunc { function_index } => {
1383 self.check_reference_types_enabled()?;
1384 if resources.type_of_function(function_index).is_none() {
1385 return Err(OperatorValidatorError::new(
1386 "unknown function: function index out of bounds",
1387 ));
1388 }
1389 if !resources.is_function_referenced(function_index) {
1390 return Err(OperatorValidatorError::new("undeclared function reference"));
1391 }
1392 self.push_operand(Type::FuncRef)?;
1393 }
1394 Operator::V128Load { memarg } => {
1395 self.check_simd_enabled()?;
1396 let ty = self.check_memarg(memarg, 4, resources)?;
1397 self.pop_operand(Some(ty))?;
1398 self.push_operand(Type::V128)?;
1399 }
1400 Operator::V128Store { memarg } => {
1401 self.check_simd_enabled()?;
1402 let ty = self.check_memarg(memarg, 4, resources)?;
1403 self.pop_operand(Some(Type::V128))?;
1404 self.pop_operand(Some(ty))?;
1405 }
1406 Operator::V128Const { .. } => {
1407 self.check_simd_enabled()?;
1408 self.push_operand(Type::V128)?;
1409 }
1410 Operator::I8x16Splat | Operator::I16x8Splat | Operator::I32x4Splat => {
1411 self.check_simd_enabled()?;
1412 self.pop_operand(Some(Type::I32))?;
1413 self.push_operand(Type::V128)?;
1414 }
1415 Operator::I64x2Splat => {
1416 self.check_simd_enabled()?;
1417 self.pop_operand(Some(Type::I64))?;
1418 self.push_operand(Type::V128)?;
1419 }
1420 Operator::F32x4Splat => {
1421 self.check_non_deterministic_enabled()?;
1422 self.check_simd_enabled()?;
1423 self.pop_operand(Some(Type::F32))?;
1424 self.push_operand(Type::V128)?;
1425 }
1426 Operator::F64x2Splat => {
1427 self.check_non_deterministic_enabled()?;
1428 self.check_simd_enabled()?;
1429 self.pop_operand(Some(Type::F64))?;
1430 self.push_operand(Type::V128)?;
1431 }
1432 Operator::I8x16ExtractLaneS { lane } | Operator::I8x16ExtractLaneU { lane } => {
1433 self.check_simd_enabled()?;
1434 self.check_simd_lane_index(lane, 16)?;
1435 self.pop_operand(Some(Type::V128))?;
1436 self.push_operand(Type::I32)?;
1437 }
1438 Operator::I16x8ExtractLaneS { lane } | Operator::I16x8ExtractLaneU { lane } => {
1439 self.check_simd_enabled()?;
1440 self.check_simd_lane_index(lane, 8)?;
1441 self.pop_operand(Some(Type::V128))?;
1442 self.push_operand(Type::I32)?;
1443 }
1444 Operator::I32x4ExtractLane { lane } => {
1445 self.check_simd_enabled()?;
1446 self.check_simd_lane_index(lane, 4)?;
1447 self.pop_operand(Some(Type::V128))?;
1448 self.push_operand(Type::I32)?;
1449 }
1450 Operator::I8x16ReplaceLane { lane } => {
1451 self.check_simd_enabled()?;
1452 self.check_simd_lane_index(lane, 16)?;
1453 self.pop_operand(Some(Type::I32))?;
1454 self.pop_operand(Some(Type::V128))?;
1455 self.push_operand(Type::V128)?;
1456 }
1457 Operator::I16x8ReplaceLane { lane } => {
1458 self.check_simd_enabled()?;
1459 self.check_simd_lane_index(lane, 8)?;
1460 self.pop_operand(Some(Type::I32))?;
1461 self.pop_operand(Some(Type::V128))?;
1462 self.push_operand(Type::V128)?;
1463 }
1464 Operator::I32x4ReplaceLane { lane } => {
1465 self.check_simd_enabled()?;
1466 self.check_simd_lane_index(lane, 4)?;
1467 self.pop_operand(Some(Type::I32))?;
1468 self.pop_operand(Some(Type::V128))?;
1469 self.push_operand(Type::V128)?;
1470 }
1471 Operator::I64x2ExtractLane { lane } => {
1472 self.check_simd_enabled()?;
1473 self.check_simd_lane_index(lane, 2)?;
1474 self.pop_operand(Some(Type::V128))?;
1475 self.push_operand(Type::I64)?;
1476 }
1477 Operator::I64x2ReplaceLane { lane } => {
1478 self.check_simd_enabled()?;
1479 self.check_simd_lane_index(lane, 2)?;
1480 self.pop_operand(Some(Type::I64))?;
1481 self.pop_operand(Some(Type::V128))?;
1482 self.push_operand(Type::V128)?;
1483 }
1484 Operator::F32x4ExtractLane { lane } => {
1485 self.check_non_deterministic_enabled()?;
1486 self.check_simd_enabled()?;
1487 self.check_simd_lane_index(lane, 4)?;
1488 self.pop_operand(Some(Type::V128))?;
1489 self.push_operand(Type::F32)?;
1490 }
1491 Operator::F32x4ReplaceLane { lane } => {
1492 self.check_non_deterministic_enabled()?;
1493 self.check_simd_enabled()?;
1494 self.check_simd_lane_index(lane, 4)?;
1495 self.pop_operand(Some(Type::F32))?;
1496 self.pop_operand(Some(Type::V128))?;
1497 self.push_operand(Type::V128)?;
1498 }
1499 Operator::F64x2ExtractLane { lane } => {
1500 self.check_non_deterministic_enabled()?;
1501 self.check_simd_enabled()?;
1502 self.check_simd_lane_index(lane, 2)?;
1503 self.pop_operand(Some(Type::V128))?;
1504 self.push_operand(Type::F64)?;
1505 }
1506 Operator::F64x2ReplaceLane { lane } => {
1507 self.check_non_deterministic_enabled()?;
1508 self.check_simd_enabled()?;
1509 self.check_simd_lane_index(lane, 2)?;
1510 self.pop_operand(Some(Type::F64))?;
1511 self.pop_operand(Some(Type::V128))?;
1512 self.push_operand(Type::V128)?;
1513 }
1514 Operator::F32x4Eq
1515 | Operator::F32x4Ne
1516 | Operator::F32x4Lt
1517 | Operator::F32x4Gt
1518 | Operator::F32x4Le
1519 | Operator::F32x4Ge
1520 | Operator::F64x2Eq
1521 | Operator::F64x2Ne
1522 | Operator::F64x2Lt
1523 | Operator::F64x2Gt
1524 | Operator::F64x2Le
1525 | Operator::F64x2Ge
1526 | Operator::F32x4Add
1527 | Operator::F32x4Sub
1528 | Operator::F32x4Mul
1529 | Operator::F32x4Div
1530 | Operator::F32x4Min
1531 | Operator::F32x4Max
1532 | Operator::F32x4PMin
1533 | Operator::F32x4PMax
1534 | Operator::F64x2Add
1535 | Operator::F64x2Sub
1536 | Operator::F64x2Mul
1537 | Operator::F64x2Div
1538 | Operator::F64x2Min
1539 | Operator::F64x2Max
1540 | Operator::F64x2PMin
1541 | Operator::F64x2PMax => {
1542 self.check_non_deterministic_enabled()?;
1543 self.check_simd_enabled()?;
1544 self.pop_operand(Some(Type::V128))?;
1545 self.pop_operand(Some(Type::V128))?;
1546 self.push_operand(Type::V128)?;
1547 }
1548 Operator::I8x16Eq
1549 | Operator::I8x16Ne
1550 | Operator::I8x16LtS
1551 | Operator::I8x16LtU
1552 | Operator::I8x16GtS
1553 | Operator::I8x16GtU
1554 | Operator::I8x16LeS
1555 | Operator::I8x16LeU
1556 | Operator::I8x16GeS
1557 | Operator::I8x16GeU
1558 | Operator::I16x8Eq
1559 | Operator::I16x8Ne
1560 | Operator::I16x8LtS
1561 | Operator::I16x8LtU
1562 | Operator::I16x8GtS
1563 | Operator::I16x8GtU
1564 | Operator::I16x8LeS
1565 | Operator::I16x8LeU
1566 | Operator::I16x8GeS
1567 | Operator::I16x8GeU
1568 | Operator::I32x4Eq
1569 | Operator::I32x4Ne
1570 | Operator::I32x4LtS
1571 | Operator::I32x4LtU
1572 | Operator::I32x4GtS
1573 | Operator::I32x4GtU
1574 | Operator::I32x4LeS
1575 | Operator::I32x4LeU
1576 | Operator::I32x4GeS
1577 | Operator::I32x4GeU
1578 | Operator::I64x2Eq
1579 | Operator::I64x2Ne
1580 | Operator::I64x2LtS
1581 | Operator::I64x2GtS
1582 | Operator::I64x2LeS
1583 | Operator::I64x2GeS
1584 | Operator::V128And
1585 | Operator::V128AndNot
1586 | Operator::V128Or
1587 | Operator::V128Xor
1588 | Operator::I8x16Add
1589 | Operator::I8x16AddSatS
1590 | Operator::I8x16AddSatU
1591 | Operator::I8x16Sub
1592 | Operator::I8x16SubSatS
1593 | Operator::I8x16SubSatU
1594 | Operator::I8x16MinS
1595 | Operator::I8x16MinU
1596 | Operator::I8x16MaxS
1597 | Operator::I8x16MaxU
1598 | Operator::I16x8Add
1599 | Operator::I16x8AddSatS
1600 | Operator::I16x8AddSatU
1601 | Operator::I16x8Sub
1602 | Operator::I16x8SubSatS
1603 | Operator::I16x8SubSatU
1604 | Operator::I16x8Mul
1605 | Operator::I16x8MinS
1606 | Operator::I16x8MinU
1607 | Operator::I16x8MaxS
1608 | Operator::I16x8MaxU
1609 | Operator::I32x4Add
1610 | Operator::I32x4Sub
1611 | Operator::I32x4Mul
1612 | Operator::I32x4MinS
1613 | Operator::I32x4MinU
1614 | Operator::I32x4MaxS
1615 | Operator::I32x4MaxU
1616 | Operator::I32x4DotI16x8S
1617 | Operator::I64x2Add
1618 | Operator::I64x2Sub
1619 | Operator::I64x2Mul
1620 | Operator::I8x16RoundingAverageU
1621 | Operator::I16x8RoundingAverageU
1622 | Operator::I8x16NarrowI16x8S
1623 | Operator::I8x16NarrowI16x8U
1624 | Operator::I16x8NarrowI32x4S
1625 | Operator::I16x8NarrowI32x4U
1626 | Operator::I16x8ExtMulLowI8x16S
1627 | Operator::I16x8ExtMulHighI8x16S
1628 | Operator::I16x8ExtMulLowI8x16U
1629 | Operator::I16x8ExtMulHighI8x16U
1630 | Operator::I32x4ExtMulLowI16x8S
1631 | Operator::I32x4ExtMulHighI16x8S
1632 | Operator::I32x4ExtMulLowI16x8U
1633 | Operator::I32x4ExtMulHighI16x8U
1634 | Operator::I64x2ExtMulLowI32x4S
1635 | Operator::I64x2ExtMulHighI32x4S
1636 | Operator::I64x2ExtMulLowI32x4U
1637 | Operator::I64x2ExtMulHighI32x4U
1638 | Operator::I16x8Q15MulrSatS => {
1639 self.check_simd_enabled()?;
1640 self.pop_operand(Some(Type::V128))?;
1641 self.pop_operand(Some(Type::V128))?;
1642 self.push_operand(Type::V128)?;
1643 }
1644 Operator::F32x4Ceil
1645 | Operator::F32x4Floor
1646 | Operator::F32x4Trunc
1647 | Operator::F32x4Nearest
1648 | Operator::F64x2Ceil
1649 | Operator::F64x2Floor
1650 | Operator::F64x2Trunc
1651 | Operator::F64x2Nearest
1652 | Operator::F32x4Abs
1653 | Operator::F32x4Neg
1654 | Operator::F32x4Sqrt
1655 | Operator::F64x2Abs
1656 | Operator::F64x2Neg
1657 | Operator::F64x2Sqrt
1658 | Operator::F32x4DemoteF64x2Zero
1659 | Operator::F64x2PromoteLowF32x4
1660 | Operator::F64x2ConvertLowI32x4S
1661 | Operator::F64x2ConvertLowI32x4U
1662 | Operator::I32x4TruncSatF64x2SZero
1663 | Operator::I32x4TruncSatF64x2UZero
1664 | Operator::F32x4ConvertI32x4S
1665 | Operator::F32x4ConvertI32x4U => {
1666 self.check_non_deterministic_enabled()?;
1667 self.check_simd_enabled()?;
1668 self.pop_operand(Some(Type::V128))?;
1669 self.push_operand(Type::V128)?;
1670 }
1671 Operator::V128Not
1672 | Operator::I8x16Abs
1673 | Operator::I8x16Neg
1674 | Operator::I8x16Popcnt
1675 | Operator::I16x8Abs
1676 | Operator::I16x8Neg
1677 | Operator::I32x4Abs
1678 | Operator::I32x4Neg
1679 | Operator::I64x2Abs
1680 | Operator::I64x2Neg
1681 | Operator::I32x4TruncSatF32x4S
1682 | Operator::I32x4TruncSatF32x4U
1683 | Operator::I16x8ExtendLowI8x16S
1684 | Operator::I16x8ExtendHighI8x16S
1685 | Operator::I16x8ExtendLowI8x16U
1686 | Operator::I16x8ExtendHighI8x16U
1687 | Operator::I32x4ExtendLowI16x8S
1688 | Operator::I32x4ExtendHighI16x8S
1689 | Operator::I32x4ExtendLowI16x8U
1690 | Operator::I32x4ExtendHighI16x8U
1691 | Operator::I64x2ExtendLowI32x4S
1692 | Operator::I64x2ExtendHighI32x4S
1693 | Operator::I64x2ExtendLowI32x4U
1694 | Operator::I64x2ExtendHighI32x4U
1695 | Operator::I16x8ExtAddPairwiseI8x16S
1696 | Operator::I16x8ExtAddPairwiseI8x16U
1697 | Operator::I32x4ExtAddPairwiseI16x8S
1698 | Operator::I32x4ExtAddPairwiseI16x8U => {
1699 self.check_simd_enabled()?;
1700 self.pop_operand(Some(Type::V128))?;
1701 self.push_operand(Type::V128)?;
1702 }
1703 Operator::V128Bitselect => {
1704 self.check_simd_enabled()?;
1705 self.pop_operand(Some(Type::V128))?;
1706 self.pop_operand(Some(Type::V128))?;
1707 self.pop_operand(Some(Type::V128))?;
1708 self.push_operand(Type::V128)?;
1709 }
1710 Operator::V128AnyTrue
1711 | Operator::I8x16AllTrue
1712 | Operator::I8x16Bitmask
1713 | Operator::I16x8AllTrue
1714 | Operator::I16x8Bitmask
1715 | Operator::I32x4AllTrue
1716 | Operator::I32x4Bitmask
1717 | Operator::I64x2AllTrue
1718 | Operator::I64x2Bitmask => {
1719 self.check_simd_enabled()?;
1720 self.pop_operand(Some(Type::V128))?;
1721 self.push_operand(Type::I32)?;
1722 }
1723 Operator::I8x16Shl
1724 | Operator::I8x16ShrS
1725 | Operator::I8x16ShrU
1726 | Operator::I16x8Shl
1727 | Operator::I16x8ShrS
1728 | Operator::I16x8ShrU
1729 | Operator::I32x4Shl
1730 | Operator::I32x4ShrS
1731 | Operator::I32x4ShrU
1732 | Operator::I64x2Shl
1733 | Operator::I64x2ShrS
1734 | Operator::I64x2ShrU => {
1735 self.check_simd_enabled()?;
1736 self.pop_operand(Some(Type::I32))?;
1737 self.pop_operand(Some(Type::V128))?;
1738 self.push_operand(Type::V128)?;
1739 }
1740 Operator::I8x16Swizzle => {
1741 self.check_simd_enabled()?;
1742 self.pop_operand(Some(Type::V128))?;
1743 self.pop_operand(Some(Type::V128))?;
1744 self.push_operand(Type::V128)?;
1745 }
1746 Operator::I8x16Shuffle { ref lanes } => {
1747 self.check_simd_enabled()?;
1748 self.pop_operand(Some(Type::V128))?;
1749 self.pop_operand(Some(Type::V128))?;
1750 for i in lanes {
1751 self.check_simd_lane_index(*i, 32)?;
1752 }
1753 self.push_operand(Type::V128)?;
1754 }
1755 Operator::V128Load8Splat { memarg } => {
1756 self.check_simd_enabled()?;
1757 let ty = self.check_memarg(memarg, 0, resources)?;
1758 self.pop_operand(Some(ty))?;
1759 self.push_operand(Type::V128)?;
1760 }
1761 Operator::V128Load16Splat { memarg } => {
1762 self.check_simd_enabled()?;
1763 let ty = self.check_memarg(memarg, 1, resources)?;
1764 self.pop_operand(Some(ty))?;
1765 self.push_operand(Type::V128)?;
1766 }
1767 Operator::V128Load32Splat { memarg } | Operator::V128Load32Zero { memarg } => {
1768 self.check_simd_enabled()?;
1769 let ty = self.check_memarg(memarg, 2, resources)?;
1770 self.pop_operand(Some(ty))?;
1771 self.push_operand(Type::V128)?;
1772 }
1773 Operator::V128Load64Splat { memarg }
1774 | Operator::V128Load64Zero { memarg }
1775 | Operator::V128Load8x8S { memarg }
1776 | Operator::V128Load8x8U { memarg }
1777 | Operator::V128Load16x4S { memarg }
1778 | Operator::V128Load16x4U { memarg }
1779 | Operator::V128Load32x2S { memarg }
1780 | Operator::V128Load32x2U { memarg } => {
1781 self.check_simd_enabled()?;
1782 let idx = self.check_memarg(memarg, 3, resources)?;
1783 self.pop_operand(Some(idx))?;
1784 self.push_operand(Type::V128)?;
1785 }
1786 Operator::V128Load8Lane { memarg, lane } => {
1787 self.check_simd_enabled()?;
1788 let idx = self.check_memarg(memarg, 0, resources)?;
1789 self.check_simd_lane_index(lane, 16)?;
1790 self.pop_operand(Some(Type::V128))?;
1791 self.pop_operand(Some(idx))?;
1792 self.push_operand(Type::V128)?;
1793 }
1794 Operator::V128Load16Lane { memarg, lane } => {
1795 self.check_simd_enabled()?;
1796 let idx = self.check_memarg(memarg, 1, resources)?;
1797 self.check_simd_lane_index(lane, 8)?;
1798 self.pop_operand(Some(Type::V128))?;
1799 self.pop_operand(Some(idx))?;
1800 self.push_operand(Type::V128)?;
1801 }
1802 Operator::V128Load32Lane { memarg, lane } => {
1803 self.check_simd_enabled()?;
1804 let idx = self.check_memarg(memarg, 2, resources)?;
1805 self.check_simd_lane_index(lane, 4)?;
1806 self.pop_operand(Some(Type::V128))?;
1807 self.pop_operand(Some(idx))?;
1808 self.push_operand(Type::V128)?;
1809 }
1810 Operator::V128Load64Lane { memarg, lane } => {
1811 self.check_simd_enabled()?;
1812 let idx = self.check_memarg(memarg, 3, resources)?;
1813 self.check_simd_lane_index(lane, 2)?;
1814 self.pop_operand(Some(Type::V128))?;
1815 self.pop_operand(Some(idx))?;
1816 self.push_operand(Type::V128)?;
1817 }
1818 Operator::V128Store8Lane { memarg, lane } => {
1819 self.check_simd_enabled()?;
1820 let idx = self.check_memarg(memarg, 0, resources)?;
1821 self.check_simd_lane_index(lane, 16)?;
1822 self.pop_operand(Some(Type::V128))?;
1823 self.pop_operand(Some(idx))?;
1824 }
1825 Operator::V128Store16Lane { memarg, lane } => {
1826 self.check_simd_enabled()?;
1827 let idx = self.check_memarg(memarg, 1, resources)?;
1828 self.check_simd_lane_index(lane, 8)?;
1829 self.pop_operand(Some(Type::V128))?;
1830 self.pop_operand(Some(idx))?;
1831 }
1832 Operator::V128Store32Lane { memarg, lane } => {
1833 self.check_simd_enabled()?;
1834 let idx = self.check_memarg(memarg, 2, resources)?;
1835 self.check_simd_lane_index(lane, 4)?;
1836 self.pop_operand(Some(Type::V128))?;
1837 self.pop_operand(Some(idx))?;
1838 }
1839 Operator::V128Store64Lane { memarg, lane } => {
1840 self.check_simd_enabled()?;
1841 let idx = self.check_memarg(memarg, 3, resources)?;
1842 self.check_simd_lane_index(lane, 2)?;
1843 self.pop_operand(Some(Type::V128))?;
1844 self.pop_operand(Some(idx))?;
1845 }
1846 Operator::MemoryInit { mem, segment } => {
1847 self.check_bulk_memory_enabled()?;
1848 let ty = self.check_memory_index(mem, resources)?;
1849 if segment >= resources.data_count() {
1850 bail_op_err!("unknown data segment {}", segment);
1851 }
1852 self.pop_operand(Some(Type::I32))?;
1853 self.pop_operand(Some(Type::I32))?;
1854 self.pop_operand(Some(ty))?;
1855 }
1856 Operator::DataDrop { segment } => {
1857 self.check_bulk_memory_enabled()?;
1858 if segment >= resources.data_count() {
1859 bail_op_err!("unknown data segment {}", segment);
1860 }
1861 }
1862 Operator::MemoryCopy { src, dst } => {
1863 self.check_bulk_memory_enabled()?;
1864 let dst_ty = self.check_memory_index(dst, resources)?;
1865 let src_ty = self.check_memory_index(src, resources)?;
1866 self.pop_operand(Some(match src_ty {
1867 Type::I32 => Type::I32,
1868 _ => dst_ty,
1869 }))?;
1870 self.pop_operand(Some(src_ty))?;
1871 self.pop_operand(Some(dst_ty))?;
1872 }
1873 Operator::MemoryFill { mem } => {
1874 self.check_bulk_memory_enabled()?;
1875 let ty = self.check_memory_index(mem, resources)?;
1876 self.pop_operand(Some(ty))?;
1877 self.pop_operand(Some(Type::I32))?;
1878 self.pop_operand(Some(ty))?;
1879 }
1880 Operator::TableInit { segment, table } => {
1881 self.check_bulk_memory_enabled()?;
1882 if table > 0 {
1883 self.check_reference_types_enabled()?;
1884 }
1885 let table = match resources.table_at(table) {
1886 Some(table) => table,
1887 None => bail_op_err!("unknown table {}: table index out of bounds", table),
1888 };
1889 let segment_ty = match resources.element_type_at(segment) {
1890 Some(ty) => ty,
1891 None => bail_op_err!(
1892 "unknown elem segment {}: segment index out of bounds",
1893 segment
1894 ),
1895 };
1896 if segment_ty != table.element_type {
1897 return Err(OperatorValidatorError::new("type mismatch"));
1898 }
1899 self.pop_operand(Some(Type::I32))?;
1900 self.pop_operand(Some(Type::I32))?;
1901 self.pop_operand(Some(Type::I32))?;
1902 }
1903 Operator::ElemDrop { segment } => {
1904 self.check_bulk_memory_enabled()?;
1905 if segment >= resources.element_count() {
1906 bail_op_err!(
1907 "unknown elem segment {}: segment index out of bounds",
1908 segment
1909 );
1910 }
1911 }
1912 Operator::TableCopy {
1913 src_table,
1914 dst_table,
1915 } => {
1916 self.check_bulk_memory_enabled()?;
1917 if src_table > 0 || dst_table > 0 {
1918 self.check_reference_types_enabled()?;
1919 }
1920 let (src, dst) =
1921 match (resources.table_at(src_table), resources.table_at(dst_table)) {
1922 (Some(a), Some(b)) => (a, b),
1923 _ => return Err(OperatorValidatorError::new("table index out of bounds")),
1924 };
1925 if src.element_type != dst.element_type {
1926 return Err(OperatorValidatorError::new("type mismatch"));
1927 }
1928 self.pop_operand(Some(Type::I32))?;
1929 self.pop_operand(Some(Type::I32))?;
1930 self.pop_operand(Some(Type::I32))?;
1931 }
1932 Operator::TableGet { table } => {
1933 self.check_reference_types_enabled()?;
1934 let ty = match resources.table_at(table) {
1935 Some(ty) => ty.element_type,
1936 None => return Err(OperatorValidatorError::new("table index out of bounds")),
1937 };
1938 self.pop_operand(Some(Type::I32))?;
1939 self.push_operand(ty)?;
1940 }
1941 Operator::TableSet { table } => {
1942 self.check_reference_types_enabled()?;
1943 let ty = match resources.table_at(table) {
1944 Some(ty) => ty.element_type,
1945 None => return Err(OperatorValidatorError::new("table index out of bounds")),
1946 };
1947 self.pop_operand(Some(ty))?;
1948 self.pop_operand(Some(Type::I32))?;
1949 }
1950 Operator::TableGrow { table } => {
1951 self.check_reference_types_enabled()?;
1952 let ty = match resources.table_at(table) {
1953 Some(ty) => ty.element_type,
1954 None => return Err(OperatorValidatorError::new("table index out of bounds")),
1955 };
1956 self.pop_operand(Some(Type::I32))?;
1957 self.pop_operand(Some(ty))?;
1958 self.push_operand(Type::I32)?;
1959 }
1960 Operator::TableSize { table } => {
1961 self.check_reference_types_enabled()?;
1962 if resources.table_at(table).is_none() {
1963 return Err(OperatorValidatorError::new("table index out of bounds"));
1964 }
1965 self.push_operand(Type::I32)?;
1966 }
1967 Operator::TableFill { table } => {
1968 self.check_bulk_memory_enabled()?;
1969 let ty = match resources.table_at(table) {
1970 Some(ty) => ty.element_type,
1971 None => return Err(OperatorValidatorError::new("table index out of bounds")),
1972 };
1973 self.pop_operand(Some(Type::I32))?;
1974 self.pop_operand(Some(ty))?;
1975 self.pop_operand(Some(Type::I32))?;
1976 }
1977 }
1978 Ok(())
1979 }
1980
finish(&mut self) -> OperatorValidatorResult<()>1981 pub fn finish(&mut self) -> OperatorValidatorResult<()> {
1982 if self.control.len() != 0 {
1983 bail_op_err!("control frames remain at end of function");
1984 }
1985 Ok(())
1986 }
1987 }
1988
func_type_at<T: WasmModuleResources>( resources: &T, at: u32, ) -> OperatorValidatorResult<&T::FuncType>1989 fn func_type_at<T: WasmModuleResources>(
1990 resources: &T,
1991 at: u32,
1992 ) -> OperatorValidatorResult<&T::FuncType> {
1993 resources
1994 .func_type_at(at)
1995 .ok_or_else(|| OperatorValidatorError::new("unknown type: type index out of bounds"))
1996 }
1997
event_at<T: WasmModuleResources>( resources: &T, at: u32, ) -> OperatorValidatorResult<&T::FuncType>1998 fn event_at<T: WasmModuleResources>(
1999 resources: &T,
2000 at: u32,
2001 ) -> OperatorValidatorResult<&T::FuncType> {
2002 resources
2003 .event_at(at)
2004 .ok_or_else(|| OperatorValidatorError::new("unknown event: event index out of bounds"))
2005 }
2006
2007 enum Either<A, B> {
2008 A(A),
2009 B(B),
2010 }
2011
2012 impl<A, B> Iterator for Either<A, B>
2013 where
2014 A: Iterator,
2015 B: Iterator<Item = A::Item>,
2016 {
2017 type Item = A::Item;
next(&mut self) -> Option<A::Item>2018 fn next(&mut self) -> Option<A::Item> {
2019 match self {
2020 Either::A(a) => a.next(),
2021 Either::B(b) => b.next(),
2022 }
2023 }
2024 }
2025 impl<A, B> DoubleEndedIterator for Either<A, B>
2026 where
2027 A: DoubleEndedIterator,
2028 B: DoubleEndedIterator<Item = A::Item>,
2029 {
next_back(&mut self) -> Option<A::Item>2030 fn next_back(&mut self) -> Option<A::Item> {
2031 match self {
2032 Either::A(a) => a.next_back(),
2033 Either::B(b) => b.next_back(),
2034 }
2035 }
2036 }
2037
params<'a>( ty: TypeOrFuncType, resources: &'a impl WasmModuleResources, ) -> OperatorValidatorResult<impl DoubleEndedIterator<Item = Type> + 'a>2038 fn params<'a>(
2039 ty: TypeOrFuncType,
2040 resources: &'a impl WasmModuleResources,
2041 ) -> OperatorValidatorResult<impl DoubleEndedIterator<Item = Type> + 'a> {
2042 Ok(match ty {
2043 TypeOrFuncType::FuncType(t) => Either::A(func_type_at(resources, t)?.inputs()),
2044 TypeOrFuncType::Type(_) => Either::B(None.into_iter()),
2045 })
2046 }
2047
results<'a>( ty: TypeOrFuncType, resources: &'a impl WasmModuleResources, ) -> OperatorValidatorResult<impl DoubleEndedIterator<Item = Type> + 'a>2048 fn results<'a>(
2049 ty: TypeOrFuncType,
2050 resources: &'a impl WasmModuleResources,
2051 ) -> OperatorValidatorResult<impl DoubleEndedIterator<Item = Type> + 'a> {
2052 Ok(match ty {
2053 TypeOrFuncType::FuncType(t) => Either::A(func_type_at(resources, t)?.outputs()),
2054 TypeOrFuncType::Type(Type::EmptyBlockType) => Either::B(None.into_iter()),
2055 TypeOrFuncType::Type(t) => Either::B(Some(t).into_iter()),
2056 })
2057 }
2058
label_types<'a>( ty: TypeOrFuncType, resources: &'a impl WasmModuleResources, kind: FrameKind, ) -> OperatorValidatorResult<impl DoubleEndedIterator<Item = Type> + 'a>2059 fn label_types<'a>(
2060 ty: TypeOrFuncType,
2061 resources: &'a impl WasmModuleResources,
2062 kind: FrameKind,
2063 ) -> OperatorValidatorResult<impl DoubleEndedIterator<Item = Type> + 'a> {
2064 Ok(match kind {
2065 FrameKind::Loop => Either::A(params(ty, resources)?),
2066 _ => Either::B(results(ty, resources)?),
2067 })
2068 }
2069
ty_to_str(ty: Type) -> &'static str2070 fn ty_to_str(ty: Type) -> &'static str {
2071 match ty {
2072 Type::I32 => "i32",
2073 Type::I64 => "i64",
2074 Type::F32 => "f32",
2075 Type::F64 => "f64",
2076 Type::V128 => "v128",
2077 Type::FuncRef => "funcref",
2078 Type::ExternRef => "externref",
2079 Type::ExnRef => "exnref",
2080 Type::Func => "func",
2081 Type::EmptyBlockType => "nil",
2082 }
2083 }
2084