wasmprinter/
operand_stack.rs1use crate::{Config, PrintTermcolor, Printer};
2use wasmparser::{
3 BinaryReader, Frame, OperatorsReader, Payload, Result, ValType, ValidPayload,
4 ValidatorResources, WasmFeatures,
5};
6
7pub struct Validator {
8 validator: wasmparser::Validator,
9 last_function: Option<FuncValidator>,
10}
11
12impl Validator {
13 pub fn new() -> Option<Validator> {
14 Some(Validator {
15 validator: wasmparser::Validator::new_with_features(WasmFeatures::all()),
16 last_function: None,
17 })
18 }
19
20 pub fn payload(&mut self, payload: &Payload<'_>) -> Result<()> {
21 match self.validator.payload(payload)? {
22 ValidPayload::Ok | ValidPayload::End(_) | ValidPayload::Parser(_) => Ok(()),
23 ValidPayload::Func(validator, _) => {
24 assert!(self.last_function.is_none());
25 self.last_function = Some(FuncValidator {
26 push_count: 0,
27 validator: validator.into_validator(Default::default()),
28 });
29 Ok(())
30 }
31 }
32 }
33
34 pub fn next_func(&mut self) -> Option<FuncValidator> {
35 Some(self.last_function.take().unwrap())
36 }
37}
38
39pub struct FuncValidator {
40 validator: wasmparser::FuncValidator<ValidatorResources>,
41 push_count: u32,
42}
43
44impl FuncValidator {
45 pub fn read_locals(&mut self, mut reader: BinaryReader<'_>) -> Result<()> {
46 self.validator.read_locals(&mut reader)
47 }
48
49 pub fn visit_operator(&mut self, reader: &OperatorsReader<'_>, is_end: bool) -> Result<()> {
50 let pos = reader.original_position();
51 reader
52 .clone()
53 .visit_operator(&mut self.validator.visitor(pos))??;
54
55 if !is_end {
56 let op = reader.clone().read()?;
57 let arity = op.operator_arity(&self.validator.visitor(pos));
58 if let Some((_pop_count, push_count)) = arity {
59 self.push_count = push_count;
60 }
61 }
62 Ok(())
63 }
64
65 pub fn visualize_operand_stack(&self, use_color: bool) -> crate::Result<String> {
66 let mut buf_color = PrintTermcolor(termcolor::Ansi::new(Vec::new()));
67 let mut buf_nocolor = PrintTermcolor(termcolor::NoColor::new(Vec::new()));
68
69 let stack_printer = Printer {
70 result: if use_color {
71 &mut buf_color
72 } else {
73 &mut buf_nocolor
74 },
75 config: &Config::new(),
76 nesting: 0,
77 line: 0,
78 group_lines: Vec::new(),
79 code_section_hints: Vec::new(),
80 };
81
82 if let Some(&Frame { height, .. }) = self.validator.get_control_frame(0) {
83 stack_printer.result.start_comment()?;
84 stack_printer.result.write_str("[")?;
85 let max_height = self.validator.operand_stack_height() as usize;
86 for depth in (height..max_height).rev() {
87 if depth + 1 < max_height {
88 stack_printer.result.write_str(" ")?;
89 }
90 if depth + 1 == height + self.push_count as usize {
91 stack_printer.result.start_type()?;
92 }
93 match self.validator.get_operand_type(depth) {
94 Some(Some(ty)) => {
95 stack_printer.result.write_str(&ty_to_str(ty))?;
96 }
97 Some(None) => {
98 stack_printer.result.write_str("(unknown)")?;
99 }
100 None => {
101 stack_printer.result.write_str("(invalid)")?;
102 }
103 }
104 }
105 stack_printer.result.start_comment()?;
106 stack_printer.result.write_str("]")?;
107 stack_printer.result.reset_color()?;
108 }
109
110 let ret = String::from_utf8(if use_color {
111 buf_color.0.into_inner()
112 } else {
113 buf_nocolor.0.into_inner()
114 })?;
115 return Ok(ret);
116
117 fn ty_to_str(ty: ValType) -> String {
118 match ty {
119 ValType::I32 => String::from("i32"),
120 ValType::I64 => String::from("i64"),
121 ValType::F32 => String::from("f32"),
122 ValType::F64 => String::from("f64"),
123 ValType::V128 => String::from("v128"),
124 ValType::Ref(r) => format!("{r}"),
125 }
126 }
127 }
128}