wasmprinter/
lib.rs

1//! A crate to convert a WebAssembly binary to its textual representation in the
2//! WebAssembly Text Format (WAT).
3//!
4//! This crate is intended for developer toolchains and debugging, supporting
5//! human-readable versions of a wasm binary. This can also be useful when
6//! developing wasm toolchain support in Rust for various purposes like testing
7//! and debugging and such.
8
9#![deny(missing_docs)]
10#![cfg_attr(docsrs, feature(doc_cfg))]
11
12use anyhow::{Context, Result, anyhow, bail};
13use operator::{OpPrinter, OperatorSeparator, OperatorState, PrintOperator, PrintOperatorFolded};
14use std::collections::{HashMap, HashSet};
15use std::fmt;
16use std::io;
17use std::marker;
18use std::mem;
19use std::path::Path;
20use wasmparser::*;
21
22const MAX_LOCALS: u32 = 50000;
23const MAX_NESTING_TO_PRINT: u32 = 50;
24const MAX_WASM_FUNCTIONS: u32 = 1_000_000;
25const MAX_WASM_FUNCTION_SIZE: u32 = 128 * 1024;
26
27#[cfg(feature = "component-model")]
28mod component;
29#[cfg(feature = "validate")]
30mod operand_stack;
31#[cfg(not(feature = "validate"))]
32mod operand_stack_disabled;
33#[cfg(not(feature = "validate"))]
34use operand_stack_disabled as operand_stack;
35mod operator;
36mod print;
37
38pub use self::print::*;
39
40/// Reads a WebAssembly `file` from the filesystem and then prints it into an
41/// in-memory `String`.
42pub fn print_file(file: impl AsRef<Path>) -> Result<String> {
43    let file = file.as_ref();
44    let contents = std::fs::read(file).context(format!("failed to read `{}`", file.display()))?;
45    print_bytes(contents)
46}
47
48/// Prints an in-memory `wasm` binary blob into an in-memory `String` which is
49/// its textual representation.
50pub fn print_bytes(wasm: impl AsRef<[u8]>) -> Result<String> {
51    let mut dst = String::new();
52    Config::new().print(wasm.as_ref(), &mut PrintFmtWrite(&mut dst))?;
53    Ok(dst)
54}
55
56/// Configuration used to print a WebAssembly binary.
57///
58/// This structure is used to control the overal structure of how wasm binaries
59/// are printed and tweaks various ways that configures the output.
60#[derive(Debug)]
61pub struct Config {
62    print_offsets: bool,
63    print_skeleton: bool,
64    name_unnamed: bool,
65    fold_instructions: bool,
66    indent_text: String,
67    print_operand_stack: bool,
68}
69
70impl Default for Config {
71    fn default() -> Self {
72        Self {
73            print_offsets: false,
74            print_skeleton: false,
75            name_unnamed: false,
76            fold_instructions: false,
77            indent_text: "  ".to_string(),
78            print_operand_stack: false,
79        }
80    }
81}
82
83/// This structure is the actual structure that prints WebAssembly binaries.
84struct Printer<'cfg, 'env> {
85    config: &'cfg Config,
86    result: &'cfg mut (dyn Print + 'env),
87    nesting: u32,
88    line: usize,
89    group_lines: Vec<usize>,
90    code_section_hints: Vec<(u32, Vec<(usize, BranchHint)>)>,
91}
92
93#[derive(Default)]
94struct CoreState {
95    types: Vec<Option<SubType>>,
96    funcs: u32,
97    func_to_type: Vec<Option<u32>>,
98    memories: u32,
99    tags: u32,
100    tag_to_type: Vec<Option<u32>>,
101    globals: u32,
102    tables: u32,
103    #[cfg(feature = "component-model")]
104    modules: u32,
105    #[cfg(feature = "component-model")]
106    instances: u32,
107    func_names: NamingMap<u32, NameFunc>,
108    local_names: NamingMap<(u32, u32), NameLocal>,
109    label_names: NamingMap<(u32, u32), NameLabel>,
110    type_names: NamingMap<u32, NameType>,
111    field_names: NamingMap<(u32, u32), NameField>,
112    tag_names: NamingMap<u32, NameTag>,
113    table_names: NamingMap<u32, NameTable>,
114    memory_names: NamingMap<u32, NameMemory>,
115    global_names: NamingMap<u32, NameGlobal>,
116    element_names: NamingMap<u32, NameElem>,
117    data_names: NamingMap<u32, NameData>,
118    #[cfg(feature = "component-model")]
119    module_names: NamingMap<u32, NameModule>,
120    #[cfg(feature = "component-model")]
121    instance_names: NamingMap<u32, NameInstance>,
122}
123
124/// A map of index-to-name for tracking what are the contents of the name
125/// section.
126///
127/// The type parameter `T` is either `u32` for most index-based maps or a `(u32,
128/// u32)` for label/local maps where there are two levels of indices.
129///
130/// The type parameter `K` is a static description/namespace for what kind of
131/// item is contained within this map. That's used by some helper methods to
132/// synthesize reasonable names automatically.
133struct NamingMap<T, K> {
134    index_to_name: HashMap<T, Naming>,
135    _marker: marker::PhantomData<K>,
136}
137
138impl<T, K> Default for NamingMap<T, K> {
139    fn default() -> NamingMap<T, K> {
140        NamingMap {
141            index_to_name: HashMap::new(),
142            _marker: marker::PhantomData,
143        }
144    }
145}
146
147#[derive(Default)]
148#[cfg(feature = "component-model")]
149struct ComponentState {
150    types: u32,
151    funcs: u32,
152    instances: u32,
153    components: u32,
154    values: u32,
155    type_names: NamingMap<u32, NameType>,
156    func_names: NamingMap<u32, NameFunc>,
157    component_names: NamingMap<u32, NameComponent>,
158    instance_names: NamingMap<u32, NameInstance>,
159    value_names: NamingMap<u32, NameValue>,
160}
161
162struct State {
163    encoding: Encoding,
164    name: Option<Naming>,
165    core: CoreState,
166    #[cfg(feature = "component-model")]
167    component: ComponentState,
168    custom_section_place: Option<(&'static str, usize)>,
169    // `custom_section_place` stores the text representation of the location where
170    // a custom section should be serialized in the binary format.
171    // The tuple elements are a str (e.g. "after elem") and the line number
172    // where the custom section place was set. `update_custom_section_place` won't
173    // update the custom section place unless the line number changes; this prevents
174    // printing a place "after xxx" where the xxx section doesn't appear in the text format
175    // (e.g. because it was present but empty in the binary format).
176}
177
178impl State {
179    fn new(encoding: Encoding) -> Self {
180        Self {
181            encoding,
182            name: None,
183            core: CoreState::default(),
184            #[cfg(feature = "component-model")]
185            component: ComponentState::default(),
186            custom_section_place: None,
187        }
188    }
189}
190
191struct Naming {
192    name: String,
193    kind: NamingKind,
194}
195
196enum NamingKind {
197    DollarName,
198    DollarQuotedName,
199    SyntheticPrefix(String),
200}
201
202impl Config {
203    /// Creates a new [`Config`] object that's ready to start printing wasm
204    /// binaries to strings.
205    pub fn new() -> Self {
206        Self::default()
207    }
208
209    /// Whether or not to print binary offsets of each item as comments in the
210    /// text format whenever a newline is printed.
211    pub fn print_offsets(&mut self, print: bool) -> &mut Self {
212        self.print_offsets = print;
213        self
214    }
215
216    /// Whether or not to print only a "skeleton" which skips function bodies,
217    /// data segment contents, element segment contents, etc.
218    pub fn print_skeleton(&mut self, print: bool) -> &mut Self {
219        self.print_skeleton = print;
220        self
221    }
222
223    /// Assign names to all unnamed items.
224    ///
225    /// If enabled then any previously unnamed item will have a name synthesized
226    /// that looks like `$#func10` for example. The leading `#` indicates that
227    /// it's `wasmprinter`-generated. The `func` is the namespace of the name
228    /// and provides extra context about the item when referenced. The 10 is the
229    /// local index of the item.
230    ///
231    /// Note that if the resulting text output is converted back to binary the
232    /// resulting `name` custom section will not be the same as before.
233    pub fn name_unnamed(&mut self, enable: bool) -> &mut Self {
234        self.name_unnamed = enable;
235        self
236    }
237
238    /// Print instructions in folded form where possible.
239    ///
240    /// This will cause printing to favor the s-expression (parenthesized) form
241    /// of WebAssembly instructions. For example this output would be generated
242    /// for a simple `add` function:
243    ///
244    /// ```wasm
245    /// (module
246    ///     (func $foo (param i32 i32) (result i32)
247    ///         (i32.add
248    ///             (local.get 0)
249    ///             (local.get 1))
250    ///     )
251    /// )
252    /// ```
253    pub fn fold_instructions(&mut self, enable: bool) -> &mut Self {
254        self.fold_instructions = enable;
255        self
256    }
257
258    /// Print the operand stack types within function bodies,
259    /// flagging newly pushed operands when color output is enabled. E.g.:
260    ///
261    /// ```wasm
262    /// (module
263    ///   (type (;0;) (func))
264    ///   (func (;0;) (type 0)
265    ///     i32.const 4
266    ///     ;; [i32]
267    ///     i32.const 5
268    ///     ;; [i32 i32]
269    ///     i32.add
270    ///     ;; [i32]
271    ///     drop
272    ///     ;; []
273    ///   )
274    /// )
275    /// ```
276    #[cfg(feature = "validate")]
277    pub fn print_operand_stack(&mut self, enable: bool) -> &mut Self {
278        self.print_operand_stack = enable;
279        self
280    }
281
282    /// Select the string to use when indenting.
283    ///
284    /// The indent allowed here are arbitrary and unchecked. You should enter
285    /// blank text like `" "` or `"\t"`, rather than something like `"(;;)"`.
286    ///
287    /// The default setting is double spaces `" "`
288    pub fn indent_text(&mut self, text: impl Into<String>) -> &mut Self {
289        self.indent_text = text.into();
290        self
291    }
292
293    /// Print a WebAssembly binary.
294    ///
295    /// This function takes an entire `wasm` binary blob and prints it to the
296    /// `result` in the WebAssembly Text Format.
297    pub fn print(&self, wasm: &[u8], result: &mut impl Print) -> Result<()> {
298        Printer {
299            config: self,
300            result,
301            code_section_hints: Vec::new(),
302            group_lines: Vec::new(),
303            line: 0,
304            nesting: 0,
305        }
306        .print_contents(wasm)
307    }
308
309    /// Get the line-by-line WAT disassembly for the given Wasm, along with the
310    /// binary offsets for each line.
311    pub fn offsets_and_lines<'a>(
312        &self,
313        wasm: &[u8],
314        storage: &'a mut String,
315    ) -> Result<impl Iterator<Item = (Option<usize>, &'a str)> + 'a> {
316        struct TrackingPrint<'a> {
317            dst: &'a mut String,
318            lines: Vec<usize>,
319            line_offsets: Vec<Option<usize>>,
320        }
321
322        impl Print for TrackingPrint<'_> {
323            fn write_str(&mut self, s: &str) -> io::Result<()> {
324                self.dst.push_str(s);
325                Ok(())
326            }
327            fn start_line(&mut self, offset: Option<usize>) {
328                self.lines.push(self.dst.len());
329                self.line_offsets.push(offset);
330            }
331        }
332
333        let mut output = TrackingPrint {
334            dst: storage,
335            lines: Vec::new(),
336            line_offsets: Vec::new(),
337        };
338        self.print(wasm, &mut output)?;
339
340        let TrackingPrint {
341            dst,
342            lines,
343            line_offsets,
344        } = output;
345        let end = dst.len();
346        let dst = &dst[..];
347        let mut offsets = line_offsets.into_iter();
348        let mut lines = lines.into_iter().peekable();
349
350        Ok(std::iter::from_fn(move || {
351            let offset = offsets.next()?;
352            let i = lines.next()?;
353            let j = lines.peek().copied().unwrap_or(end);
354            let line = &dst[i..j];
355            Some((offset, line))
356        }))
357    }
358}
359
360impl Printer<'_, '_> {
361    fn read_names<'a>(
362        &mut self,
363        mut bytes: &'a [u8],
364        mut parser: Parser,
365        state: &mut State,
366    ) -> Result<()> {
367        loop {
368            let payload = match parser.parse(bytes, true)? {
369                Chunk::NeedMoreData(_) => unreachable!(),
370                Chunk::Parsed { payload, consumed } => {
371                    bytes = &bytes[consumed..];
372                    payload
373                }
374            };
375
376            match payload {
377                Payload::CodeSectionStart { size, .. } => {
378                    if size as usize > bytes.len() {
379                        bail!("invalid code section size");
380                    }
381                    bytes = &bytes[size as usize..];
382                    parser.skip_section();
383                }
384                #[cfg(feature = "component-model")]
385                Payload::ModuleSection {
386                    unchecked_range: range,
387                    ..
388                }
389                | Payload::ComponentSection {
390                    unchecked_range: range,
391                    ..
392                } => {
393                    let offset = range.end - range.start;
394                    if offset > bytes.len() {
395                        bail!("invalid module or component section range");
396                    }
397                    bytes = &bytes[offset..];
398                }
399
400                Payload::CustomSection(c) => {
401                    // Ignore any error associated with the name sections.
402                    match c.as_known() {
403                        KnownCustom::Name(reader) => {
404                            drop(self.register_names(state, reader));
405                        }
406                        #[cfg(feature = "component-model")]
407                        KnownCustom::ComponentName(reader) => {
408                            drop(self.register_component_names(state, reader));
409                        }
410                        KnownCustom::BranchHints(reader) => {
411                            drop(self.register_branch_hint_section(reader));
412                        }
413                        _ => {}
414                    }
415                }
416
417                Payload::End(_) => break,
418                _ => {}
419            }
420        }
421
422        Ok(())
423    }
424
425    fn ensure_module(states: &[State]) -> Result<()> {
426        if !matches!(states.last().unwrap().encoding, Encoding::Module) {
427            bail!("a module section was encountered when parsing a component");
428        }
429
430        Ok(())
431    }
432
433    #[cfg(feature = "component-model")]
434    fn ensure_component(states: &[State]) -> Result<()> {
435        if !matches!(states.last().unwrap().encoding, Encoding::Component) {
436            bail!("a component section was encountered when parsing a module");
437        }
438
439        Ok(())
440    }
441
442    fn print_contents(&mut self, mut bytes: &[u8]) -> Result<()> {
443        self.result.start_line(Some(0));
444
445        let mut expected = None;
446        let mut states: Vec<State> = Vec::new();
447        let mut parser = Parser::new(0);
448        #[cfg(feature = "component-model")]
449        let mut parsers = Vec::new();
450
451        let mut validator = if self.config.print_operand_stack {
452            operand_stack::Validator::new()
453        } else {
454            None
455        };
456
457        loop {
458            let payload = match parser.parse(bytes, true)? {
459                Chunk::NeedMoreData(_) => unreachable!(),
460                Chunk::Parsed { payload, consumed } => {
461                    bytes = &bytes[consumed..];
462                    payload
463                }
464            };
465            if let Some(validator) = &mut validator {
466                match validator.payload(&payload) {
467                    Ok(()) => {}
468                    Err(e) => {
469                        self.newline_unknown_pos()?;
470                        write!(self.result, ";; module or component is invalid: {e}")?;
471                    }
472                }
473            }
474            match payload {
475                Payload::Version { encoding, .. } => {
476                    if let Some(e) = expected {
477                        if encoding != e {
478                            bail!("incorrect encoding for nested module or component");
479                        }
480                        expected = None;
481                    }
482
483                    assert!(states.last().map(|s| s.encoding) != Some(Encoding::Module));
484
485                    match encoding {
486                        Encoding::Module => {
487                            states.push(State::new(Encoding::Module));
488                            states.last_mut().unwrap().custom_section_place =
489                                Some(("before first", self.line));
490                            if states.len() > 1 {
491                                self.start_group("core module")?;
492                            } else {
493                                self.start_group("module")?;
494                            }
495
496                            #[cfg(feature = "component-model")]
497                            if states.len() > 1 {
498                                let parent = &states[states.len() - 2];
499                                self.result.write_str(" ")?;
500                                self.print_name(&parent.core.module_names, parent.core.modules)?;
501                            }
502                        }
503                        Encoding::Component => {
504                            #[cfg(feature = "component-model")]
505                            {
506                                states.push(State::new(Encoding::Component));
507                                self.start_group("component")?;
508
509                                if states.len() > 1 {
510                                    let parent = &states[states.len() - 2];
511                                    self.result.write_str(" ")?;
512                                    self.print_name(
513                                        &parent.component.component_names,
514                                        parent.component.components,
515                                    )?;
516                                }
517                            }
518                            #[cfg(not(feature = "component-model"))]
519                            {
520                                bail!(
521                                    "support for printing components disabled \
522                                     at compile-time"
523                                );
524                            }
525                        }
526                    }
527
528                    let len = states.len();
529                    let state = states.last_mut().unwrap();
530
531                    // First up try to find the `name` subsection which we'll use to print
532                    // pretty names everywhere.
533                    self.read_names(bytes, parser.clone(), state)?;
534
535                    if len == 1 {
536                        if let Some(name) = state.name.as_ref() {
537                            self.result.write_str(" ")?;
538                            name.write(self)?;
539                        }
540                    }
541                }
542                Payload::CustomSection(c) => {
543                    // If the custom printing trait handles this section, keep
544                    // going after that.
545                    let printed =
546                        self.result
547                            .print_custom_section(c.name(), c.data_offset(), c.data())?;
548                    if printed {
549                        self.update_custom_section_line(&mut states);
550                        continue;
551                    }
552
553                    // If this wasn't handled specifically above then try to
554                    // print the known custom builtin sections. If this fails
555                    // because the custom section is malformed then print the
556                    // raw contents instead.
557                    let state = states.last().unwrap();
558                    let start = self.nesting;
559                    match c.as_known() {
560                        KnownCustom::Unknown => self.print_raw_custom_section(state, c.clone())?,
561                        _ => {
562                            match (Printer {
563                                config: self.config,
564                                result: &mut PrintFmtWrite(String::new()),
565                                nesting: 0,
566                                line: 0,
567                                group_lines: Vec::new(),
568                                code_section_hints: Vec::new(),
569                            })
570                            .print_known_custom_section(c.clone())
571                            {
572                                Ok(true) => {
573                                    self.print_known_custom_section(c.clone())?;
574                                }
575                                Ok(false) => self.print_raw_custom_section(state, c.clone())?,
576                                Err(e) if !e.is::<BinaryReaderError>() => return Err(e),
577                                Err(e) => {
578                                    let msg = format!(
579                                        "failed to parse custom section `{}`: {e}",
580                                        c.name()
581                                    );
582                                    for line in msg.lines() {
583                                        self.newline(c.data_offset())?;
584                                        write!(self.result, ";; {line}")?;
585                                    }
586                                    self.print_raw_custom_section(state, c.clone())?
587                                }
588                            }
589                        }
590                    }
591                    assert!(self.nesting == start);
592                    self.update_custom_section_line(&mut states);
593                }
594                Payload::TypeSection(s) => {
595                    self.print_types(states.last_mut().unwrap(), s)?;
596                    self.update_custom_section_place(&mut states, "after type");
597                }
598                Payload::ImportSection(s) => {
599                    Self::ensure_module(&states)?;
600                    self.print_imports(states.last_mut().unwrap(), s)?;
601                    self.update_custom_section_place(&mut states, "after import");
602                }
603                Payload::FunctionSection(reader) => {
604                    Self::ensure_module(&states)?;
605                    if reader.count() > MAX_WASM_FUNCTIONS {
606                        bail!(
607                            "module contains {} functions which exceeds the limit of {}",
608                            reader.count(),
609                            MAX_WASM_FUNCTIONS
610                        );
611                    }
612                    for ty in reader {
613                        states.last_mut().unwrap().core.func_to_type.push(Some(ty?))
614                    }
615                    self.update_custom_section_place(&mut states, "after func");
616                }
617                Payload::TableSection(s) => {
618                    Self::ensure_module(&states)?;
619                    self.print_tables(states.last_mut().unwrap(), s)?;
620                    self.update_custom_section_place(&mut states, "after table");
621                }
622                Payload::MemorySection(s) => {
623                    Self::ensure_module(&states)?;
624                    self.print_memories(states.last_mut().unwrap(), s)?;
625                    self.update_custom_section_place(&mut states, "after memory");
626                }
627                Payload::TagSection(s) => {
628                    Self::ensure_module(&states)?;
629                    self.print_tags(states.last_mut().unwrap(), s)?;
630                    self.update_custom_section_place(&mut states, "after tag");
631                }
632                Payload::GlobalSection(s) => {
633                    Self::ensure_module(&states)?;
634                    self.print_globals(states.last_mut().unwrap(), s)?;
635                    self.update_custom_section_place(&mut states, "after global");
636                }
637                Payload::ExportSection(s) => {
638                    Self::ensure_module(&states)?;
639                    self.print_exports(states.last().unwrap(), s)?;
640                    self.update_custom_section_place(&mut states, "after export");
641                }
642                Payload::StartSection { func, range } => {
643                    Self::ensure_module(&states)?;
644                    self.newline(range.start)?;
645                    self.start_group("start ")?;
646                    self.print_idx(&states.last().unwrap().core.func_names, func)?;
647                    self.end_group()?;
648                    self.update_custom_section_place(&mut states, "after start");
649                }
650                Payload::ElementSection(s) => {
651                    Self::ensure_module(&states)?;
652                    self.print_elems(states.last_mut().unwrap(), s)?;
653                    self.update_custom_section_place(&mut states, "after elem");
654                }
655                Payload::CodeSectionStart { .. } => {
656                    Self::ensure_module(&states)?;
657                }
658                Payload::CodeSectionEntry(body) => {
659                    self.print_code_section_entry(
660                        states.last_mut().unwrap(),
661                        &body,
662                        validator.as_mut().and_then(|v| v.next_func()),
663                    )?;
664                    self.update_custom_section_place(&mut states, "after code");
665                }
666                Payload::DataCountSection { .. } => {
667                    Self::ensure_module(&states)?;
668                    // not part of the text format
669                }
670                Payload::DataSection(s) => {
671                    Self::ensure_module(&states)?;
672                    self.print_data(states.last_mut().unwrap(), s)?;
673                    self.update_custom_section_place(&mut states, "after data");
674                }
675
676                #[cfg(feature = "component-model")]
677                Payload::ModuleSection {
678                    parser: inner,
679                    unchecked_range: range,
680                } => {
681                    Self::ensure_component(&states)?;
682                    expected = Some(Encoding::Module);
683                    parsers.push(parser);
684                    parser = inner;
685                    self.newline(range.start)?;
686                }
687                #[cfg(feature = "component-model")]
688                Payload::InstanceSection(s) => {
689                    Self::ensure_component(&states)?;
690                    self.print_instances(states.last_mut().unwrap(), s)?;
691                }
692                #[cfg(feature = "component-model")]
693                Payload::CoreTypeSection(s) => self.print_core_types(&mut states, s)?,
694                #[cfg(feature = "component-model")]
695                Payload::ComponentSection {
696                    parser: inner,
697                    unchecked_range: range,
698                } => {
699                    Self::ensure_component(&states)?;
700                    expected = Some(Encoding::Component);
701                    parsers.push(parser);
702                    parser = inner;
703                    self.newline(range.start)?;
704                }
705                #[cfg(feature = "component-model")]
706                Payload::ComponentInstanceSection(s) => {
707                    Self::ensure_component(&states)?;
708                    self.print_component_instances(states.last_mut().unwrap(), s)?;
709                }
710                #[cfg(feature = "component-model")]
711                Payload::ComponentAliasSection(s) => {
712                    Self::ensure_component(&states)?;
713                    self.print_component_aliases(&mut states, s)?;
714                }
715                #[cfg(feature = "component-model")]
716                Payload::ComponentTypeSection(s) => {
717                    Self::ensure_component(&states)?;
718                    self.print_component_types(&mut states, s)?;
719                }
720                #[cfg(feature = "component-model")]
721                Payload::ComponentCanonicalSection(s) => {
722                    Self::ensure_component(&states)?;
723                    self.print_canonical_functions(states.last_mut().unwrap(), s)?;
724                }
725                #[cfg(feature = "component-model")]
726                Payload::ComponentStartSection { start, range } => {
727                    Self::ensure_component(&states)?;
728                    self.print_component_start(states.last_mut().unwrap(), range.start, start)?;
729                }
730                #[cfg(feature = "component-model")]
731                Payload::ComponentImportSection(s) => {
732                    Self::ensure_component(&states)?;
733                    self.print_component_imports(states.last_mut().unwrap(), s)?;
734                }
735                #[cfg(feature = "component-model")]
736                Payload::ComponentExportSection(s) => {
737                    Self::ensure_component(&states)?;
738                    self.print_component_exports(states.last_mut().unwrap(), s)?;
739                }
740
741                Payload::End(offset) => {
742                    self.end_group_at_pos(offset)?; // close the `module` or `component` group
743
744                    #[cfg(feature = "component-model")]
745                    {
746                        let state = states.pop().unwrap();
747                        if let Some(parent) = states.last_mut() {
748                            match state.encoding {
749                                Encoding::Module => {
750                                    parent.core.modules += 1;
751                                }
752                                Encoding::Component => {
753                                    parent.component.components += 1;
754                                }
755                            }
756                            parser = parsers.pop().unwrap();
757
758                            continue;
759                        }
760                    }
761                    self.result.newline()?;
762                    break;
763                }
764
765                other => match other.as_section() {
766                    Some((id, _)) => bail!("found unknown section `{}`", id),
767                    None => bail!("found unknown payload"),
768                },
769            }
770        }
771
772        Ok(())
773    }
774
775    fn update_custom_section_place(&self, states: &mut Vec<State>, place: &'static str) {
776        if let Some(last) = states.last_mut() {
777            if let Some((prev, prev_line)) = &mut last.custom_section_place {
778                if *prev_line != self.line {
779                    *prev = place;
780                    *prev_line = self.line;
781                }
782            }
783        }
784    }
785
786    fn update_custom_section_line(&self, states: &mut Vec<State>) {
787        if let Some(last) = states.last_mut() {
788            if let Some((_, prev_line)) = &mut last.custom_section_place {
789                *prev_line = self.line;
790            }
791        }
792    }
793
794    fn start_group(&mut self, name: &str) -> Result<()> {
795        write!(self.result, "(")?;
796        self.result.start_keyword()?;
797        write!(self.result, "{name}")?;
798        self.result.reset_color()?;
799        self.nesting += 1;
800        self.group_lines.push(self.line);
801        Ok(())
802    }
803
804    fn end_group(&mut self) -> Result<()> {
805        self.nesting -= 1;
806        if let Some(line) = self.group_lines.pop() {
807            if line != self.line {
808                self.newline_unknown_pos()?;
809            }
810        }
811        self.result.write_str(")")?;
812        Ok(())
813    }
814
815    fn end_group_at_pos(&mut self, offset: usize) -> Result<()> {
816        self.nesting -= 1;
817        let start_group_line = self.group_lines.pop();
818        if self.config.print_offsets {
819            self.newline(offset)?;
820        } else if let Some(line) = start_group_line {
821            if line != self.line {
822                self.newline(offset)?;
823            }
824        }
825        self.result.write_str(")")?;
826        Ok(())
827    }
828
829    fn register_names(&mut self, state: &mut State, names: NameSectionReader<'_>) -> Result<()> {
830        fn indirect_name_map<K>(
831            into: &mut NamingMap<(u32, u32), K>,
832            names: IndirectNameMap<'_>,
833            name: &str,
834        ) -> Result<()> {
835            for indirect in names {
836                let indirect = indirect?;
837                let mut used = match name {
838                    // labels can be shadowed, so maintaining the used names is not useful.
839                    "label" => None,
840                    "local" | "field" => Some(HashSet::new()),
841                    _ => unimplemented!("{name} is an unknown type of indirect names"),
842                };
843                for naming in indirect.names {
844                    let naming = naming?;
845                    into.index_to_name.insert(
846                        (indirect.index, naming.index),
847                        Naming::new(naming.name, naming.index, name, used.as_mut()),
848                    );
849                }
850            }
851            Ok(())
852        }
853
854        for section in names {
855            match section? {
856                Name::Module { name, .. } => {
857                    let name = Naming::new(name, 0, "module", None);
858                    state.name = Some(name);
859                }
860                Name::Function(n) => name_map(&mut state.core.func_names, n, "func")?,
861                Name::Local(n) => indirect_name_map(&mut state.core.local_names, n, "local")?,
862                Name::Label(n) => indirect_name_map(&mut state.core.label_names, n, "label")?,
863                Name::Type(n) => name_map(&mut state.core.type_names, n, "type")?,
864                Name::Table(n) => name_map(&mut state.core.table_names, n, "table")?,
865                Name::Memory(n) => name_map(&mut state.core.memory_names, n, "memory")?,
866                Name::Global(n) => name_map(&mut state.core.global_names, n, "global")?,
867                Name::Element(n) => name_map(&mut state.core.element_names, n, "elem")?,
868                Name::Data(n) => name_map(&mut state.core.data_names, n, "data")?,
869                Name::Field(n) => indirect_name_map(&mut state.core.field_names, n, "field")?,
870                Name::Tag(n) => name_map(&mut state.core.tag_names, n, "tag")?,
871                Name::Unknown { .. } => (),
872            }
873        }
874        Ok(())
875    }
876
877    fn print_rec(
878        &mut self,
879        state: &mut State,
880        offset: Option<usize>,
881        rec: RecGroup,
882        is_component: bool,
883    ) -> Result<()> {
884        if rec.is_explicit_rec_group() {
885            if is_component {
886                self.start_group("core rec")?;
887            } else {
888                self.start_group("rec")?;
889            }
890            for ty in rec.into_types() {
891                match offset {
892                    Some(offset) => self.newline(offset + 2)?,
893                    None => self.newline_unknown_pos()?,
894                }
895                self.print_type(state, ty, false)?;
896            }
897            self.end_group()?; // `rec`
898        } else {
899            assert_eq!(rec.types().len(), 1);
900            let ty = rec.into_types().next().unwrap();
901            self.print_type(state, ty, is_component)?;
902        }
903        Ok(())
904    }
905
906    fn print_type(&mut self, state: &mut State, ty: SubType, is_component: bool) -> Result<()> {
907        if is_component {
908            self.start_group("core type ")?;
909        } else {
910            self.start_group("type ")?;
911        }
912        let ty_idx = state.core.types.len() as u32;
913        self.print_name(&state.core.type_names, ty_idx)?;
914        self.result.write_str(" ")?;
915        self.print_sub(state, &ty, ty_idx)?;
916        self.end_group()?; // `type`
917        state.core.types.push(Some(ty));
918        Ok(())
919    }
920
921    fn print_sub(&mut self, state: &State, ty: &SubType, ty_idx: u32) -> Result<u32> {
922        let r = if !ty.is_final || !ty.supertype_idx.is_none() {
923            self.start_group("sub")?;
924            self.print_sub_type(state, ty)?;
925            let r = self.print_composite(state, &ty.composite_type, ty_idx)?;
926            self.end_group()?; // `sub`
927            r
928        } else {
929            self.print_composite(state, &ty.composite_type, ty_idx)?
930        };
931        Ok(r)
932    }
933
934    fn print_composite(&mut self, state: &State, ty: &CompositeType, ty_idx: u32) -> Result<u32> {
935        if ty.shared {
936            self.start_group("shared")?;
937            self.result.write_str(" ")?;
938        }
939        if let Some(idx) = ty.describes_idx {
940            self.start_group("describes")?;
941            self.result.write_str(" ")?;
942            self.print_idx(&state.core.type_names, idx.as_module_index().unwrap())?;
943            self.end_group()?;
944            self.result.write_str(" ")?;
945        }
946        if let Some(idx) = ty.descriptor_idx {
947            self.start_group("descriptor")?;
948            self.result.write_str(" ")?;
949            self.print_idx(&state.core.type_names, idx.as_module_index().unwrap())?;
950            self.end_group()?;
951            self.result.write_str(" ")?;
952        }
953        let r = match &ty.inner {
954            CompositeInnerType::Func(ty) => {
955                self.start_group("func")?;
956                let r = self.print_func_type(state, ty, None)?;
957                self.end_group()?; // `func`
958                r
959            }
960            CompositeInnerType::Array(ty) => {
961                self.start_group("array")?;
962                let r = self.print_array_type(state, ty)?;
963                self.end_group()?; // `array`
964                r
965            }
966            CompositeInnerType::Struct(ty) => {
967                self.start_group("struct")?;
968                let r = self.print_struct_type(state, ty, ty_idx)?;
969                self.end_group()?; // `struct`
970                r
971            }
972            CompositeInnerType::Cont(ty) => {
973                self.start_group("cont")?;
974                let r = self.print_cont_type(state, ty)?;
975                self.end_group()?; // `cont`
976                r
977            }
978        };
979        if ty.shared {
980            self.end_group()?; // `shared`
981        }
982        Ok(r)
983    }
984
985    fn print_types(&mut self, state: &mut State, parser: TypeSectionReader<'_>) -> Result<()> {
986        for ty in parser.into_iter_with_offsets() {
987            let (offset, rec_group) = ty?;
988            self.newline(offset)?;
989            self.print_rec(state, Some(offset), rec_group, false)?;
990        }
991        Ok(())
992    }
993
994    fn print_core_functype_idx(
995        &mut self,
996        state: &State,
997        idx: u32,
998        names_for: Option<u32>,
999    ) -> Result<Option<u32>> {
1000        self.print_core_type_ref(state, idx)?;
1001
1002        match state.core.types.get(idx as usize) {
1003            Some(Some(SubType {
1004                composite_type:
1005                    CompositeType {
1006                        inner: CompositeInnerType::Func(ty),
1007                        shared: false,
1008                        descriptor_idx: None,
1009                        describes_idx: None,
1010                    },
1011                ..
1012            })) => self.print_func_type(state, ty, names_for).map(Some),
1013            Some(Some(_)) | Some(None) | None => Ok(None),
1014        }
1015    }
1016
1017    /// Returns the number of parameters, useful for local index calculations
1018    /// later.
1019    fn print_func_type(
1020        &mut self,
1021        state: &State,
1022        ty: &FuncType,
1023        names_for: Option<u32>,
1024    ) -> Result<u32> {
1025        if !ty.params().is_empty() {
1026            self.result.write_str(" ")?;
1027        }
1028
1029        let mut params = NamedLocalPrinter::new("param");
1030        // Note that named parameters must be alone in a `param` block, so
1031        // we need to be careful to terminate previous param blocks and open
1032        // a new one if that's the case with a named parameter.
1033        for (i, param) in ty.params().iter().enumerate() {
1034            params.start_local(names_for, i as u32, self, state)?;
1035            self.print_valtype(state, *param)?;
1036            params.end_local(self)?;
1037        }
1038        params.finish(self)?;
1039        if !ty.results().is_empty() {
1040            self.result.write_str(" ")?;
1041            self.start_group("result")?;
1042            for result in ty.results().iter() {
1043                self.result.write_str(" ")?;
1044                self.print_valtype(state, *result)?;
1045            }
1046            self.end_group()?;
1047        }
1048        Ok(ty.params().len() as u32)
1049    }
1050
1051    fn print_field_type(
1052        &mut self,
1053        state: &State,
1054        ty: &FieldType,
1055        ty_field_idx: Option<(u32, u32)>,
1056    ) -> Result<u32> {
1057        self.result.write_str(" ")?;
1058        if let Some(idxs @ (_, field_idx)) = ty_field_idx {
1059            match state.core.field_names.index_to_name.get(&idxs) {
1060                Some(name) => {
1061                    name.write_identifier(self)?;
1062                    self.result.write_str(" ")?;
1063                }
1064                None if self.config.name_unnamed => write!(self.result, "$#field{field_idx} ")?,
1065                None => {}
1066            }
1067        }
1068        if ty.mutable {
1069            self.result.write_str("(mut ")?;
1070        }
1071        self.print_storage_type(state, ty.element_type)?;
1072        if ty.mutable {
1073            self.result.write_str(")")?;
1074        }
1075        Ok(0)
1076    }
1077
1078    fn print_array_type(&mut self, state: &State, ty: &ArrayType) -> Result<u32> {
1079        self.print_field_type(state, &ty.0, None)
1080    }
1081
1082    fn print_struct_type(&mut self, state: &State, ty: &StructType, ty_idx: u32) -> Result<u32> {
1083        for (field_index, field) in ty.fields.iter().enumerate() {
1084            self.result.write_str(" (field")?;
1085            self.print_field_type(state, field, Some((ty_idx, field_index as u32)))?;
1086            self.result.write_str(")")?;
1087        }
1088        Ok(0)
1089    }
1090
1091    fn print_cont_type(&mut self, state: &State, ct: &ContType) -> Result<u32> {
1092        self.result.write_str(" ")?;
1093        self.print_idx(&state.core.type_names, ct.0.as_module_index().unwrap())?;
1094        Ok(0)
1095    }
1096
1097    fn print_sub_type(&mut self, state: &State, ty: &SubType) -> Result<u32> {
1098        self.result.write_str(" ")?;
1099        if ty.is_final {
1100            self.result.write_str("final ")?;
1101        }
1102        if let Some(idx) = ty.supertype_idx {
1103            self.print_idx(&state.core.type_names, idx.as_module_index().unwrap())?;
1104            self.result.write_str(" ")?;
1105        }
1106        Ok(0)
1107    }
1108
1109    fn print_storage_type(&mut self, state: &State, ty: StorageType) -> Result<()> {
1110        match ty {
1111            StorageType::I8 => self.result.write_str("i8")?,
1112            StorageType::I16 => self.result.write_str("i16")?,
1113            StorageType::Val(val_type) => self.print_valtype(state, val_type)?,
1114        }
1115        Ok(())
1116    }
1117
1118    fn print_valtype(&mut self, state: &State, ty: ValType) -> Result<()> {
1119        match ty {
1120            ValType::I32 => self.print_type_keyword("i32")?,
1121            ValType::I64 => self.print_type_keyword("i64")?,
1122            ValType::F32 => self.print_type_keyword("f32")?,
1123            ValType::F64 => self.print_type_keyword("f64")?,
1124            ValType::V128 => self.print_type_keyword("v128")?,
1125            ValType::Ref(rt) => self.print_reftype(state, rt)?,
1126        }
1127        Ok(())
1128    }
1129
1130    fn print_valtypes(&mut self, state: &State, tys: Vec<ValType>) -> Result<()> {
1131        for ty in tys {
1132            self.result.write_str(" ")?;
1133            self.print_valtype(state, ty)?;
1134        }
1135        Ok(())
1136    }
1137
1138    fn print_reftype(&mut self, state: &State, ty: RefType) -> Result<()> {
1139        if ty.is_nullable() {
1140            match ty.as_non_null() {
1141                RefType::FUNC => self.print_type_keyword("funcref")?,
1142                RefType::EXTERN => self.print_type_keyword("externref")?,
1143                RefType::I31 => self.print_type_keyword("i31ref")?,
1144                RefType::ANY => self.print_type_keyword("anyref")?,
1145                RefType::NONE => self.print_type_keyword("nullref")?,
1146                RefType::NOEXTERN => self.print_type_keyword("nullexternref")?,
1147                RefType::NOFUNC => self.print_type_keyword("nullfuncref")?,
1148                RefType::EQ => self.print_type_keyword("eqref")?,
1149                RefType::STRUCT => self.print_type_keyword("structref")?,
1150                RefType::ARRAY => self.print_type_keyword("arrayref")?,
1151                RefType::EXN => self.print_type_keyword("exnref")?,
1152                RefType::NOEXN => self.print_type_keyword("nullexnref")?,
1153                _ => {
1154                    self.start_group("ref")?;
1155                    self.result.write_str(" null ")?;
1156                    self.print_heaptype(state, ty.heap_type())?;
1157                    self.end_group()?;
1158                }
1159            }
1160        } else {
1161            self.start_group("ref ")?;
1162            self.print_heaptype(state, ty.heap_type())?;
1163            self.end_group()?;
1164        }
1165        Ok(())
1166    }
1167
1168    fn print_heaptype(&mut self, state: &State, ty: HeapType) -> Result<()> {
1169        match ty {
1170            HeapType::Concrete(i) => {
1171                self.print_idx(&state.core.type_names, i.as_module_index().unwrap())?;
1172            }
1173            HeapType::Exact(i) => {
1174                self.start_group("exact ")?;
1175                self.print_idx(&state.core.type_names, i.as_module_index().unwrap())?;
1176                self.end_group()?;
1177            }
1178            HeapType::Abstract { shared, ty } => {
1179                use AbstractHeapType::*;
1180                if shared {
1181                    self.start_group("shared ")?;
1182                }
1183                match ty {
1184                    Func => self.print_type_keyword("func")?,
1185                    Extern => self.print_type_keyword("extern")?,
1186                    Any => self.print_type_keyword("any")?,
1187                    None => self.print_type_keyword("none")?,
1188                    NoExtern => self.print_type_keyword("noextern")?,
1189                    NoFunc => self.print_type_keyword("nofunc")?,
1190                    Eq => self.print_type_keyword("eq")?,
1191                    Struct => self.print_type_keyword("struct")?,
1192                    Array => self.print_type_keyword("array")?,
1193                    I31 => self.print_type_keyword("i31")?,
1194                    Exn => self.print_type_keyword("exn")?,
1195                    NoExn => self.print_type_keyword("noexn")?,
1196                    Cont => self.print_type_keyword("cont")?,
1197                    NoCont => self.print_type_keyword("nocont")?,
1198                }
1199                if shared {
1200                    self.end_group()?;
1201                }
1202            }
1203        }
1204        Ok(())
1205    }
1206
1207    fn print_type_keyword(&mut self, keyword: &str) -> Result<()> {
1208        self.result.start_type()?;
1209        self.result.write_str(keyword)?;
1210        self.result.reset_color()?;
1211        Ok(())
1212    }
1213
1214    fn print_imports(&mut self, state: &mut State, parser: ImportSectionReader<'_>) -> Result<()> {
1215        for import in parser.into_iter_with_offsets() {
1216            let (offset, import) = import?;
1217            self.newline(offset)?;
1218            self.print_import(state, &import, true)?;
1219            match import.ty {
1220                TypeRef::Func(idx) => {
1221                    debug_assert!(state.core.func_to_type.len() == state.core.funcs as usize);
1222                    state.core.funcs += 1;
1223                    state.core.func_to_type.push(Some(idx))
1224                }
1225                TypeRef::Table(_) => state.core.tables += 1,
1226                TypeRef::Memory(_) => state.core.memories += 1,
1227                TypeRef::Tag(TagType {
1228                    kind: _,
1229                    func_type_idx: idx,
1230                }) => {
1231                    debug_assert!(state.core.tag_to_type.len() == state.core.tags as usize);
1232                    state.core.tags += 1;
1233                    state.core.tag_to_type.push(Some(idx))
1234                }
1235                TypeRef::Global(_) => state.core.globals += 1,
1236            }
1237        }
1238        Ok(())
1239    }
1240
1241    fn print_import(&mut self, state: &State, import: &Import<'_>, index: bool) -> Result<()> {
1242        self.start_group("import ")?;
1243        self.print_str(import.module)?;
1244        self.result.write_str(" ")?;
1245        self.print_str(import.name)?;
1246        self.result.write_str(" ")?;
1247        self.print_import_ty(state, &import.ty, index)?;
1248        self.end_group()?;
1249        Ok(())
1250    }
1251
1252    fn print_import_ty(&mut self, state: &State, ty: &TypeRef, index: bool) -> Result<()> {
1253        match ty {
1254            TypeRef::Func(f) => {
1255                self.start_group("func ")?;
1256                if index {
1257                    self.print_name(&state.core.func_names, state.core.funcs)?;
1258                    self.result.write_str(" ")?;
1259                }
1260                self.print_core_type_ref(state, *f)?;
1261            }
1262            TypeRef::Table(f) => self.print_table_type(state, f, index)?,
1263            TypeRef::Memory(f) => self.print_memory_type(state, f, index)?,
1264            TypeRef::Tag(f) => self.print_tag_type(state, f, index)?,
1265            TypeRef::Global(f) => self.print_global_type(state, f, index)?,
1266        }
1267        self.end_group()?;
1268        Ok(())
1269    }
1270
1271    fn print_table_type(&mut self, state: &State, ty: &TableType, index: bool) -> Result<()> {
1272        self.start_group("table ")?;
1273        if index {
1274            self.print_name(&state.core.table_names, state.core.tables)?;
1275            self.result.write_str(" ")?;
1276        }
1277        if ty.shared {
1278            self.print_type_keyword("shared ")?;
1279        }
1280        if ty.table64 {
1281            self.print_type_keyword("i64 ")?;
1282        }
1283        self.print_limits(ty.initial, ty.maximum)?;
1284        self.result.write_str(" ")?;
1285        self.print_reftype(state, ty.element_type)?;
1286        Ok(())
1287    }
1288
1289    fn print_memory_type(&mut self, state: &State, ty: &MemoryType, index: bool) -> Result<()> {
1290        self.start_group("memory ")?;
1291        if index {
1292            self.print_name(&state.core.memory_names, state.core.memories)?;
1293            self.result.write_str(" ")?;
1294        }
1295        if ty.memory64 {
1296            self.print_type_keyword("i64 ")?;
1297        }
1298        self.print_limits(ty.initial, ty.maximum)?;
1299        if ty.shared {
1300            self.print_type_keyword(" shared")?;
1301        }
1302        if let Some(p) = ty.page_size_log2 {
1303            let p = 1_u64
1304                .checked_shl(p)
1305                .ok_or_else(|| anyhow!("left shift overflow").context("invalid page size"))?;
1306
1307            self.result.write_str(" ")?;
1308            self.start_group("pagesize ")?;
1309            write!(self.result, "{p:#x}")?;
1310            self.end_group()?;
1311        }
1312        Ok(())
1313    }
1314
1315    fn print_tag_type(&mut self, state: &State, ty: &TagType, index: bool) -> Result<()> {
1316        self.start_group("tag ")?;
1317        if index {
1318            self.print_name(&state.core.tag_names, state.core.tags)?;
1319            self.result.write_str(" ")?;
1320        }
1321        self.print_core_functype_idx(state, ty.func_type_idx, None)?;
1322        Ok(())
1323    }
1324
1325    fn print_limits<T>(&mut self, initial: T, maximum: Option<T>) -> Result<()>
1326    where
1327        T: fmt::Display,
1328    {
1329        self.result.start_literal()?;
1330        write!(self.result, "{initial}")?;
1331        if let Some(max) = maximum {
1332            write!(self.result, " {max}")?;
1333        }
1334        self.result.reset_color()?;
1335        Ok(())
1336    }
1337
1338    fn print_global_type(&mut self, state: &State, ty: &GlobalType, index: bool) -> Result<()> {
1339        self.start_group("global ")?;
1340        if index {
1341            self.print_name(&state.core.global_names, state.core.globals)?;
1342            self.result.write_str(" ")?;
1343        }
1344        if ty.shared || ty.mutable {
1345            self.result.write_str("(")?;
1346            if ty.shared {
1347                self.print_type_keyword("shared ")?;
1348            }
1349            if ty.mutable {
1350                self.print_type_keyword("mut ")?;
1351            }
1352            self.print_valtype(state, ty.content_type)?;
1353            self.result.write_str(")")?;
1354        } else {
1355            self.print_valtype(state, ty.content_type)?;
1356        }
1357        Ok(())
1358    }
1359
1360    fn print_tables(&mut self, state: &mut State, parser: TableSectionReader<'_>) -> Result<()> {
1361        for table in parser.into_iter_with_offsets() {
1362            let (offset, table) = table?;
1363            self.newline(offset)?;
1364            self.print_table_type(state, &table.ty, true)?;
1365            match &table.init {
1366                TableInit::RefNull => {}
1367                TableInit::Expr(expr) => {
1368                    self.result.write_str(" ")?;
1369                    self.print_const_expr(state, expr, self.config.fold_instructions)?;
1370                }
1371            }
1372            self.end_group()?;
1373            state.core.tables += 1;
1374        }
1375        Ok(())
1376    }
1377
1378    fn print_memories(&mut self, state: &mut State, parser: MemorySectionReader<'_>) -> Result<()> {
1379        for memory in parser.into_iter_with_offsets() {
1380            let (offset, memory) = memory?;
1381            self.newline(offset)?;
1382            self.print_memory_type(state, &memory, true)?;
1383            self.end_group()?;
1384            state.core.memories += 1;
1385        }
1386        Ok(())
1387    }
1388
1389    fn print_tags(&mut self, state: &mut State, parser: TagSectionReader<'_>) -> Result<()> {
1390        for tag in parser.into_iter_with_offsets() {
1391            let (offset, tag) = tag?;
1392            self.newline(offset)?;
1393            self.print_tag_type(state, &tag, true)?;
1394            self.end_group()?;
1395            debug_assert!(state.core.tag_to_type.len() == state.core.tags as usize);
1396            state.core.tags += 1;
1397            state.core.tag_to_type.push(Some(tag.func_type_idx));
1398        }
1399        Ok(())
1400    }
1401
1402    fn print_globals(&mut self, state: &mut State, parser: GlobalSectionReader<'_>) -> Result<()> {
1403        for global in parser.into_iter_with_offsets() {
1404            let (offset, global) = global?;
1405            self.newline(offset)?;
1406            self.print_global_type(state, &global.ty, true)?;
1407            self.result.write_str(" ")?;
1408            self.print_const_expr(state, &global.init_expr, self.config.fold_instructions)?;
1409            self.end_group()?;
1410            state.core.globals += 1;
1411        }
1412        Ok(())
1413    }
1414
1415    fn print_code_section_entry(
1416        &mut self,
1417        state: &mut State,
1418        body: &FunctionBody<'_>,
1419        validator: Option<operand_stack::FuncValidator>,
1420    ) -> Result<()> {
1421        self.newline(body.get_binary_reader().original_position())?;
1422        self.start_group("func ")?;
1423        let func_idx = state.core.funcs;
1424        self.print_name(&state.core.func_names, func_idx)?;
1425        self.result.write_str(" ")?;
1426        let ty = match state.core.func_to_type.get(func_idx as usize) {
1427            Some(Some(x)) => *x,
1428            _ => panic!("invalid function type"),
1429        };
1430        let params = self
1431            .print_core_functype_idx(state, ty, Some(func_idx))?
1432            .unwrap_or(0);
1433
1434        // Hints are stored on `self` in reverse order of function index so
1435        // check the last one and see if it matches this function.
1436        let hints = match self.code_section_hints.last() {
1437            Some((f, _)) if *f == func_idx => {
1438                let (_, hints) = self.code_section_hints.pop().unwrap();
1439                hints
1440            }
1441            _ => Vec::new(),
1442        };
1443
1444        if self.config.print_skeleton {
1445            self.result.write_str(" ...")?;
1446            self.end_group()?;
1447        } else {
1448            let end_pos =
1449                self.print_func_body(state, func_idx, params, &body, &hints, validator)?;
1450            self.end_group_at_pos(end_pos)?;
1451        }
1452
1453        state.core.funcs += 1;
1454        Ok(())
1455    }
1456
1457    fn print_func_body(
1458        &mut self,
1459        state: &mut State,
1460        func_idx: u32,
1461        params: u32,
1462        body: &FunctionBody<'_>,
1463        branch_hints: &[(usize, BranchHint)],
1464        mut validator: Option<operand_stack::FuncValidator>,
1465    ) -> Result<usize> {
1466        let mut first = true;
1467        let mut local_idx = 0;
1468        let mut locals = NamedLocalPrinter::new("local");
1469        let mut reader = body.get_binary_reader();
1470        let func_start = reader.original_position();
1471        for _ in 0..reader.read_var_u32()? {
1472            let offset = reader.original_position();
1473            let cnt = reader.read_var_u32()?;
1474            let ty = reader.read()?;
1475            if MAX_LOCALS
1476                .checked_sub(local_idx)
1477                .and_then(|s| s.checked_sub(cnt))
1478                .is_none()
1479            {
1480                bail!("function exceeds the maximum number of locals that can be printed");
1481            }
1482            for _ in 0..cnt {
1483                if first {
1484                    self.newline(offset)?;
1485                    first = false;
1486                }
1487                locals.start_local(Some(func_idx), params + local_idx, self, state)?;
1488                self.print_valtype(state, ty)?;
1489                locals.end_local(self)?;
1490                local_idx += 1;
1491            }
1492        }
1493        locals.finish(self)?;
1494
1495        if let Some(f) = &mut validator {
1496            if let Err(e) = f.read_locals(body.get_binary_reader()) {
1497                validator = None;
1498                self.newline_unknown_pos()?;
1499                write!(self.result, ";; locals are invalid: {e}")?;
1500            }
1501        }
1502
1503        let nesting_start = self.nesting;
1504        let fold_instructions = self.config.fold_instructions;
1505        let mut operator_state = OperatorState::new(self, OperatorSeparator::Newline);
1506
1507        let end_pos = if fold_instructions {
1508            let mut folded_printer = PrintOperatorFolded::new(self, state, &mut operator_state);
1509            folded_printer.set_offset(func_start);
1510            folded_printer.begin_function(func_idx)?;
1511            Self::print_operators(
1512                &mut reader,
1513                branch_hints,
1514                func_start,
1515                &mut folded_printer,
1516                validator,
1517            )?
1518        } else {
1519            let mut flat_printer = PrintOperator::new(self, state, &mut operator_state);
1520            Self::print_operators(
1521                &mut reader,
1522                branch_hints,
1523                func_start,
1524                &mut flat_printer,
1525                validator,
1526            )?
1527        };
1528
1529        // If this was an invalid function body then the nesting may not
1530        // have reset back to normal. Fix that up here and forcibly insert
1531        // a newline as well in case the last instruction was something
1532        // like an `if` which has a comment after it which could interfere
1533        // with the closing paren printed for the func.
1534        if self.nesting != nesting_start {
1535            self.nesting = nesting_start;
1536            self.newline(reader.original_position())?;
1537        }
1538
1539        Ok(end_pos)
1540    }
1541
1542    fn print_operators<'a, O: OpPrinter>(
1543        body: &mut BinaryReader<'a>,
1544        mut branch_hints: &[(usize, BranchHint)],
1545        func_start: usize,
1546        op_printer: &mut O,
1547        mut validator: Option<operand_stack::FuncValidator>,
1548    ) -> Result<usize> {
1549        let mut ops = OperatorsReader::new(body.clone());
1550        while !ops.eof() {
1551            if ops.is_end_then_eof() {
1552                let mut annotation = None;
1553                if let Some(f) = &mut validator {
1554                    match f.visit_operator(&ops, true) {
1555                        Ok(()) => {}
1556                        Err(_) => {
1557                            annotation = Some(String::from("type mismatch at end of expression"))
1558                        }
1559                    }
1560                }
1561
1562                let end_pos = ops.original_position();
1563                ops.read()?; // final "end" opcode terminates instruction sequence
1564                ops.finish()?;
1565                op_printer.finalize(annotation.as_deref())?;
1566                return Ok(end_pos);
1567            }
1568
1569            // Branch hints are stored in increasing order of their body offset
1570            // so print them whenever their instruction comes up.
1571            if let Some(((hint_offset, hint), rest)) = branch_hints.split_first() {
1572                if hint.func_offset == (ops.original_position() - func_start) as u32 {
1573                    branch_hints = rest;
1574                    op_printer.branch_hint(*hint_offset, hint.taken)?;
1575                }
1576            }
1577            let mut annotation = None;
1578            if let Some(f) = &mut validator {
1579                let result = f
1580                    .visit_operator(&ops, false)
1581                    .map_err(anyhow::Error::from)
1582                    .and_then(|()| f.visualize_operand_stack(op_printer.use_color()));
1583                match result {
1584                    Ok(s) => annotation = Some(s),
1585                    Err(_) => {
1586                        validator = None;
1587                        annotation = Some(String::from("(invalid)"));
1588                    }
1589                }
1590            }
1591            op_printer.set_offset(ops.original_position());
1592            op_printer.visit_operator(&mut ops, annotation.as_deref())?;
1593        }
1594        ops.finish()?; // for the error message
1595        bail!("unexpected end of operators");
1596    }
1597
1598    fn newline(&mut self, offset: usize) -> Result<()> {
1599        self.print_newline(Some(offset))
1600    }
1601
1602    fn newline_unknown_pos(&mut self) -> Result<()> {
1603        self.print_newline(None)
1604    }
1605
1606    fn print_newline(&mut self, offset: Option<usize>) -> Result<()> {
1607        self.result.newline()?;
1608        self.result.start_line(offset);
1609
1610        if self.config.print_offsets {
1611            match offset {
1612                Some(offset) => {
1613                    self.result.start_comment()?;
1614                    write!(self.result, "(;@{offset:<6x};)")?;
1615                    self.result.reset_color()?;
1616                }
1617                None => self.result.write_str("           ")?,
1618            }
1619        }
1620        self.line += 1;
1621
1622        // Clamp the maximum nesting size that we print at something somewhat
1623        // reasonable to avoid generating hundreds of megabytes of whitespace
1624        // for small-ish modules that have deep-ish nesting.
1625        for _ in 0..self.nesting.min(MAX_NESTING_TO_PRINT) {
1626            self.result.write_str(&self.config.indent_text)?;
1627        }
1628        Ok(())
1629    }
1630
1631    fn print_exports(&mut self, state: &State, data: ExportSectionReader) -> Result<()> {
1632        for export in data.into_iter_with_offsets() {
1633            let (offset, export) = export?;
1634            self.newline(offset)?;
1635            self.print_export(state, &export)?;
1636        }
1637        Ok(())
1638    }
1639
1640    fn print_export(&mut self, state: &State, export: &Export) -> Result<()> {
1641        self.start_group("export ")?;
1642        self.print_str(export.name)?;
1643        self.result.write_str(" ")?;
1644        self.print_external_kind(state, export.kind, export.index)?;
1645        self.end_group()?; // export
1646        Ok(())
1647    }
1648
1649    fn print_external_kind(&mut self, state: &State, kind: ExternalKind, index: u32) -> Result<()> {
1650        match kind {
1651            ExternalKind::Func => {
1652                self.start_group("func ")?;
1653                self.print_idx(&state.core.func_names, index)?;
1654            }
1655            ExternalKind::Table => {
1656                self.start_group("table ")?;
1657                self.print_idx(&state.core.table_names, index)?;
1658            }
1659            ExternalKind::Global => {
1660                self.start_group("global ")?;
1661                self.print_idx(&state.core.global_names, index)?;
1662            }
1663            ExternalKind::Memory => {
1664                self.start_group("memory ")?;
1665                self.print_idx(&state.core.memory_names, index)?;
1666            }
1667            ExternalKind::Tag => {
1668                self.start_group("tag ")?;
1669                write!(self.result, "{index}")?;
1670            }
1671        }
1672        self.end_group()?;
1673        Ok(())
1674    }
1675
1676    fn print_core_type_ref(&mut self, state: &State, idx: u32) -> Result<()> {
1677        self.start_group("type ")?;
1678        self.print_idx(&state.core.type_names, idx)?;
1679        self.end_group()?;
1680        Ok(())
1681    }
1682
1683    // Note: in the text format, modules can use identifiers that are defined anywhere, but
1684    // components can only use previously-defined identifiers. In the binary format,
1685    // invalid components can make forward references to an index that appears in the name section;
1686    // these can be printed but the output won't parse.
1687    fn print_idx<K>(&mut self, names: &NamingMap<u32, K>, idx: u32) -> Result<()>
1688    where
1689        K: NamingNamespace,
1690    {
1691        self._print_idx(&names.index_to_name, idx, K::desc())
1692    }
1693
1694    fn _print_idx(&mut self, names: &HashMap<u32, Naming>, idx: u32, desc: &str) -> Result<()> {
1695        self.result.start_name()?;
1696        match names.get(&idx) {
1697            Some(name) => name.write_identifier(self)?,
1698            None if self.config.name_unnamed => write!(self.result, "$#{desc}{idx}")?,
1699            None => write!(self.result, "{idx}")?,
1700        }
1701        self.result.reset_color()?;
1702        Ok(())
1703    }
1704
1705    fn print_local_idx(&mut self, state: &State, func: u32, idx: u32) -> Result<()> {
1706        self.result.start_name()?;
1707        match state.core.local_names.index_to_name.get(&(func, idx)) {
1708            Some(name) => name.write_identifier(self)?,
1709            None if self.config.name_unnamed => write!(self.result, "$#local{idx}")?,
1710            None => write!(self.result, "{idx}")?,
1711        }
1712        self.result.reset_color()?;
1713        Ok(())
1714    }
1715
1716    fn print_field_idx(&mut self, state: &State, ty: u32, idx: u32) -> Result<()> {
1717        self.result.start_name()?;
1718        match state.core.field_names.index_to_name.get(&(ty, idx)) {
1719            Some(name) => name.write_identifier(self)?,
1720            None if self.config.name_unnamed => write!(self.result, "$#field{idx}")?,
1721            None => write!(self.result, "{idx}")?,
1722        }
1723        self.result.reset_color()?;
1724        Ok(())
1725    }
1726
1727    fn print_name<K>(&mut self, names: &NamingMap<u32, K>, cur_idx: u32) -> Result<()>
1728    where
1729        K: NamingNamespace,
1730    {
1731        self._print_name(&names.index_to_name, cur_idx, K::desc())
1732    }
1733
1734    fn _print_name(
1735        &mut self,
1736        names: &HashMap<u32, Naming>,
1737        cur_idx: u32,
1738        desc: &str,
1739    ) -> Result<()> {
1740        self.result.start_name()?;
1741        match names.get(&cur_idx) {
1742            Some(name) => {
1743                name.write(self)?;
1744                self.result.write_str(" ")?;
1745            }
1746            None if self.config.name_unnamed => {
1747                write!(self.result, "$#{desc}{cur_idx} ")?;
1748            }
1749            None => {}
1750        }
1751        write!(self.result, "(;{cur_idx};)")?;
1752        self.result.reset_color()?;
1753        Ok(())
1754    }
1755
1756    fn print_elems(&mut self, state: &mut State, data: ElementSectionReader) -> Result<()> {
1757        for (i, elem) in data.into_iter_with_offsets().enumerate() {
1758            let (offset, mut elem) = elem?;
1759            self.newline(offset)?;
1760            self.start_group("elem ")?;
1761            self.print_name(&state.core.element_names, i as u32)?;
1762            match &mut elem.kind {
1763                ElementKind::Passive => {}
1764                ElementKind::Declared => self.result.write_str(" declare")?,
1765                ElementKind::Active {
1766                    table_index,
1767                    offset_expr,
1768                } => {
1769                    if let Some(table_index) = *table_index {
1770                        self.result.write_str(" ")?;
1771                        self.start_group("table ")?;
1772                        self.print_idx(&state.core.table_names, table_index)?;
1773                        self.end_group()?;
1774                    }
1775                    self.result.write_str(" ")?;
1776                    self.print_const_expr_sugar(state, offset_expr, "offset")?;
1777                }
1778            }
1779            self.result.write_str(" ")?;
1780
1781            if self.config.print_skeleton {
1782                self.result.write_str("...")?;
1783            } else {
1784                match elem.items {
1785                    ElementItems::Functions(reader) => {
1786                        self.result.write_str("func")?;
1787                        for idx in reader {
1788                            self.result.write_str(" ")?;
1789                            self.print_idx(&state.core.func_names, idx?)?
1790                        }
1791                    }
1792                    ElementItems::Expressions(ty, reader) => {
1793                        self.print_reftype(state, ty)?;
1794                        for expr in reader {
1795                            self.result.write_str(" ")?;
1796                            self.print_const_expr_sugar(state, &expr?, "item")?
1797                        }
1798                    }
1799                }
1800            }
1801            self.end_group()?;
1802        }
1803        Ok(())
1804    }
1805
1806    fn print_data(&mut self, state: &mut State, data: DataSectionReader) -> Result<()> {
1807        for (i, data) in data.into_iter_with_offsets().enumerate() {
1808            let (offset, data) = data?;
1809            self.newline(offset)?;
1810            self.start_group("data ")?;
1811            self.print_name(&state.core.data_names, i as u32)?;
1812            self.result.write_str(" ")?;
1813            match &data.kind {
1814                DataKind::Passive => {}
1815                DataKind::Active {
1816                    memory_index,
1817                    offset_expr,
1818                } => {
1819                    if *memory_index != 0 {
1820                        self.start_group("memory ")?;
1821                        self.print_idx(&state.core.memory_names, *memory_index)?;
1822                        self.end_group()?;
1823                        self.result.write_str(" ")?;
1824                    }
1825                    self.print_const_expr_sugar(state, offset_expr, "offset")?;
1826                    self.result.write_str(" ")?;
1827                }
1828            }
1829            if self.config.print_skeleton {
1830                self.result.write_str("...")?;
1831            } else {
1832                self.print_bytes(data.data)?;
1833            }
1834            self.end_group()?;
1835        }
1836        Ok(())
1837    }
1838
1839    /// Prints the operators of `expr` space-separated, taking into account that
1840    /// if there's only one operator in `expr` then instead of `(explicit ...)`
1841    /// the printing can be `(...)`.
1842    fn print_const_expr_sugar(
1843        &mut self,
1844        state: &mut State,
1845        expr: &ConstExpr,
1846        explicit: &str,
1847    ) -> Result<()> {
1848        self.start_group("")?;
1849        let mut reader = expr.get_operators_reader();
1850
1851        if reader.read().is_ok() && !reader.is_end_then_eof() {
1852            write!(self.result, "{explicit} ")?;
1853            self.print_const_expr(state, expr, self.config.fold_instructions)?;
1854        } else {
1855            self.print_const_expr(state, expr, false)?;
1856        }
1857
1858        self.end_group()?;
1859        Ok(())
1860    }
1861
1862    /// Prints the operators of `expr` space-separated.
1863    fn print_const_expr(&mut self, state: &mut State, expr: &ConstExpr, fold: bool) -> Result<()> {
1864        let mut reader = expr.get_binary_reader();
1865        let mut operator_state = OperatorState::new(self, OperatorSeparator::NoneThenSpace);
1866
1867        if fold {
1868            let mut folded_printer = PrintOperatorFolded::new(self, state, &mut operator_state);
1869            folded_printer.begin_const_expr();
1870            Self::print_operators(&mut reader, &[], 0, &mut folded_printer, None)?;
1871        } else {
1872            let mut op_printer = PrintOperator::new(self, state, &mut operator_state);
1873            Self::print_operators(&mut reader, &[], 0, &mut op_printer, None)?;
1874        }
1875
1876        Ok(())
1877    }
1878
1879    fn print_str(&mut self, name: &str) -> Result<()> {
1880        self.result.start_literal()?;
1881        self.result.write_str("\"")?;
1882        self.print_str_contents(name)?;
1883        self.result.write_str("\"")?;
1884        self.result.reset_color()?;
1885        Ok(())
1886    }
1887
1888    fn print_str_contents(&mut self, name: &str) -> Result<()> {
1889        for c in name.chars() {
1890            let v = c as u32;
1891            if (0x20..0x7f).contains(&v) && c != '"' && c != '\\' && v < 0xff {
1892                write!(self.result, "{c}")?;
1893            } else {
1894                write!(self.result, "\\u{{{v:x}}}",)?;
1895            }
1896        }
1897        Ok(())
1898    }
1899
1900    fn print_bytes(&mut self, bytes: &[u8]) -> Result<()> {
1901        self.result.start_literal()?;
1902        self.result.write_str("\"")?;
1903        for byte in bytes {
1904            if *byte >= 0x20 && *byte < 0x7f && *byte != b'"' && *byte != b'\\' {
1905                write!(self.result, "{}", *byte as char)?;
1906            } else {
1907                self.hex_byte(*byte)?;
1908            }
1909        }
1910        self.result.write_str("\"")?;
1911        self.result.reset_color()?;
1912        Ok(())
1913    }
1914
1915    fn hex_byte(&mut self, byte: u8) -> Result<()> {
1916        write!(self.result, "\\{byte:02x}")?;
1917        Ok(())
1918    }
1919
1920    fn print_known_custom_section(&mut self, section: CustomSectionReader<'_>) -> Result<bool> {
1921        match section.as_known() {
1922            // For now `wasmprinter` has invented syntax for `producers` and
1923            // `dylink.0` below to use in tests. Note that this syntax is not
1924            // official at this time.
1925            KnownCustom::Producers(s) => {
1926                self.newline(section.range().start)?;
1927                self.print_producers_section(s)?;
1928                Ok(true)
1929            }
1930            KnownCustom::Dylink0(s) => {
1931                self.newline(section.range().start)?;
1932                self.print_dylink0_section(s)?;
1933                Ok(true)
1934            }
1935
1936            // These are parsed during `read_names` and are part of
1937            // printing elsewhere, so don't print them.
1938            KnownCustom::Name(_) | KnownCustom::BranchHints(_) => Ok(true),
1939            #[cfg(feature = "component-model")]
1940            KnownCustom::ComponentName(_) => Ok(true),
1941
1942            _ => Ok(false),
1943        }
1944    }
1945
1946    fn print_raw_custom_section(
1947        &mut self,
1948        state: &State,
1949        section: CustomSectionReader<'_>,
1950    ) -> Result<()> {
1951        self.newline(section.range().start)?;
1952        self.start_group("@custom ")?;
1953        self.print_str(section.name())?;
1954        if let Some((place, _)) = state.custom_section_place {
1955            write!(self.result, " ({place})")?;
1956        }
1957        self.result.write_str(" ")?;
1958        if self.config.print_skeleton {
1959            self.result.write_str("...")?;
1960        } else {
1961            self.print_bytes(section.data())?;
1962        }
1963        self.end_group()?;
1964        Ok(())
1965    }
1966
1967    fn print_producers_section(&mut self, section: ProducersSectionReader<'_>) -> Result<()> {
1968        self.start_group("@producers")?;
1969        for field in section {
1970            let field = field?;
1971            for value in field.values.into_iter_with_offsets() {
1972                let (offset, value) = value?;
1973                self.newline(offset)?;
1974                self.start_group(field.name)?;
1975                self.result.write_str(" ")?;
1976                self.print_str(value.name)?;
1977                self.result.write_str(" ")?;
1978                self.print_str(value.version)?;
1979                self.end_group()?;
1980            }
1981        }
1982        self.end_group()?;
1983        Ok(())
1984    }
1985
1986    fn print_dylink0_section(&mut self, mut section: Dylink0SectionReader<'_>) -> Result<()> {
1987        self.start_group("@dylink.0")?;
1988        loop {
1989            let start = section.original_position();
1990            let next = match section.next() {
1991                Some(Ok(next)) => next,
1992                Some(Err(e)) => return Err(e.into()),
1993                None => break,
1994            };
1995            match next {
1996                Dylink0Subsection::MemInfo(info) => {
1997                    self.newline(start)?;
1998                    self.start_group("mem-info")?;
1999                    if info.memory_size > 0 || info.memory_alignment > 0 {
2000                        write!(
2001                            self.result,
2002                            " (memory {} {})",
2003                            info.memory_size, info.memory_alignment
2004                        )?;
2005                    }
2006                    if info.table_size > 0 || info.table_alignment > 0 {
2007                        write!(
2008                            self.result,
2009                            " (table {} {})",
2010                            info.table_size, info.table_alignment
2011                        )?;
2012                    }
2013                    self.end_group()?;
2014                }
2015                Dylink0Subsection::Needed(needed) => {
2016                    self.newline(start)?;
2017                    self.start_group("needed")?;
2018                    for s in needed {
2019                        self.result.write_str(" ")?;
2020                        self.print_str(s)?;
2021                    }
2022                    self.end_group()?;
2023                }
2024                Dylink0Subsection::ExportInfo(info) => {
2025                    for info in info {
2026                        self.newline(start)?;
2027                        self.start_group("export-info ")?;
2028                        self.print_str(info.name)?;
2029                        self.print_dylink0_flags(info.flags)?;
2030                        self.end_group()?;
2031                    }
2032                }
2033                Dylink0Subsection::ImportInfo(info) => {
2034                    for info in info {
2035                        self.newline(start)?;
2036                        self.start_group("import-info ")?;
2037                        self.print_str(info.module)?;
2038                        self.result.write_str(" ")?;
2039                        self.print_str(info.field)?;
2040                        self.print_dylink0_flags(info.flags)?;
2041                        self.end_group()?;
2042                    }
2043                }
2044                Dylink0Subsection::RuntimePath(runtime_path) => {
2045                    self.newline(start)?;
2046                    self.start_group("runtime-path")?;
2047                    for s in runtime_path {
2048                        self.result.write_str(" ")?;
2049                        self.print_str(s)?;
2050                    }
2051                    self.end_group()?;
2052                }
2053                Dylink0Subsection::Unknown { ty, .. } => {
2054                    bail!("don't know how to print dylink.0 subsection id {ty}");
2055                }
2056            }
2057        }
2058        self.end_group()?;
2059        Ok(())
2060    }
2061
2062    fn print_dylink0_flags(&mut self, mut flags: SymbolFlags) -> Result<()> {
2063        macro_rules! print_flag {
2064            ($($name:ident = $text:tt)*) => ({$(
2065                if flags.contains(SymbolFlags::$name) {
2066                    flags.remove(SymbolFlags::$name);
2067                    write!(self.result, concat!(" ", $text))?;
2068                }
2069            )*})
2070        }
2071        // N.B.: Keep in sync with `parse_sym_flags` in `crates/wast/src/core/custom.rs`.
2072        print_flag! {
2073            BINDING_WEAK = "binding-weak"
2074            BINDING_LOCAL = "binding-local"
2075            VISIBILITY_HIDDEN = "visibility-hidden"
2076            UNDEFINED = "undefined"
2077            EXPORTED = "exported"
2078            EXPLICIT_NAME = "explicit-name"
2079            NO_STRIP = "no-strip"
2080            TLS = "tls"
2081            ABSOLUTE = "absolute"
2082        }
2083        if !flags.is_empty() {
2084            write!(self.result, " {flags:#x}")?;
2085        }
2086        Ok(())
2087    }
2088
2089    fn register_branch_hint_section(&mut self, section: BranchHintSectionReader<'_>) -> Result<()> {
2090        self.code_section_hints.clear();
2091        for func in section {
2092            let func = func?;
2093            if self.code_section_hints.len() >= MAX_WASM_FUNCTIONS as usize {
2094                bail!("found too many hints");
2095            }
2096            if func.hints.count() >= MAX_WASM_FUNCTION_SIZE {
2097                bail!("found too many hints");
2098            }
2099            let hints = func
2100                .hints
2101                .into_iter_with_offsets()
2102                .collect::<wasmparser::Result<Vec<_>>>()?;
2103            self.code_section_hints.push((func.func, hints));
2104        }
2105        self.code_section_hints.reverse();
2106        Ok(())
2107    }
2108}
2109
2110struct NamedLocalPrinter {
2111    group_name: &'static str,
2112    in_group: bool,
2113    end_group_after_local: bool,
2114    first: bool,
2115}
2116
2117impl NamedLocalPrinter {
2118    fn new(group_name: &'static str) -> NamedLocalPrinter {
2119        NamedLocalPrinter {
2120            group_name,
2121            in_group: false,
2122            end_group_after_local: false,
2123            first: true,
2124        }
2125    }
2126
2127    fn start_local(
2128        &mut self,
2129        func: Option<u32>,
2130        local: u32,
2131        dst: &mut Printer,
2132        state: &State,
2133    ) -> Result<()> {
2134        let name = state
2135            .core
2136            .local_names
2137            .index_to_name
2138            .get(&(func.unwrap_or(u32::MAX), local));
2139
2140        // Named locals must be in their own group, so if we have a name we need
2141        // to terminate the previous group.
2142        if name.is_some() && self.in_group {
2143            dst.end_group()?;
2144            self.in_group = false;
2145        }
2146
2147        if self.first {
2148            self.first = false;
2149        } else {
2150            dst.result.write_str(" ")?;
2151        }
2152
2153        // Next we either need a separator if we're already in a group or we
2154        // need to open a group for our new local.
2155        if !self.in_group {
2156            dst.start_group(self.group_name)?;
2157            dst.result.write_str(" ")?;
2158            self.in_group = true;
2159        }
2160
2161        // Print the optional name if given...
2162        match name {
2163            Some(name) => {
2164                name.write(dst)?;
2165                dst.result.write_str(" ")?;
2166                self.end_group_after_local = true;
2167            }
2168            None if dst.config.name_unnamed && func.is_some() => {
2169                write!(dst.result, "$#local{local} ")?;
2170                self.end_group_after_local = true;
2171            }
2172            None => {
2173                self.end_group_after_local = false;
2174            }
2175        }
2176        Ok(())
2177    }
2178
2179    fn end_local(&mut self, dst: &mut Printer) -> Result<()> {
2180        if self.end_group_after_local {
2181            dst.end_group()?;
2182            self.end_group_after_local = false;
2183            self.in_group = false;
2184        }
2185        Ok(())
2186    }
2187    fn finish(self, dst: &mut Printer) -> Result<()> {
2188        if self.in_group {
2189            dst.end_group()?;
2190        }
2191        Ok(())
2192    }
2193}
2194
2195macro_rules! print_float {
2196    ($name:ident $float:ident $uint:ident $sint:ident $exp_bits:tt) => {
2197        fn $name(&mut self, mut bits: $uint) -> Result<()> {
2198            // Calculate a few constants
2199            let int_width = mem::size_of::<$uint>() * 8;
2200            let exp_width = $exp_bits;
2201            let mantissa_width = int_width - 1 - exp_width;
2202            let bias = (1 << (exp_width - 1)) - 1;
2203            let max_exp = (1 as $sint) << (exp_width - 1);
2204            let min_exp = -max_exp + 1;
2205
2206            // Handle `NaN` and infinity specially
2207            let f = $float::from_bits(bits);
2208            if bits >> (int_width - 1) != 0 {
2209                bits ^= 1 << (int_width - 1);
2210                self.result.write_str("-")?;
2211            }
2212            if f.is_infinite() {
2213                self.result.start_literal()?;
2214                self.result.write_str("inf ")?;
2215                self.result.start_comment()?;
2216                write!(self.result, "(;={f};)")?;
2217                self.result.reset_color()?;
2218                return Ok(());
2219            }
2220            if f.is_nan() {
2221                let payload = bits & ((1 << mantissa_width) - 1);
2222                self.result.start_literal()?;
2223                if payload == 1 << (mantissa_width - 1) {
2224                    self.result.write_str("nan ")?;
2225                    self.result.start_comment()?;
2226                    write!(self.result, "(;={f};)")?;
2227                } else {
2228                    write!(self.result, "nan:{:#x} ", payload)?;
2229                    self.result.start_comment()?;
2230                    write!(self.result, "(;={f};)")?;
2231                }
2232                self.result.reset_color()?;
2233                return Ok(());
2234            }
2235
2236            // Figure out our exponent, but keep in mine that it's in an
2237            // integer width that may not be supported. As a result we do a few
2238            // tricks here:
2239            //
2240            // * Make the MSB the top bit of the exponent, then shift the
2241            //   exponent to the bottom. This means we now have a signed
2242            //   integer in `$sint` width representing the whole exponent.
2243            // * Do the arithmetic for the exponent (subtract)
2244            // * Next we only care about the lowest `$exp_bits` bits of the
2245            //   result, but we do care about the sign. Use sign-carrying of
2246            //   the signed integer shifts to shift it left then shift it back.
2247            //
2248            // Overall this should do basic arithmetic for `$exp_bits` bit
2249            // numbers and get the result back as a signed integer with `$sint`
2250            // bits in `exponent` representing the same decimal value.
2251            let mut exponent = (((bits << 1) as $sint) >> (mantissa_width + 1)).wrapping_sub(bias);
2252            exponent = (exponent << (int_width - exp_width)) >> (int_width - exp_width);
2253            let mut fraction = bits & ((1 << mantissa_width) - 1);
2254            self.result.start_literal()?;
2255            self.result.write_str("0x")?;
2256            if bits == 0 {
2257                self.result.write_str("0p+0")?;
2258            } else {
2259                self.result.write_str("1")?;
2260                if fraction > 0 {
2261                    fraction <<= (int_width - mantissa_width);
2262
2263                    // Apparently the subnormal is handled here. I don't know
2264                    // what a subnormal is. If someone else does, please let me
2265                    // know!
2266                    if exponent == min_exp {
2267                        let leading = fraction.leading_zeros();
2268                        if (leading as usize) < int_width - 1 {
2269                            fraction <<= leading + 1;
2270                        } else {
2271                            fraction = 0;
2272                        }
2273                        exponent -= leading as $sint;
2274                    }
2275
2276                    self.result.write_str(".")?;
2277                    while fraction > 0 {
2278                        write!(self.result, "{:x}", fraction >> (int_width - 4))?;
2279                        fraction <<= 4;
2280                    }
2281                }
2282                write!(self.result, "p{:+}", exponent)?;
2283            }
2284            self.result.start_comment()?;
2285            write!(self.result, " (;={};)", f)?;
2286            self.result.reset_color()?;
2287            Ok(())
2288        }
2289    };
2290}
2291
2292impl Printer<'_, '_> {
2293    print_float!(print_f32 f32 u32 i32 8);
2294    print_float!(print_f64 f64 u64 i64 11);
2295}
2296
2297impl Naming {
2298    fn new<'a>(
2299        name: &'a str,
2300        index: u32,
2301        group: &str,
2302        used: Option<&mut HashSet<&'a str>>,
2303    ) -> Naming {
2304        let mut kind = NamingKind::DollarName;
2305        if name.chars().any(|c| !is_idchar(c)) {
2306            kind = NamingKind::DollarQuotedName;
2307        }
2308
2309        // If the `name` provided can't be used as the raw identifier for the
2310        // item that it's describing then a synthetic name must be made. The
2311        // rules here which generate a name are:
2312        //
2313        // * Empty identifiers are not allowed
2314        // * Identifiers have a fixed set of valid characters
2315        // * For wasmprinter's purposes we "reserve" identifiers with the `#`
2316        //   prefix, which is in theory rare to encounter in practice.
2317        // * If the name has already been used for some other item and cannot
2318        //   be reused (e.g. because shadowing in this context is not possible).
2319        //
2320        // If any of these conditions match then we generate a unique identifier
2321        // based on `name` but not it exactly. By factoring in the `group`,
2322        // `index`, and `name` we get a guaranteed unique identifier (due to the
2323        // leading `#` prefix that we reserve and factoring in of the item
2324        // index) while preserving human readability at least somewhat (the
2325        // valid identifier characters of `name` still appear in the returned
2326        // name).
2327        if name.is_empty()
2328            || name.starts_with('#')
2329            || used.map(|set| !set.insert(name)).unwrap_or(false)
2330        {
2331            kind = NamingKind::SyntheticPrefix(format!("#{group}{index}"));
2332        }
2333        return Naming {
2334            kind,
2335            name: name.to_string(),
2336        };
2337
2338        // See https://webassembly.github.io/spec/core/text/values.html#text-id
2339        fn is_idchar(c: char) -> bool {
2340            matches!(
2341                c,
2342                '0'..='9'
2343                | 'a'..='z'
2344                | 'A'..='Z'
2345                | '!'
2346                | '#'
2347                | '$'
2348                | '%'
2349                | '&'
2350                | '\''
2351                | '*'
2352                | '+'
2353                | '-'
2354                | '.'
2355                | '/'
2356                | ':'
2357                | '<'
2358                | '='
2359                | '>'
2360                | '?'
2361                | '@'
2362                | '\\'
2363                | '^'
2364                | '_'
2365                | '`'
2366                | '|'
2367                | '~'
2368            )
2369        }
2370    }
2371
2372    fn write_identifier(&self, printer: &mut Printer<'_, '_>) -> Result<()> {
2373        match &self.kind {
2374            NamingKind::DollarName => {
2375                printer.result.write_str("$")?;
2376                printer.result.write_str(&self.name)?;
2377            }
2378            NamingKind::DollarQuotedName => {
2379                printer.result.write_str("$\"")?;
2380                printer.print_str_contents(&self.name)?;
2381                printer.result.write_str("\"")?;
2382            }
2383            NamingKind::SyntheticPrefix(prefix) => {
2384                printer.result.write_str("$\"")?;
2385                printer.result.write_str(&prefix)?;
2386                printer.result.write_str(" ")?;
2387                printer.print_str_contents(&self.name)?;
2388                printer.result.write_str("\"")?;
2389            }
2390        }
2391        Ok(())
2392    }
2393
2394    fn write(&self, dst: &mut Printer<'_, '_>) -> Result<()> {
2395        self.write_identifier(dst)?;
2396        match &self.kind {
2397            NamingKind::DollarName | NamingKind::DollarQuotedName => {}
2398
2399            NamingKind::SyntheticPrefix(_) => {
2400                dst.result.write_str(" ")?;
2401                dst.start_group("@name \"")?;
2402                dst.print_str_contents(&self.name)?;
2403                dst.result.write_str("\"")?;
2404                dst.end_group()?;
2405            }
2406        }
2407        Ok(())
2408    }
2409}
2410
2411/// Helper trait for the `NamingMap` type's `K` type parameter.
2412trait NamingNamespace {
2413    fn desc() -> &'static str;
2414}
2415
2416macro_rules! naming_namespaces {
2417    ($(struct $name:ident => $desc:tt)*) => ($(
2418        struct $name;
2419
2420        impl NamingNamespace for $name {
2421            fn desc() -> &'static str { $desc }
2422        }
2423    )*)
2424}
2425
2426naming_namespaces! {
2427    struct NameFunc => "func"
2428    struct NameGlobal => "global"
2429    struct NameMemory => "memory"
2430    struct NameLocal => "local"
2431    struct NameLabel => "label"
2432    struct NameTable => "table"
2433    struct NameType => "type"
2434    struct NameField => "field"
2435    struct NameData => "data"
2436    struct NameElem => "elem"
2437    struct NameTag => "tag"
2438}
2439
2440#[cfg(feature = "component-model")]
2441naming_namespaces! {
2442    struct NameModule => "module"
2443    struct NameInstance => "instance"
2444    struct NameValue => "value"
2445    struct NameComponent => "component"
2446}
2447
2448fn name_map<K>(into: &mut NamingMap<u32, K>, names: NameMap<'_>, name: &str) -> Result<()> {
2449    let mut used = HashSet::new();
2450    for naming in names {
2451        let naming = naming?;
2452        into.index_to_name.insert(
2453            naming.index,
2454            Naming::new(naming.name, naming.index, name, Some(&mut used)),
2455        );
2456    }
2457    Ok(())
2458}