1use core::iter;
2
3use alloc::vec;
4use alloc::vec::Vec;
5
6use crate::{
7 core::reader::types::{FuncType, ResultType},
8 NumType, RefType, ValType, ValidationError,
9};
10
11#[derive(Debug, PartialEq, Eq)]
12pub struct ValidationStack {
13 stack: Vec<ValidationStackEntry>,
14 pub ctrl_stack: Vec<CtrlStackEntry>,
16}
17
18impl ValidationStack {
19 pub fn new() -> Self {
21 Self {
22 stack: Vec::new(),
23 ctrl_stack: vec![CtrlStackEntry {
24 label_info: LabelInfo::Untyped,
25 block_ty: FuncType {
26 params: ResultType {
27 valtypes: Vec::new(),
28 },
29 returns: ResultType {
30 valtypes: Vec::new(),
31 },
32 },
33 height: 0,
34 unreachable: false,
35 }],
36 }
37 }
38
39 pub(super) fn new_for_func(block_ty: FuncType) -> Self {
41 Self {
42 stack: Vec::new(),
43 ctrl_stack: vec![CtrlStackEntry {
44 label_info: LabelInfo::Func {
45 stps_to_backpatch: Vec::new(),
46 },
47 block_ty,
48 height: 0,
49 unreachable: false,
50 }],
51 }
52 }
53
54 pub fn len(&self) -> usize {
55 self.stack.len()
56 }
57
58 pub fn push_valtype(&mut self, valtype: ValType) {
59 self.stack.push(ValidationStackEntry::Val(valtype));
60 }
61
62 pub(super) fn drop_val(&mut self) -> Result<(), ValidationError> {
65 self.pop_valtype()
66 .map_err(|_| ValidationError::ExpectedAnOperand)?;
67 Ok(())
68 }
69
70 pub(super) fn make_unspecified(&mut self) -> Result<(), ValidationError> {
77 let last_ctrl_stack_entry = self
78 .ctrl_stack
79 .last_mut()
80 .ok_or(ValidationError::ValidationCtrlStackEmpty)?;
81 last_ctrl_stack_entry.unreachable = true;
82 self.stack.truncate(last_ctrl_stack_entry.height);
83 Ok(())
84 }
85
86 fn pop_valtype(&mut self) -> Result<ValidationStackEntry, ValidationError> {
95 let last_ctrl_stack_entry = self.ctrl_stack.last().unwrap();
99 assert!(self.stack.len() >= last_ctrl_stack_entry.height);
100 if last_ctrl_stack_entry.height == self.stack.len() {
101 if last_ctrl_stack_entry.unreachable {
102 Ok(ValidationStackEntry::Bottom)
103 } else {
104 Err(ValidationError::EndInvalidValueStack)
105 }
106 } else {
107 self.stack
109 .pop()
110 .ok_or(ValidationError::EndInvalidValueStack)
111 }
112 }
113
114 pub fn assert_pop_ref_type(
120 &mut self,
121 expected_ty: Option<RefType>,
122 ) -> Result<(), ValidationError> {
123 match self.pop_valtype()? {
124 ValidationStackEntry::Val(ValType::RefType(ref_type)) => {
125 expected_ty.map_or(Ok(()), |ty| {
126 (ty == ref_type)
127 .then_some(())
128 .ok_or(ValidationError::DifferentRefTypes(ref_type, ty))
129 })
130 }
131 ValidationStackEntry::Val(v) => Err(ValidationError::ExpectedARefType(v)),
132 ValidationStackEntry::Bottom => Ok(()),
133 }
134 }
135
136 pub fn assert_pop_val_type(&mut self, expected_ty: ValType) -> Result<(), ValidationError> {
142 match self.pop_valtype()? {
143 ValidationStackEntry::Val(ty) => (ty == expected_ty)
144 .then_some(())
145 .ok_or(ValidationError::InvalidValidationStackValType(Some(ty))),
146 ValidationStackEntry::Bottom => Ok(()),
147 }
148 }
149
150 fn assert_val_types_on_top_with_custom_stacks(
153 stack: &mut Vec<ValidationStackEntry>,
154 ctrl_stack: &[CtrlStackEntry],
155 expected_val_types: &[ValType],
156 unify_to_expected_types: bool,
157 ) -> Result<(), ValidationError> {
158 let last_ctrl_stack_entry = ctrl_stack
159 .last()
160 .ok_or(ValidationError::ValidationCtrlStackEmpty)?;
161 let stack_len = stack.len();
162
163 let rev_iterator = expected_val_types.iter().rev().enumerate();
164 for (i, expected_ty) in rev_iterator {
165 if stack_len - last_ctrl_stack_entry.height <= i {
166 if last_ctrl_stack_entry.unreachable {
167 if unify_to_expected_types {
168 stack.splice(
170 stack_len - i..stack_len - i,
171 expected_val_types[..expected_val_types.len() - i]
172 .iter()
173 .map(|ty| ValidationStackEntry::Val(*ty)),
174 );
175 } else {
176 stack.splice(
177 stack_len - i..stack_len - i,
178 iter::repeat(ValidationStackEntry::Bottom)
179 .take(expected_val_types.len() - i),
180 );
181 }
182 return Ok(());
183 } else {
184 return Err(ValidationError::EndInvalidValueStack);
185 }
186 }
187
188 let actual_ty = &mut stack[stack_len - i - 1];
190
191 match actual_ty {
192 ValidationStackEntry::Val(actual_val_ty) => {
193 if *actual_val_ty != *expected_ty {
194 return Err(ValidationError::EndInvalidValueStack);
195 }
196 }
197 ValidationStackEntry::Bottom => {
198 if unify_to_expected_types {
200 *actual_ty = ValidationStackEntry::Val(*expected_ty);
201 }
202 }
203 }
204 }
205
206 Ok(())
207 }
208
209 fn assert_val_types_with_custom_stacks(
210 stack: &mut Vec<ValidationStackEntry>,
211 ctrl_stack: &[CtrlStackEntry],
212 expected_val_types: &[ValType],
213 unify_to_expected_types: bool,
214 ) -> Result<(), ValidationError> {
215 ValidationStack::assert_val_types_on_top_with_custom_stacks(
216 stack,
217 ctrl_stack,
218 expected_val_types,
219 unify_to_expected_types,
220 )?;
221 let last_ctrl_stack_entry = &ctrl_stack[ctrl_stack.len() - 1];
223 if stack.len() == last_ctrl_stack_entry.height + expected_val_types.len() {
224 Ok(())
225 } else {
226 Err(ValidationError::EndInvalidValueStack)
227 }
228 }
229
230 pub(super) fn assert_val_types_on_top(
241 &mut self,
242 expected_val_types: &[ValType],
243 unify_to_expected_types: bool,
244 ) -> Result<(), ValidationError> {
245 ValidationStack::assert_val_types_on_top_with_custom_stacks(
246 &mut self.stack,
247 &self.ctrl_stack,
248 expected_val_types,
249 unify_to_expected_types,
250 )
251 }
252
253 pub fn assert_val_types(
263 &mut self,
264 expected_val_types: &[ValType],
265 unify_to_expected_types: bool,
266 ) -> Result<(), ValidationError> {
267 ValidationStack::assert_val_types_with_custom_stacks(
268 &mut self.stack,
269 &self.ctrl_stack,
270 expected_val_types,
271 unify_to_expected_types,
272 )
273 }
274
275 pub fn assert_val_types_of_label_jump_types_on_top(
285 &mut self,
286 label_idx: usize,
287 unify_to_expected_types: bool,
288 ) -> Result<(), ValidationError> {
289 let index_of_label_in_ctrl_stack = self
290 .ctrl_stack
291 .len()
292 .checked_sub(label_idx)
293 .and_then(|i| i.checked_sub(1));
294
295 let label_types = index_of_label_in_ctrl_stack
296 .and_then(|index_of_label_in_ctrl_stack| {
297 self.ctrl_stack.get(index_of_label_in_ctrl_stack)
298 })
299 .ok_or(ValidationError::InvalidLabelIdx(label_idx))?
300 .label_types();
301 ValidationStack::assert_val_types_on_top_with_custom_stacks(
302 &mut self.stack,
303 &self.ctrl_stack,
304 label_types,
305 unify_to_expected_types,
306 )
307 }
308
309 pub fn assert_push_ctrl(
318 &mut self,
319 label_info: LabelInfo,
320 block_ty: FuncType,
321 unify_to_expected_types: bool,
322 ) -> Result<(), ValidationError> {
323 self.assert_val_types_on_top(&block_ty.params.valtypes, unify_to_expected_types)?;
324 let height = self.stack.len() - block_ty.params.valtypes.len();
325 self.ctrl_stack.push(CtrlStackEntry {
326 label_info,
327 block_ty,
328 height,
329 unreachable: false,
330 });
331 Ok(())
332 }
333
334 pub fn assert_pop_ctrl(
343 &mut self,
344 unify_to_expected_types: bool,
345 ) -> Result<(LabelInfo, FuncType), ValidationError> {
346 let return_types = &self
347 .ctrl_stack
348 .last()
349 .ok_or(ValidationError::ValidationCtrlStackEmpty)?
350 .block_ty
351 .returns
352 .valtypes;
353 ValidationStack::assert_val_types_with_custom_stacks(
354 &mut self.stack,
355 &self.ctrl_stack,
356 return_types,
357 unify_to_expected_types,
358 )?;
359
360 let last_ctrl_stack_entry = self.ctrl_stack.pop().unwrap();
362 Ok((
363 last_ctrl_stack_entry.label_info,
364 last_ctrl_stack_entry.block_ty,
365 ))
366 }
367
368 pub fn validate_polymorphic_select(&mut self) -> Result<(), ValidationError> {
370 self.assert_pop_val_type(ValType::NumType(crate::NumType::I32))?;
374
375 let first_arg = self.pop_valtype()?;
376 let second_arg = self.pop_valtype()?;
377
378 let unified_type = second_arg
379 .unify(&first_arg)
380 .ok_or(ValidationError::InvalidValidationStackValType(None))?;
381
382 if !(unified_type.unifies_to(&ValidationStackEntry::Val(ValType::NumType(NumType::I32)))
384 || unified_type.unifies_to(&ValidationStackEntry::Val(ValType::NumType(NumType::F32)))
385 || unified_type.unifies_to(&ValidationStackEntry::Val(ValType::NumType(NumType::I64)))
386 || unified_type.unifies_to(&ValidationStackEntry::Val(ValType::NumType(NumType::F64)))
387 || unified_type.unifies_to(&ValidationStackEntry::Val(ValType::VecType)))
388 {
389 return Err(ValidationError::InvalidValidationStackValType(None));
390 }
391
392 self.stack.push(unified_type);
393 Ok(())
394 }
395}
396
397#[derive(Clone, Debug, PartialEq, Eq)]
399pub enum ValidationStackEntry {
400 Val(ValType),
401 Bottom,
402}
403
404impl ValidationStackEntry {
405 fn unifies_to(&self, other: &ValidationStackEntry) -> bool {
407 match self {
408 ValidationStackEntry::Bottom => true,
409 ValidationStackEntry::Val(_) => self == other,
410 }
411 }
412
413 fn unify(&self, other: &ValidationStackEntry) -> Option<Self> {
415 self.unifies_to(other).then(|| other.clone())
416 }
417}
418
419#[derive(Clone, Debug, PartialEq, Eq)]
421pub struct CtrlStackEntry {
422 pub label_info: LabelInfo,
423 pub block_ty: FuncType,
424 pub height: usize,
425 pub unreachable: bool,
426}
427
428impl CtrlStackEntry {
429 pub fn label_types(&self) -> &[ValType] {
430 if matches!(self.label_info, LabelInfo::Loop { .. }) {
431 &self.block_ty.params.valtypes
432 } else {
433 &self.block_ty.returns.valtypes
434 }
435 }
436}
437
438#[derive(Clone, Debug, PartialEq, Eq)]
442pub enum LabelInfo {
443 Block {
444 stps_to_backpatch: Vec<usize>,
445 },
446 Loop {
447 ip: usize,
448 stp: usize,
449 },
450 If {
451 stps_to_backpatch: Vec<usize>,
452 stp: usize,
453 },
454 Func {
455 stps_to_backpatch: Vec<usize>,
456 },
457 Untyped,
458}
459
460#[cfg(test)]
461mod tests {
462 use crate::{NumType, RefType, ValType};
463
464 use super::{CtrlStackEntry, FuncType, LabelInfo, ResultType, ValidationStack, Vec};
465
466 fn push_dummy_untyped_label(validation_stack: &mut ValidationStack) {
467 validation_stack.ctrl_stack.push(CtrlStackEntry {
468 label_info: LabelInfo::Untyped,
469 block_ty: FuncType {
470 params: ResultType {
471 valtypes: Vec::new(),
472 },
473 returns: ResultType {
474 valtypes: Vec::new(),
475 },
476 },
477 height: validation_stack.len(),
478 unreachable: false,
479 })
480 }
481
482 #[test]
483 fn push_then_pop() {
484 let mut stack = ValidationStack::new();
485
486 stack.push_valtype(ValType::NumType(NumType::F64));
487 stack.push_valtype(ValType::NumType(NumType::I32));
488 stack.push_valtype(ValType::VecType);
489 stack.push_valtype(ValType::RefType(RefType::ExternRef));
490
491 stack
492 .assert_pop_val_type(ValType::RefType(RefType::ExternRef))
493 .unwrap();
494 stack.assert_pop_val_type(ValType::VecType).unwrap();
495 stack
496 .assert_pop_val_type(ValType::NumType(NumType::I32))
497 .unwrap();
498 stack
499 .assert_pop_val_type(ValType::NumType(NumType::F64))
500 .unwrap();
501 }
502
503 #[test]
537 fn assert_valtypes() {
538 let mut stack = ValidationStack::new();
539
540 stack.push_valtype(ValType::NumType(NumType::F64));
541 stack.push_valtype(ValType::NumType(NumType::I32));
542 stack.push_valtype(ValType::NumType(NumType::F32));
543
544 stack
545 .assert_val_types(
546 &[
547 ValType::NumType(NumType::F64),
548 ValType::NumType(NumType::I32),
549 ValType::NumType(NumType::F32),
550 ],
551 true,
552 )
553 .unwrap();
554
555 push_dummy_untyped_label(&mut stack);
556
557 stack.push_valtype(ValType::NumType(NumType::I32));
558
559 stack
560 .assert_val_types(&[ValType::NumType(NumType::I32)], true)
561 .unwrap();
562 }
563
564 #[test]
565 fn assert_emtpy_valtypes() {
566 let mut stack = ValidationStack::new();
567
568 stack.assert_val_types(&[], true).unwrap();
569
570 stack.push_valtype(ValType::NumType(NumType::I32));
571 push_dummy_untyped_label(&mut stack);
572
573 stack.assert_val_types(&[], true).unwrap();
575 }
576
577 #[test]
578 fn assert_valtypes_on_top() {
579 let mut stack = ValidationStack::new();
580
581 stack.assert_val_types_on_top(&[], true).unwrap();
582
583 stack.push_valtype(ValType::NumType(NumType::I32));
584 stack.push_valtype(ValType::NumType(NumType::F32));
585 stack.push_valtype(ValType::NumType(NumType::I64));
586
587 stack.assert_val_types_on_top(&[], true).unwrap();
589
590 stack
591 .assert_val_types_on_top(&[ValType::NumType(NumType::I64)], true)
592 .unwrap();
593
594 stack
595 .assert_val_types_on_top(
596 &[
597 ValType::NumType(NumType::F32),
598 ValType::NumType(NumType::I64),
599 ],
600 true,
601 )
602 .unwrap();
603
604 stack
605 .assert_val_types_on_top(
606 &[
607 ValType::NumType(NumType::I32),
608 ValType::NumType(NumType::F32),
609 ValType::NumType(NumType::I64),
610 ],
611 true,
612 )
613 .unwrap();
614 }
615
616 #[test]
617 fn unspecified() {
618 let mut stack = ValidationStack::new();
619 push_dummy_untyped_label(&mut stack);
620
621 stack.make_unspecified().unwrap();
622
623 stack
625 .assert_pop_val_type(ValType::NumType(NumType::I32))
626 .unwrap();
627
628 stack
629 .assert_pop_val_type(ValType::RefType(RefType::ExternRef))
630 .unwrap();
631
632 stack.ctrl_stack.pop();
636
637 assert_eq!(stack.assert_val_types(&[], true), Ok(()));
639 }
640
641 #[test]
642 fn unspecified2() {
643 let mut stack = ValidationStack::new();
644 push_dummy_untyped_label(&mut stack);
645
646 stack.make_unspecified().unwrap();
647
648 stack
650 .assert_val_types(
651 &[
652 ValType::NumType(NumType::I64),
653 ValType::NumType(NumType::F32),
654 ValType::NumType(NumType::I32),
655 ],
656 true,
657 )
658 .unwrap();
659
660 stack.ctrl_stack.pop();
661
662 assert_eq!(
663 stack.assert_pop_val_type(ValType::NumType(NumType::I32)),
664 Ok(())
665 );
666 assert_eq!(
667 stack.assert_pop_val_type(ValType::NumType(NumType::F32)),
668 Ok(())
669 );
670 assert_eq!(
671 stack.assert_pop_val_type(ValType::NumType(NumType::I64)),
672 Ok(())
673 );
674 }
675
676 #[test]
677 fn unspecified3() {
678 let mut stack = ValidationStack::new();
679 push_dummy_untyped_label(&mut stack);
680
681 stack.make_unspecified().unwrap();
682
683 stack.push_valtype(ValType::NumType(NumType::I32));
684
685 stack
688 .assert_val_types(
689 &[
690 ValType::NumType(NumType::I64),
691 ValType::NumType(NumType::F32),
692 ValType::NumType(NumType::I32),
693 ],
694 true,
695 )
696 .unwrap();
697
698 stack.ctrl_stack.pop();
699
700 assert_eq!(
701 stack.assert_pop_val_type(ValType::NumType(NumType::I32)),
702 Ok(())
703 );
704 assert_eq!(
705 stack.assert_pop_val_type(ValType::NumType(NumType::F32)),
706 Ok(())
707 );
708 assert_eq!(
709 stack.assert_pop_val_type(ValType::NumType(NumType::I64)),
710 Ok(())
711 );
712 }
713
714 #[test]
715 fn unspecified4() {
716 let mut stack = ValidationStack::new();
717
718 stack.push_valtype(ValType::VecType);
719 stack.push_valtype(ValType::NumType(NumType::I32));
720
721 push_dummy_untyped_label(&mut stack);
722
723 stack.make_unspecified().unwrap();
724
725 stack.push_valtype(ValType::VecType);
726 stack.push_valtype(ValType::RefType(RefType::FuncRef));
727
728 stack
731 .assert_val_types(
732 &[
733 ValType::NumType(NumType::I64),
734 ValType::NumType(NumType::F32),
735 ValType::VecType,
736 ValType::RefType(RefType::FuncRef),
737 ],
738 true,
739 )
740 .unwrap();
741
742 stack.ctrl_stack.pop();
743
744 assert_eq!(
745 stack.assert_pop_val_type(ValType::RefType(RefType::FuncRef)),
746 Ok(())
747 );
748 assert_eq!(stack.assert_pop_val_type(ValType::VecType), Ok(()));
749 assert_eq!(
750 stack.assert_pop_val_type(ValType::NumType(NumType::F32)),
751 Ok(())
752 );
753 assert_eq!(
754 stack.assert_pop_val_type(ValType::NumType(NumType::I64)),
755 Ok(())
756 );
757 assert_eq!(
758 stack.assert_pop_val_type(ValType::NumType(NumType::I32)),
759 Ok(())
760 );
761 assert_eq!(stack.assert_pop_val_type(ValType::VecType), Ok(()));
762 }
763}