1use core::iter;
2
3use super::Result;
4use alloc::vec;
5use alloc::vec::Vec;
6
7use crate::{
8 core::reader::types::{FuncType, ResultType},
9 Error, NumType, RefType, ValType,
10};
11
12#[derive(Debug, PartialEq, Eq)]
13pub struct ValidationStack {
14 stack: Vec<ValidationStackEntry>,
15 pub ctrl_stack: Vec<CtrlStackEntry>,
17}
18
19impl ValidationStack {
20 pub fn new() -> Self {
22 Self {
23 stack: Vec::new(),
24 ctrl_stack: vec![CtrlStackEntry {
25 label_info: LabelInfo::Untyped,
26 block_ty: FuncType {
27 params: ResultType {
28 valtypes: Vec::new(),
29 },
30 returns: ResultType {
31 valtypes: Vec::new(),
32 },
33 },
34 height: 0,
35 unreachable: false,
36 }],
37 }
38 }
39
40 pub(super) fn new_for_func(block_ty: FuncType) -> Self {
42 Self {
43 stack: Vec::new(),
44 ctrl_stack: vec![CtrlStackEntry {
45 label_info: LabelInfo::Func {
46 stps_to_backpatch: Vec::new(),
47 },
48 block_ty,
49 height: 0,
50 unreachable: false,
51 }],
52 }
53 }
54
55 pub fn len(&self) -> usize {
56 self.stack.len()
57 }
58
59 pub fn push_valtype(&mut self, valtype: ValType) {
60 self.stack.push(ValidationStackEntry::Val(valtype));
61 }
62
63 pub(super) fn drop_val(&mut self) -> Result<()> {
66 self.pop_valtype().map_err(|_| Error::ExpectedAnOperand)?;
67 Ok(())
68 }
69
70 pub(super) fn make_unspecified(&mut self) -> Result<()> {
77 let last_ctrl_stack_entry = self
78 .ctrl_stack
79 .last_mut()
80 .ok_or(Error::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> {
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(Error::EndInvalidValueStack)
105 }
106 } else {
107 self.stack.pop().ok_or(Error::EndInvalidValueStack)
109 }
110 }
111
112 pub fn assert_pop_ref_type(&mut self, expected_ty: Option<RefType>) -> Result<()> {
118 match self.pop_valtype()? {
119 ValidationStackEntry::Val(ValType::RefType(ref_type)) => {
120 expected_ty.map_or(Ok(()), |ty| {
121 (ty == ref_type)
122 .then_some(())
123 .ok_or(Error::DifferentRefTypes(ref_type, ty))
124 })
125 }
126 ValidationStackEntry::Val(v) => Err(Error::ExpectedARefType(v)),
127 ValidationStackEntry::Bottom => Ok(()),
128 }
129 }
130
131 pub fn assert_pop_val_type(&mut self, expected_ty: ValType) -> Result<()> {
137 match self.pop_valtype()? {
138 ValidationStackEntry::Val(ty) => (ty == expected_ty)
139 .then_some(())
140 .ok_or(Error::InvalidValidationStackValType(Some(ty))),
141 ValidationStackEntry::Bottom => Ok(()),
142 }
143 }
144
145 fn assert_val_types_on_top_with_custom_stacks(
148 stack: &mut Vec<ValidationStackEntry>,
149 ctrl_stack: &[CtrlStackEntry],
150 expected_val_types: &[ValType],
151 unify_to_expected_types: bool,
152 ) -> Result<()> {
153 let last_ctrl_stack_entry = ctrl_stack.last().ok_or(Error::ValidationCtrlStackEmpty)?;
154 let stack_len = stack.len();
155
156 let rev_iterator = expected_val_types.iter().rev().enumerate();
157 for (i, expected_ty) in rev_iterator {
158 if stack_len - last_ctrl_stack_entry.height <= i {
159 if last_ctrl_stack_entry.unreachable {
160 if unify_to_expected_types {
161 stack.splice(
163 stack_len - i..stack_len - i,
164 expected_val_types[..expected_val_types.len() - i]
165 .iter()
166 .map(|ty| ValidationStackEntry::Val(*ty)),
167 );
168 } else {
169 stack.splice(
170 stack_len - i..stack_len - i,
171 iter::repeat(ValidationStackEntry::Bottom)
172 .take(expected_val_types.len() - i),
173 );
174 }
175 return Ok(());
176 } else {
177 return Err(Error::EndInvalidValueStack);
178 }
179 }
180
181 let actual_ty = &mut stack[stack_len - i - 1];
183
184 match actual_ty {
185 ValidationStackEntry::Val(actual_val_ty) => {
186 if *actual_val_ty != *expected_ty {
187 return Err(Error::EndInvalidValueStack);
188 }
189 }
190 ValidationStackEntry::Bottom => {
191 if unify_to_expected_types {
193 *actual_ty = ValidationStackEntry::Val(*expected_ty);
194 }
195 }
196 }
197 }
198
199 Ok(())
200 }
201
202 fn assert_val_types_with_custom_stacks(
203 stack: &mut Vec<ValidationStackEntry>,
204 ctrl_stack: &[CtrlStackEntry],
205 expected_val_types: &[ValType],
206 unify_to_expected_types: bool,
207 ) -> Result<()> {
208 ValidationStack::assert_val_types_on_top_with_custom_stacks(
209 stack,
210 ctrl_stack,
211 expected_val_types,
212 unify_to_expected_types,
213 )?;
214 let last_ctrl_stack_entry = &ctrl_stack[ctrl_stack.len() - 1];
216 if stack.len() == last_ctrl_stack_entry.height + expected_val_types.len() {
217 Ok(())
218 } else {
219 Err(Error::EndInvalidValueStack)
220 }
221 }
222
223 pub(super) fn assert_val_types_on_top(
234 &mut self,
235 expected_val_types: &[ValType],
236 unify_to_expected_types: bool,
237 ) -> Result<()> {
238 ValidationStack::assert_val_types_on_top_with_custom_stacks(
239 &mut self.stack,
240 &self.ctrl_stack,
241 expected_val_types,
242 unify_to_expected_types,
243 )
244 }
245
246 pub fn assert_val_types(
256 &mut self,
257 expected_val_types: &[ValType],
258 unify_to_expected_types: bool,
259 ) -> Result<()> {
260 ValidationStack::assert_val_types_with_custom_stacks(
261 &mut self.stack,
262 &self.ctrl_stack,
263 expected_val_types,
264 unify_to_expected_types,
265 )
266 }
267
268 pub fn assert_val_types_of_label_jump_types_on_top(
278 &mut self,
279 label_idx: usize,
280 unify_to_expected_types: bool,
281 ) -> Result<()> {
282 let label_types = self
283 .ctrl_stack
284 .get(self.ctrl_stack.len() - label_idx - 1)
285 .ok_or(Error::InvalidLabelIdx(label_idx))?
286 .label_types();
287 ValidationStack::assert_val_types_on_top_with_custom_stacks(
288 &mut self.stack,
289 &self.ctrl_stack,
290 label_types,
291 unify_to_expected_types,
292 )
293 }
294
295 pub fn assert_push_ctrl(
304 &mut self,
305 label_info: LabelInfo,
306 block_ty: FuncType,
307 unify_to_expected_types: bool,
308 ) -> Result<()> {
309 self.assert_val_types_on_top(&block_ty.params.valtypes, unify_to_expected_types)?;
310 let height = self.stack.len() - block_ty.params.valtypes.len();
311 self.ctrl_stack.push(CtrlStackEntry {
312 label_info,
313 block_ty,
314 height,
315 unreachable: false,
316 });
317 Ok(())
318 }
319
320 pub fn assert_pop_ctrl(
329 &mut self,
330 unify_to_expected_types: bool,
331 ) -> Result<(LabelInfo, FuncType)> {
332 let return_types = &self
333 .ctrl_stack
334 .last()
335 .ok_or(Error::ValidationCtrlStackEmpty)?
336 .block_ty
337 .returns
338 .valtypes;
339 ValidationStack::assert_val_types_with_custom_stacks(
340 &mut self.stack,
341 &self.ctrl_stack,
342 return_types,
343 unify_to_expected_types,
344 )?;
345
346 let last_ctrl_stack_entry = self.ctrl_stack.pop().unwrap();
348 Ok((
349 last_ctrl_stack_entry.label_info,
350 last_ctrl_stack_entry.block_ty,
351 ))
352 }
353
354 pub fn validate_polymorphic_select(&mut self) -> Result<()> {
356 self.assert_pop_val_type(ValType::NumType(crate::NumType::I32))?;
360
361 let first_arg = self.pop_valtype()?;
362 let second_arg = self.pop_valtype()?;
363
364 let unified_type = second_arg
365 .unify(&first_arg)
366 .ok_or(Error::InvalidValidationStackValType(None))?;
367
368 if !(unified_type.unifies_to(&ValidationStackEntry::Val(ValType::NumType(NumType::I32)))
370 || unified_type.unifies_to(&ValidationStackEntry::Val(ValType::NumType(NumType::F32)))
371 || unified_type.unifies_to(&ValidationStackEntry::Val(ValType::NumType(NumType::I64)))
372 || unified_type.unifies_to(&ValidationStackEntry::Val(ValType::NumType(NumType::F64)))
373 || unified_type.unifies_to(&ValidationStackEntry::Val(ValType::VecType)))
374 {
375 return Err(Error::InvalidValidationStackValType(None));
376 }
377
378 self.stack.push(unified_type);
379 Ok(())
380 }
381}
382
383#[derive(Clone, Debug, PartialEq, Eq)]
385pub enum ValidationStackEntry {
386 Val(ValType),
387 Bottom,
388}
389
390impl ValidationStackEntry {
391 fn unifies_to(&self, other: &ValidationStackEntry) -> bool {
393 match self {
394 ValidationStackEntry::Bottom => true,
395 ValidationStackEntry::Val(_) => self == other,
396 }
397 }
398
399 fn unify(&self, other: &ValidationStackEntry) -> Option<Self> {
401 self.unifies_to(other).then(|| other.clone())
402 }
403}
404
405#[derive(Clone, Debug, PartialEq, Eq)]
407pub struct CtrlStackEntry {
408 pub label_info: LabelInfo,
409 pub block_ty: FuncType,
410 pub height: usize,
411 pub unreachable: bool,
412}
413
414impl CtrlStackEntry {
415 pub fn label_types(&self) -> &[ValType] {
416 if matches!(self.label_info, LabelInfo::Loop { .. }) {
417 &self.block_ty.params.valtypes
418 } else {
419 &self.block_ty.returns.valtypes
420 }
421 }
422}
423
424#[derive(Clone, Debug, PartialEq, Eq)]
428pub enum LabelInfo {
429 Block {
430 stps_to_backpatch: Vec<usize>,
431 },
432 Loop {
433 ip: usize,
434 stp: usize,
435 },
436 If {
437 stps_to_backpatch: Vec<usize>,
438 stp: usize,
439 },
440 Func {
441 stps_to_backpatch: Vec<usize>,
442 },
443 Untyped,
444}
445
446#[cfg(test)]
447mod tests {
448 use crate::{NumType, RefType, ValType};
449
450 use super::{CtrlStackEntry, FuncType, LabelInfo, ResultType, ValidationStack, Vec};
451
452 fn push_dummy_untyped_label(validation_stack: &mut ValidationStack) {
453 validation_stack.ctrl_stack.push(CtrlStackEntry {
454 label_info: LabelInfo::Untyped,
455 block_ty: FuncType {
456 params: ResultType {
457 valtypes: Vec::new(),
458 },
459 returns: ResultType {
460 valtypes: Vec::new(),
461 },
462 },
463 height: validation_stack.len(),
464 unreachable: false,
465 })
466 }
467
468 #[test]
469 fn push_then_pop() {
470 let mut stack = ValidationStack::new();
471
472 stack.push_valtype(ValType::NumType(NumType::F64));
473 stack.push_valtype(ValType::NumType(NumType::I32));
474 stack.push_valtype(ValType::VecType);
475 stack.push_valtype(ValType::RefType(RefType::ExternRef));
476
477 stack
478 .assert_pop_val_type(ValType::RefType(RefType::ExternRef))
479 .unwrap();
480 stack.assert_pop_val_type(ValType::VecType).unwrap();
481 stack
482 .assert_pop_val_type(ValType::NumType(NumType::I32))
483 .unwrap();
484 stack
485 .assert_pop_val_type(ValType::NumType(NumType::F64))
486 .unwrap();
487 }
488
489 #[test]
523 fn assert_valtypes() {
524 let mut stack = ValidationStack::new();
525
526 stack.push_valtype(ValType::NumType(NumType::F64));
527 stack.push_valtype(ValType::NumType(NumType::I32));
528 stack.push_valtype(ValType::NumType(NumType::F32));
529
530 stack
531 .assert_val_types(
532 &[
533 ValType::NumType(NumType::F64),
534 ValType::NumType(NumType::I32),
535 ValType::NumType(NumType::F32),
536 ],
537 true,
538 )
539 .unwrap();
540
541 push_dummy_untyped_label(&mut stack);
542
543 stack.push_valtype(ValType::NumType(NumType::I32));
544
545 stack
546 .assert_val_types(&[ValType::NumType(NumType::I32)], true)
547 .unwrap();
548 }
549
550 #[test]
551 fn assert_emtpy_valtypes() {
552 let mut stack = ValidationStack::new();
553
554 stack.assert_val_types(&[], true).unwrap();
555
556 stack.push_valtype(ValType::NumType(NumType::I32));
557 push_dummy_untyped_label(&mut stack);
558
559 stack.assert_val_types(&[], true).unwrap();
561 }
562
563 #[test]
564 fn assert_valtypes_on_top() {
565 let mut stack = ValidationStack::new();
566
567 stack.assert_val_types_on_top(&[], true).unwrap();
568
569 stack.push_valtype(ValType::NumType(NumType::I32));
570 stack.push_valtype(ValType::NumType(NumType::F32));
571 stack.push_valtype(ValType::NumType(NumType::I64));
572
573 stack.assert_val_types_on_top(&[], true).unwrap();
575
576 stack
577 .assert_val_types_on_top(&[ValType::NumType(NumType::I64)], true)
578 .unwrap();
579
580 stack
581 .assert_val_types_on_top(
582 &[
583 ValType::NumType(NumType::F32),
584 ValType::NumType(NumType::I64),
585 ],
586 true,
587 )
588 .unwrap();
589
590 stack
591 .assert_val_types_on_top(
592 &[
593 ValType::NumType(NumType::I32),
594 ValType::NumType(NumType::F32),
595 ValType::NumType(NumType::I64),
596 ],
597 true,
598 )
599 .unwrap();
600 }
601
602 #[test]
603 fn unspecified() {
604 let mut stack = ValidationStack::new();
605 push_dummy_untyped_label(&mut stack);
606
607 stack.make_unspecified().unwrap();
608
609 stack
611 .assert_pop_val_type(ValType::NumType(NumType::I32))
612 .unwrap();
613
614 stack
615 .assert_pop_val_type(ValType::RefType(RefType::ExternRef))
616 .unwrap();
617
618 stack.ctrl_stack.pop();
622
623 assert_eq!(stack.assert_val_types(&[], true), Ok(()));
625 }
626
627 #[test]
628 fn unspecified2() {
629 let mut stack = ValidationStack::new();
630 push_dummy_untyped_label(&mut stack);
631
632 stack.make_unspecified().unwrap();
633
634 stack
636 .assert_val_types(
637 &[
638 ValType::NumType(NumType::I64),
639 ValType::NumType(NumType::F32),
640 ValType::NumType(NumType::I32),
641 ],
642 true,
643 )
644 .unwrap();
645
646 stack.ctrl_stack.pop();
647
648 assert_eq!(
649 stack.assert_pop_val_type(ValType::NumType(NumType::I32)),
650 Ok(())
651 );
652 assert_eq!(
653 stack.assert_pop_val_type(ValType::NumType(NumType::F32)),
654 Ok(())
655 );
656 assert_eq!(
657 stack.assert_pop_val_type(ValType::NumType(NumType::I64)),
658 Ok(())
659 );
660 }
661
662 #[test]
663 fn unspecified3() {
664 let mut stack = ValidationStack::new();
665 push_dummy_untyped_label(&mut stack);
666
667 stack.make_unspecified().unwrap();
668
669 stack.push_valtype(ValType::NumType(NumType::I32));
670
671 stack
674 .assert_val_types(
675 &[
676 ValType::NumType(NumType::I64),
677 ValType::NumType(NumType::F32),
678 ValType::NumType(NumType::I32),
679 ],
680 true,
681 )
682 .unwrap();
683
684 stack.ctrl_stack.pop();
685
686 assert_eq!(
687 stack.assert_pop_val_type(ValType::NumType(NumType::I32)),
688 Ok(())
689 );
690 assert_eq!(
691 stack.assert_pop_val_type(ValType::NumType(NumType::F32)),
692 Ok(())
693 );
694 assert_eq!(
695 stack.assert_pop_val_type(ValType::NumType(NumType::I64)),
696 Ok(())
697 );
698 }
699
700 #[test]
701 fn unspecified4() {
702 let mut stack = ValidationStack::new();
703
704 stack.push_valtype(ValType::VecType);
705 stack.push_valtype(ValType::NumType(NumType::I32));
706
707 push_dummy_untyped_label(&mut stack);
708
709 stack.make_unspecified().unwrap();
710
711 stack.push_valtype(ValType::VecType);
712 stack.push_valtype(ValType::RefType(RefType::FuncRef));
713
714 stack
717 .assert_val_types(
718 &[
719 ValType::NumType(NumType::I64),
720 ValType::NumType(NumType::F32),
721 ValType::VecType,
722 ValType::RefType(RefType::FuncRef),
723 ],
724 true,
725 )
726 .unwrap();
727
728 stack.ctrl_stack.pop();
729
730 assert_eq!(
731 stack.assert_pop_val_type(ValType::RefType(RefType::FuncRef)),
732 Ok(())
733 );
734 assert_eq!(stack.assert_pop_val_type(ValType::VecType), Ok(()));
735 assert_eq!(
736 stack.assert_pop_val_type(ValType::NumType(NumType::F32)),
737 Ok(())
738 );
739 assert_eq!(
740 stack.assert_pop_val_type(ValType::NumType(NumType::I64)),
741 Ok(())
742 );
743 assert_eq!(
744 stack.assert_pop_val_type(ValType::NumType(NumType::I32)),
745 Ok(())
746 );
747 assert_eq!(stack.assert_pop_val_type(ValType::VecType), Ok(()));
748 }
749}