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) | TypeRef::FuncExact(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::FuncExact(f) => {
1263                self.start_group("func ")?;
1264                if index {
1265                    self.print_name(&state.core.func_names, state.core.funcs)?;
1266                    self.result.write_str(" ")?;
1267                }
1268                self.start_group("exact ")?;
1269                self.print_core_type_ref(state, *f)?;
1270                self.end_group()?;
1271            }
1272            TypeRef::Table(f) => self.print_table_type(state, f, index)?,
1273            TypeRef::Memory(f) => self.print_memory_type(state, f, index)?,
1274            TypeRef::Tag(f) => self.print_tag_type(state, f, index)?,
1275            TypeRef::Global(f) => self.print_global_type(state, f, index)?,
1276        }
1277        self.end_group()?;
1278        Ok(())
1279    }
1280
1281    fn print_table_type(&mut self, state: &State, ty: &TableType, index: bool) -> Result<()> {
1282        self.start_group("table ")?;
1283        if index {
1284            self.print_name(&state.core.table_names, state.core.tables)?;
1285            self.result.write_str(" ")?;
1286        }
1287        if ty.shared {
1288            self.print_type_keyword("shared ")?;
1289        }
1290        if ty.table64 {
1291            self.print_type_keyword("i64 ")?;
1292        }
1293        self.print_limits(ty.initial, ty.maximum)?;
1294        self.result.write_str(" ")?;
1295        self.print_reftype(state, ty.element_type)?;
1296        Ok(())
1297    }
1298
1299    fn print_memory_type(&mut self, state: &State, ty: &MemoryType, index: bool) -> Result<()> {
1300        self.start_group("memory ")?;
1301        if index {
1302            self.print_name(&state.core.memory_names, state.core.memories)?;
1303            self.result.write_str(" ")?;
1304        }
1305        if ty.memory64 {
1306            self.print_type_keyword("i64 ")?;
1307        }
1308        self.print_limits(ty.initial, ty.maximum)?;
1309        if ty.shared {
1310            self.print_type_keyword(" shared")?;
1311        }
1312        if let Some(p) = ty.page_size_log2 {
1313            let p = 1_u64
1314                .checked_shl(p)
1315                .ok_or_else(|| anyhow!("left shift overflow").context("invalid page size"))?;
1316
1317            self.result.write_str(" ")?;
1318            self.start_group("pagesize ")?;
1319            write!(self.result, "{p:#x}")?;
1320            self.end_group()?;
1321        }
1322        Ok(())
1323    }
1324
1325    fn print_tag_type(&mut self, state: &State, ty: &TagType, index: bool) -> Result<()> {
1326        self.start_group("tag ")?;
1327        if index {
1328            self.print_name(&state.core.tag_names, state.core.tags)?;
1329            self.result.write_str(" ")?;
1330        }
1331        self.print_core_functype_idx(state, ty.func_type_idx, None)?;
1332        Ok(())
1333    }
1334
1335    fn print_limits<T>(&mut self, initial: T, maximum: Option<T>) -> Result<()>
1336    where
1337        T: fmt::Display,
1338    {
1339        self.result.start_literal()?;
1340        write!(self.result, "{initial}")?;
1341        if let Some(max) = maximum {
1342            write!(self.result, " {max}")?;
1343        }
1344        self.result.reset_color()?;
1345        Ok(())
1346    }
1347
1348    fn print_global_type(&mut self, state: &State, ty: &GlobalType, index: bool) -> Result<()> {
1349        self.start_group("global ")?;
1350        if index {
1351            self.print_name(&state.core.global_names, state.core.globals)?;
1352            self.result.write_str(" ")?;
1353        }
1354        if ty.shared || ty.mutable {
1355            self.result.write_str("(")?;
1356            if ty.shared {
1357                self.print_type_keyword("shared ")?;
1358            }
1359            if ty.mutable {
1360                self.print_type_keyword("mut ")?;
1361            }
1362            self.print_valtype(state, ty.content_type)?;
1363            self.result.write_str(")")?;
1364        } else {
1365            self.print_valtype(state, ty.content_type)?;
1366        }
1367        Ok(())
1368    }
1369
1370    fn print_tables(&mut self, state: &mut State, parser: TableSectionReader<'_>) -> Result<()> {
1371        for table in parser.into_iter_with_offsets() {
1372            let (offset, table) = table?;
1373            self.newline(offset)?;
1374            self.print_table_type(state, &table.ty, true)?;
1375            match &table.init {
1376                TableInit::RefNull => {}
1377                TableInit::Expr(expr) => {
1378                    self.result.write_str(" ")?;
1379                    self.print_const_expr(state, expr, self.config.fold_instructions)?;
1380                }
1381            }
1382            self.end_group()?;
1383            state.core.tables += 1;
1384        }
1385        Ok(())
1386    }
1387
1388    fn print_memories(&mut self, state: &mut State, parser: MemorySectionReader<'_>) -> Result<()> {
1389        for memory in parser.into_iter_with_offsets() {
1390            let (offset, memory) = memory?;
1391            self.newline(offset)?;
1392            self.print_memory_type(state, &memory, true)?;
1393            self.end_group()?;
1394            state.core.memories += 1;
1395        }
1396        Ok(())
1397    }
1398
1399    fn print_tags(&mut self, state: &mut State, parser: TagSectionReader<'_>) -> Result<()> {
1400        for tag in parser.into_iter_with_offsets() {
1401            let (offset, tag) = tag?;
1402            self.newline(offset)?;
1403            self.print_tag_type(state, &tag, true)?;
1404            self.end_group()?;
1405            debug_assert!(state.core.tag_to_type.len() == state.core.tags as usize);
1406            state.core.tags += 1;
1407            state.core.tag_to_type.push(Some(tag.func_type_idx));
1408        }
1409        Ok(())
1410    }
1411
1412    fn print_globals(&mut self, state: &mut State, parser: GlobalSectionReader<'_>) -> Result<()> {
1413        for global in parser.into_iter_with_offsets() {
1414            let (offset, global) = global?;
1415            self.newline(offset)?;
1416            self.print_global_type(state, &global.ty, true)?;
1417            self.result.write_str(" ")?;
1418            self.print_const_expr(state, &global.init_expr, self.config.fold_instructions)?;
1419            self.end_group()?;
1420            state.core.globals += 1;
1421        }
1422        Ok(())
1423    }
1424
1425    fn print_code_section_entry(
1426        &mut self,
1427        state: &mut State,
1428        body: &FunctionBody<'_>,
1429        validator: Option<operand_stack::FuncValidator>,
1430    ) -> Result<()> {
1431        self.newline(body.get_binary_reader().original_position())?;
1432        self.start_group("func ")?;
1433        let func_idx = state.core.funcs;
1434        self.print_name(&state.core.func_names, func_idx)?;
1435        self.result.write_str(" ")?;
1436        let ty = match state.core.func_to_type.get(func_idx as usize) {
1437            Some(Some(x)) => *x,
1438            _ => panic!("invalid function type"),
1439        };
1440        let params = self
1441            .print_core_functype_idx(state, ty, Some(func_idx))?
1442            .unwrap_or(0);
1443
1444        // Hints are stored on `self` in reverse order of function index so
1445        // check the last one and see if it matches this function.
1446        let hints = match self.code_section_hints.last() {
1447            Some((f, _)) if *f == func_idx => {
1448                let (_, hints) = self.code_section_hints.pop().unwrap();
1449                hints
1450            }
1451            _ => Vec::new(),
1452        };
1453
1454        if self.config.print_skeleton {
1455            self.result.write_str(" ...")?;
1456            self.end_group()?;
1457        } else {
1458            let end_pos =
1459                self.print_func_body(state, func_idx, params, &body, &hints, validator)?;
1460            self.end_group_at_pos(end_pos)?;
1461        }
1462
1463        state.core.funcs += 1;
1464        Ok(())
1465    }
1466
1467    fn print_func_body(
1468        &mut self,
1469        state: &mut State,
1470        func_idx: u32,
1471        params: u32,
1472        body: &FunctionBody<'_>,
1473        branch_hints: &[(usize, BranchHint)],
1474        mut validator: Option<operand_stack::FuncValidator>,
1475    ) -> Result<usize> {
1476        let mut first = true;
1477        let mut local_idx = 0;
1478        let mut locals = NamedLocalPrinter::new("local");
1479        let mut reader = body.get_binary_reader();
1480        let func_start = reader.original_position();
1481        for _ in 0..reader.read_var_u32()? {
1482            let offset = reader.original_position();
1483            let cnt = reader.read_var_u32()?;
1484            let ty = reader.read()?;
1485            if MAX_LOCALS
1486                .checked_sub(local_idx)
1487                .and_then(|s| s.checked_sub(cnt))
1488                .is_none()
1489            {
1490                bail!("function exceeds the maximum number of locals that can be printed");
1491            }
1492            for _ in 0..cnt {
1493                if first {
1494                    self.newline(offset)?;
1495                    first = false;
1496                }
1497                locals.start_local(Some(func_idx), params + local_idx, self, state)?;
1498                self.print_valtype(state, ty)?;
1499                locals.end_local(self)?;
1500                local_idx += 1;
1501            }
1502        }
1503        locals.finish(self)?;
1504
1505        if let Some(f) = &mut validator {
1506            if let Err(e) = f.read_locals(body.get_binary_reader()) {
1507                validator = None;
1508                self.newline_unknown_pos()?;
1509                write!(self.result, ";; locals are invalid: {e}")?;
1510            }
1511        }
1512
1513        let nesting_start = self.nesting;
1514        let fold_instructions = self.config.fold_instructions;
1515        let mut operator_state = OperatorState::new(self, OperatorSeparator::Newline);
1516
1517        let end_pos = if fold_instructions {
1518            let mut folded_printer = PrintOperatorFolded::new(self, state, &mut operator_state);
1519            folded_printer.set_offset(func_start);
1520            folded_printer.begin_function(func_idx)?;
1521            Self::print_operators(
1522                &mut reader,
1523                branch_hints,
1524                func_start,
1525                &mut folded_printer,
1526                validator,
1527            )?
1528        } else {
1529            let mut flat_printer = PrintOperator::new(self, state, &mut operator_state);
1530            Self::print_operators(
1531                &mut reader,
1532                branch_hints,
1533                func_start,
1534                &mut flat_printer,
1535                validator,
1536            )?
1537        };
1538
1539        // If this was an invalid function body then the nesting may not
1540        // have reset back to normal. Fix that up here and forcibly insert
1541        // a newline as well in case the last instruction was something
1542        // like an `if` which has a comment after it which could interfere
1543        // with the closing paren printed for the func.
1544        if self.nesting != nesting_start {
1545            self.nesting = nesting_start;
1546            self.newline(reader.original_position())?;
1547        }
1548
1549        Ok(end_pos)
1550    }
1551
1552    fn print_operators<'a, O: OpPrinter>(
1553        body: &mut BinaryReader<'a>,
1554        mut branch_hints: &[(usize, BranchHint)],
1555        func_start: usize,
1556        op_printer: &mut O,
1557        mut validator: Option<operand_stack::FuncValidator>,
1558    ) -> Result<usize> {
1559        let mut ops = OperatorsReader::new(body.clone());
1560        while !ops.eof() {
1561            if ops.is_end_then_eof() {
1562                let mut annotation = None;
1563                if let Some(f) = &mut validator {
1564                    match f.visit_operator(&ops, true) {
1565                        Ok(()) => {}
1566                        Err(_) => {
1567                            annotation = Some(String::from("type mismatch at end of expression"))
1568                        }
1569                    }
1570                }
1571
1572                let end_pos = ops.original_position();
1573                ops.read()?; // final "end" opcode terminates instruction sequence
1574                ops.finish()?;
1575                op_printer.finalize(annotation.as_deref())?;
1576                return Ok(end_pos);
1577            }
1578
1579            // Branch hints are stored in increasing order of their body offset
1580            // so print them whenever their instruction comes up.
1581            if let Some(((hint_offset, hint), rest)) = branch_hints.split_first() {
1582                if hint.func_offset == (ops.original_position() - func_start) as u32 {
1583                    branch_hints = rest;
1584                    op_printer.branch_hint(*hint_offset, hint.taken)?;
1585                }
1586            }
1587            let mut annotation = None;
1588            if let Some(f) = &mut validator {
1589                let result = f
1590                    .visit_operator(&ops, false)
1591                    .map_err(anyhow::Error::from)
1592                    .and_then(|()| f.visualize_operand_stack(op_printer.use_color()));
1593                match result {
1594                    Ok(s) => annotation = Some(s),
1595                    Err(_) => {
1596                        validator = None;
1597                        annotation = Some(String::from("(invalid)"));
1598                    }
1599                }
1600            }
1601            op_printer.set_offset(ops.original_position());
1602            op_printer.visit_operator(&mut ops, annotation.as_deref())?;
1603        }
1604        ops.finish()?; // for the error message
1605        bail!("unexpected end of operators");
1606    }
1607
1608    fn newline(&mut self, offset: usize) -> Result<()> {
1609        self.print_newline(Some(offset))
1610    }
1611
1612    fn newline_unknown_pos(&mut self) -> Result<()> {
1613        self.print_newline(None)
1614    }
1615
1616    fn print_newline(&mut self, offset: Option<usize>) -> Result<()> {
1617        self.result.newline()?;
1618        self.result.start_line(offset);
1619
1620        if self.config.print_offsets {
1621            match offset {
1622                Some(offset) => {
1623                    self.result.start_comment()?;
1624                    write!(self.result, "(;@{offset:<6x};)")?;
1625                    self.result.reset_color()?;
1626                }
1627                None => self.result.write_str("           ")?,
1628            }
1629        }
1630        self.line += 1;
1631
1632        // Clamp the maximum nesting size that we print at something somewhat
1633        // reasonable to avoid generating hundreds of megabytes of whitespace
1634        // for small-ish modules that have deep-ish nesting.
1635        for _ in 0..self.nesting.min(MAX_NESTING_TO_PRINT) {
1636            self.result.write_str(&self.config.indent_text)?;
1637        }
1638        Ok(())
1639    }
1640
1641    fn print_exports(&mut self, state: &State, data: ExportSectionReader) -> Result<()> {
1642        for export in data.into_iter_with_offsets() {
1643            let (offset, export) = export?;
1644            self.newline(offset)?;
1645            self.print_export(state, &export)?;
1646        }
1647        Ok(())
1648    }
1649
1650    fn print_export(&mut self, state: &State, export: &Export) -> Result<()> {
1651        self.start_group("export ")?;
1652        self.print_str(export.name)?;
1653        self.result.write_str(" ")?;
1654        self.print_external_kind(state, export.kind, export.index)?;
1655        self.end_group()?; // export
1656        Ok(())
1657    }
1658
1659    fn print_external_kind(&mut self, state: &State, kind: ExternalKind, index: u32) -> Result<()> {
1660        match kind {
1661            ExternalKind::Func | ExternalKind::FuncExact => {
1662                self.start_group("func ")?;
1663                self.print_idx(&state.core.func_names, index)?;
1664            }
1665            ExternalKind::Table => {
1666                self.start_group("table ")?;
1667                self.print_idx(&state.core.table_names, index)?;
1668            }
1669            ExternalKind::Global => {
1670                self.start_group("global ")?;
1671                self.print_idx(&state.core.global_names, index)?;
1672            }
1673            ExternalKind::Memory => {
1674                self.start_group("memory ")?;
1675                self.print_idx(&state.core.memory_names, index)?;
1676            }
1677            ExternalKind::Tag => {
1678                self.start_group("tag ")?;
1679                write!(self.result, "{index}")?;
1680            }
1681        }
1682        self.end_group()?;
1683        Ok(())
1684    }
1685
1686    fn print_core_type_ref(&mut self, state: &State, idx: u32) -> Result<()> {
1687        self.start_group("type ")?;
1688        self.print_idx(&state.core.type_names, idx)?;
1689        self.end_group()?;
1690        Ok(())
1691    }
1692
1693    // Note: in the text format, modules can use identifiers that are defined anywhere, but
1694    // components can only use previously-defined identifiers. In the binary format,
1695    // invalid components can make forward references to an index that appears in the name section;
1696    // these can be printed but the output won't parse.
1697    fn print_idx<K>(&mut self, names: &NamingMap<u32, K>, idx: u32) -> Result<()>
1698    where
1699        K: NamingNamespace,
1700    {
1701        self._print_idx(&names.index_to_name, idx, K::desc())
1702    }
1703
1704    fn _print_idx(&mut self, names: &HashMap<u32, Naming>, idx: u32, desc: &str) -> Result<()> {
1705        self.result.start_name()?;
1706        match names.get(&idx) {
1707            Some(name) => name.write_identifier(self)?,
1708            None if self.config.name_unnamed => write!(self.result, "$#{desc}{idx}")?,
1709            None => write!(self.result, "{idx}")?,
1710        }
1711        self.result.reset_color()?;
1712        Ok(())
1713    }
1714
1715    fn print_local_idx(&mut self, state: &State, func: u32, idx: u32) -> Result<()> {
1716        self.result.start_name()?;
1717        match state.core.local_names.index_to_name.get(&(func, idx)) {
1718            Some(name) => name.write_identifier(self)?,
1719            None if self.config.name_unnamed => write!(self.result, "$#local{idx}")?,
1720            None => write!(self.result, "{idx}")?,
1721        }
1722        self.result.reset_color()?;
1723        Ok(())
1724    }
1725
1726    fn print_field_idx(&mut self, state: &State, ty: u32, idx: u32) -> Result<()> {
1727        self.result.start_name()?;
1728        match state.core.field_names.index_to_name.get(&(ty, idx)) {
1729            Some(name) => name.write_identifier(self)?,
1730            None if self.config.name_unnamed => write!(self.result, "$#field{idx}")?,
1731            None => write!(self.result, "{idx}")?,
1732        }
1733        self.result.reset_color()?;
1734        Ok(())
1735    }
1736
1737    fn print_name<K>(&mut self, names: &NamingMap<u32, K>, cur_idx: u32) -> Result<()>
1738    where
1739        K: NamingNamespace,
1740    {
1741        self._print_name(&names.index_to_name, cur_idx, K::desc())
1742    }
1743
1744    fn _print_name(
1745        &mut self,
1746        names: &HashMap<u32, Naming>,
1747        cur_idx: u32,
1748        desc: &str,
1749    ) -> Result<()> {
1750        self.result.start_name()?;
1751        match names.get(&cur_idx) {
1752            Some(name) => {
1753                name.write(self)?;
1754                self.result.write_str(" ")?;
1755            }
1756            None if self.config.name_unnamed => {
1757                write!(self.result, "$#{desc}{cur_idx} ")?;
1758            }
1759            None => {}
1760        }
1761        write!(self.result, "(;{cur_idx};)")?;
1762        self.result.reset_color()?;
1763        Ok(())
1764    }
1765
1766    fn print_elems(&mut self, state: &mut State, data: ElementSectionReader) -> Result<()> {
1767        for (i, elem) in data.into_iter_with_offsets().enumerate() {
1768            let (offset, mut elem) = elem?;
1769            self.newline(offset)?;
1770            self.start_group("elem ")?;
1771            self.print_name(&state.core.element_names, i as u32)?;
1772            match &mut elem.kind {
1773                ElementKind::Passive => {}
1774                ElementKind::Declared => self.result.write_str(" declare")?,
1775                ElementKind::Active {
1776                    table_index,
1777                    offset_expr,
1778                } => {
1779                    if let Some(table_index) = *table_index {
1780                        self.result.write_str(" ")?;
1781                        self.start_group("table ")?;
1782                        self.print_idx(&state.core.table_names, table_index)?;
1783                        self.end_group()?;
1784                    }
1785                    self.result.write_str(" ")?;
1786                    self.print_const_expr_sugar(state, offset_expr, "offset")?;
1787                }
1788            }
1789            self.result.write_str(" ")?;
1790
1791            if self.config.print_skeleton {
1792                self.result.write_str("...")?;
1793            } else {
1794                match elem.items {
1795                    ElementItems::Functions(reader) => {
1796                        self.result.write_str("func")?;
1797                        for idx in reader {
1798                            self.result.write_str(" ")?;
1799                            self.print_idx(&state.core.func_names, idx?)?
1800                        }
1801                    }
1802                    ElementItems::Expressions(ty, reader) => {
1803                        self.print_reftype(state, ty)?;
1804                        for expr in reader {
1805                            self.result.write_str(" ")?;
1806                            self.print_const_expr_sugar(state, &expr?, "item")?
1807                        }
1808                    }
1809                }
1810            }
1811            self.end_group()?;
1812        }
1813        Ok(())
1814    }
1815
1816    fn print_data(&mut self, state: &mut State, data: DataSectionReader) -> Result<()> {
1817        for (i, data) in data.into_iter_with_offsets().enumerate() {
1818            let (offset, data) = data?;
1819            self.newline(offset)?;
1820            self.start_group("data ")?;
1821            self.print_name(&state.core.data_names, i as u32)?;
1822            self.result.write_str(" ")?;
1823            match &data.kind {
1824                DataKind::Passive => {}
1825                DataKind::Active {
1826                    memory_index,
1827                    offset_expr,
1828                } => {
1829                    if *memory_index != 0 {
1830                        self.start_group("memory ")?;
1831                        self.print_idx(&state.core.memory_names, *memory_index)?;
1832                        self.end_group()?;
1833                        self.result.write_str(" ")?;
1834                    }
1835                    self.print_const_expr_sugar(state, offset_expr, "offset")?;
1836                    self.result.write_str(" ")?;
1837                }
1838            }
1839            if self.config.print_skeleton {
1840                self.result.write_str("...")?;
1841            } else {
1842                self.print_bytes(data.data)?;
1843            }
1844            self.end_group()?;
1845        }
1846        Ok(())
1847    }
1848
1849    /// Prints the operators of `expr` space-separated, taking into account that
1850    /// if there's only one operator in `expr` then instead of `(explicit ...)`
1851    /// the printing can be `(...)`.
1852    fn print_const_expr_sugar(
1853        &mut self,
1854        state: &mut State,
1855        expr: &ConstExpr,
1856        explicit: &str,
1857    ) -> Result<()> {
1858        self.start_group("")?;
1859        let mut reader = expr.get_operators_reader();
1860
1861        if reader.read().is_ok() && !reader.is_end_then_eof() {
1862            write!(self.result, "{explicit} ")?;
1863            self.print_const_expr(state, expr, self.config.fold_instructions)?;
1864        } else {
1865            self.print_const_expr(state, expr, false)?;
1866        }
1867
1868        self.end_group()?;
1869        Ok(())
1870    }
1871
1872    /// Prints the operators of `expr` space-separated.
1873    fn print_const_expr(&mut self, state: &mut State, expr: &ConstExpr, fold: bool) -> Result<()> {
1874        let mut reader = expr.get_binary_reader();
1875        let mut operator_state = OperatorState::new(self, OperatorSeparator::NoneThenSpace);
1876
1877        if fold {
1878            let mut folded_printer = PrintOperatorFolded::new(self, state, &mut operator_state);
1879            folded_printer.begin_const_expr();
1880            Self::print_operators(&mut reader, &[], 0, &mut folded_printer, None)?;
1881        } else {
1882            let mut op_printer = PrintOperator::new(self, state, &mut operator_state);
1883            Self::print_operators(&mut reader, &[], 0, &mut op_printer, None)?;
1884        }
1885
1886        Ok(())
1887    }
1888
1889    fn print_str(&mut self, name: &str) -> Result<()> {
1890        self.result.start_literal()?;
1891        self.result.write_str("\"")?;
1892        self.print_str_contents(name)?;
1893        self.result.write_str("\"")?;
1894        self.result.reset_color()?;
1895        Ok(())
1896    }
1897
1898    fn print_str_contents(&mut self, name: &str) -> Result<()> {
1899        for c in name.chars() {
1900            let v = c as u32;
1901            if (0x20..0x7f).contains(&v) && c != '"' && c != '\\' && v < 0xff {
1902                write!(self.result, "{c}")?;
1903            } else {
1904                write!(self.result, "\\u{{{v:x}}}",)?;
1905            }
1906        }
1907        Ok(())
1908    }
1909
1910    fn print_bytes(&mut self, bytes: &[u8]) -> Result<()> {
1911        self.result.start_literal()?;
1912        self.result.write_str("\"")?;
1913        for byte in bytes {
1914            if *byte >= 0x20 && *byte < 0x7f && *byte != b'"' && *byte != b'\\' {
1915                write!(self.result, "{}", *byte as char)?;
1916            } else {
1917                self.hex_byte(*byte)?;
1918            }
1919        }
1920        self.result.write_str("\"")?;
1921        self.result.reset_color()?;
1922        Ok(())
1923    }
1924
1925    fn hex_byte(&mut self, byte: u8) -> Result<()> {
1926        write!(self.result, "\\{byte:02x}")?;
1927        Ok(())
1928    }
1929
1930    fn print_known_custom_section(&mut self, section: CustomSectionReader<'_>) -> Result<bool> {
1931        match section.as_known() {
1932            // For now `wasmprinter` has invented syntax for `producers` and
1933            // `dylink.0` below to use in tests. Note that this syntax is not
1934            // official at this time.
1935            KnownCustom::Producers(s) => {
1936                self.newline(section.range().start)?;
1937                self.print_producers_section(s)?;
1938                Ok(true)
1939            }
1940            KnownCustom::Dylink0(s) => {
1941                self.newline(section.range().start)?;
1942                self.print_dylink0_section(s)?;
1943                Ok(true)
1944            }
1945
1946            // These are parsed during `read_names` and are part of
1947            // printing elsewhere, so don't print them.
1948            KnownCustom::Name(_) | KnownCustom::BranchHints(_) => Ok(true),
1949            #[cfg(feature = "component-model")]
1950            KnownCustom::ComponentName(_) => Ok(true),
1951
1952            _ => Ok(false),
1953        }
1954    }
1955
1956    fn print_raw_custom_section(
1957        &mut self,
1958        state: &State,
1959        section: CustomSectionReader<'_>,
1960    ) -> Result<()> {
1961        self.newline(section.range().start)?;
1962        self.start_group("@custom ")?;
1963        self.print_str(section.name())?;
1964        if let Some((place, _)) = state.custom_section_place {
1965            write!(self.result, " ({place})")?;
1966        }
1967        self.result.write_str(" ")?;
1968        if self.config.print_skeleton {
1969            self.result.write_str("...")?;
1970        } else {
1971            self.print_bytes(section.data())?;
1972        }
1973        self.end_group()?;
1974        Ok(())
1975    }
1976
1977    fn print_producers_section(&mut self, section: ProducersSectionReader<'_>) -> Result<()> {
1978        self.start_group("@producers")?;
1979        for field in section {
1980            let field = field?;
1981            for value in field.values.into_iter_with_offsets() {
1982                let (offset, value) = value?;
1983                self.newline(offset)?;
1984                self.start_group(field.name)?;
1985                self.result.write_str(" ")?;
1986                self.print_str(value.name)?;
1987                self.result.write_str(" ")?;
1988                self.print_str(value.version)?;
1989                self.end_group()?;
1990            }
1991        }
1992        self.end_group()?;
1993        Ok(())
1994    }
1995
1996    fn print_dylink0_section(&mut self, mut section: Dylink0SectionReader<'_>) -> Result<()> {
1997        self.start_group("@dylink.0")?;
1998        loop {
1999            let start = section.original_position();
2000            let next = match section.next() {
2001                Some(Ok(next)) => next,
2002                Some(Err(e)) => return Err(e.into()),
2003                None => break,
2004            };
2005            match next {
2006                Dylink0Subsection::MemInfo(info) => {
2007                    self.newline(start)?;
2008                    self.start_group("mem-info")?;
2009                    if info.memory_size > 0 || info.memory_alignment > 0 {
2010                        write!(
2011                            self.result,
2012                            " (memory {} {})",
2013                            info.memory_size, info.memory_alignment
2014                        )?;
2015                    }
2016                    if info.table_size > 0 || info.table_alignment > 0 {
2017                        write!(
2018                            self.result,
2019                            " (table {} {})",
2020                            info.table_size, info.table_alignment
2021                        )?;
2022                    }
2023                    self.end_group()?;
2024                }
2025                Dylink0Subsection::Needed(needed) => {
2026                    self.newline(start)?;
2027                    self.start_group("needed")?;
2028                    for s in needed {
2029                        self.result.write_str(" ")?;
2030                        self.print_str(s)?;
2031                    }
2032                    self.end_group()?;
2033                }
2034                Dylink0Subsection::ExportInfo(info) => {
2035                    for info in info {
2036                        self.newline(start)?;
2037                        self.start_group("export-info ")?;
2038                        self.print_str(info.name)?;
2039                        self.print_dylink0_flags(info.flags)?;
2040                        self.end_group()?;
2041                    }
2042                }
2043                Dylink0Subsection::ImportInfo(info) => {
2044                    for info in info {
2045                        self.newline(start)?;
2046                        self.start_group("import-info ")?;
2047                        self.print_str(info.module)?;
2048                        self.result.write_str(" ")?;
2049                        self.print_str(info.field)?;
2050                        self.print_dylink0_flags(info.flags)?;
2051                        self.end_group()?;
2052                    }
2053                }
2054                Dylink0Subsection::RuntimePath(runtime_path) => {
2055                    self.newline(start)?;
2056                    self.start_group("runtime-path")?;
2057                    for s in runtime_path {
2058                        self.result.write_str(" ")?;
2059                        self.print_str(s)?;
2060                    }
2061                    self.end_group()?;
2062                }
2063                Dylink0Subsection::Unknown { ty, .. } => {
2064                    bail!("don't know how to print dylink.0 subsection id {ty}");
2065                }
2066            }
2067        }
2068        self.end_group()?;
2069        Ok(())
2070    }
2071
2072    fn print_dylink0_flags(&mut self, mut flags: SymbolFlags) -> Result<()> {
2073        macro_rules! print_flag {
2074            ($($name:ident = $text:tt)*) => ({$(
2075                if flags.contains(SymbolFlags::$name) {
2076                    flags.remove(SymbolFlags::$name);
2077                    write!(self.result, concat!(" ", $text))?;
2078                }
2079            )*})
2080        }
2081        // N.B.: Keep in sync with `parse_sym_flags` in `crates/wast/src/core/custom.rs`.
2082        print_flag! {
2083            BINDING_WEAK = "binding-weak"
2084            BINDING_LOCAL = "binding-local"
2085            VISIBILITY_HIDDEN = "visibility-hidden"
2086            UNDEFINED = "undefined"
2087            EXPORTED = "exported"
2088            EXPLICIT_NAME = "explicit-name"
2089            NO_STRIP = "no-strip"
2090            TLS = "tls"
2091            ABSOLUTE = "absolute"
2092        }
2093        if !flags.is_empty() {
2094            write!(self.result, " {flags:#x}")?;
2095        }
2096        Ok(())
2097    }
2098
2099    fn register_branch_hint_section(&mut self, section: BranchHintSectionReader<'_>) -> Result<()> {
2100        self.code_section_hints.clear();
2101        for func in section {
2102            let func = func?;
2103            if self.code_section_hints.len() >= MAX_WASM_FUNCTIONS as usize {
2104                bail!("found too many hints");
2105            }
2106            if func.hints.count() >= MAX_WASM_FUNCTION_SIZE {
2107                bail!("found too many hints");
2108            }
2109            let hints = func
2110                .hints
2111                .into_iter_with_offsets()
2112                .collect::<wasmparser::Result<Vec<_>>>()?;
2113            self.code_section_hints.push((func.func, hints));
2114        }
2115        self.code_section_hints.reverse();
2116        Ok(())
2117    }
2118}
2119
2120struct NamedLocalPrinter {
2121    group_name: &'static str,
2122    in_group: bool,
2123    end_group_after_local: bool,
2124    first: bool,
2125}
2126
2127impl NamedLocalPrinter {
2128    fn new(group_name: &'static str) -> NamedLocalPrinter {
2129        NamedLocalPrinter {
2130            group_name,
2131            in_group: false,
2132            end_group_after_local: false,
2133            first: true,
2134        }
2135    }
2136
2137    fn start_local(
2138        &mut self,
2139        func: Option<u32>,
2140        local: u32,
2141        dst: &mut Printer,
2142        state: &State,
2143    ) -> Result<()> {
2144        let name = state
2145            .core
2146            .local_names
2147            .index_to_name
2148            .get(&(func.unwrap_or(u32::MAX), local));
2149
2150        // Named locals must be in their own group, so if we have a name we need
2151        // to terminate the previous group.
2152        if name.is_some() && self.in_group {
2153            dst.end_group()?;
2154            self.in_group = false;
2155        }
2156
2157        if self.first {
2158            self.first = false;
2159        } else {
2160            dst.result.write_str(" ")?;
2161        }
2162
2163        // Next we either need a separator if we're already in a group or we
2164        // need to open a group for our new local.
2165        if !self.in_group {
2166            dst.start_group(self.group_name)?;
2167            dst.result.write_str(" ")?;
2168            self.in_group = true;
2169        }
2170
2171        // Print the optional name if given...
2172        match name {
2173            Some(name) => {
2174                name.write(dst)?;
2175                dst.result.write_str(" ")?;
2176                self.end_group_after_local = true;
2177            }
2178            None if dst.config.name_unnamed && func.is_some() => {
2179                write!(dst.result, "$#local{local} ")?;
2180                self.end_group_after_local = true;
2181            }
2182            None => {
2183                self.end_group_after_local = false;
2184            }
2185        }
2186        Ok(())
2187    }
2188
2189    fn end_local(&mut self, dst: &mut Printer) -> Result<()> {
2190        if self.end_group_after_local {
2191            dst.end_group()?;
2192            self.end_group_after_local = false;
2193            self.in_group = false;
2194        }
2195        Ok(())
2196    }
2197    fn finish(self, dst: &mut Printer) -> Result<()> {
2198        if self.in_group {
2199            dst.end_group()?;
2200        }
2201        Ok(())
2202    }
2203}
2204
2205macro_rules! print_float {
2206    ($name:ident $float:ident $uint:ident $sint:ident $exp_bits:tt) => {
2207        fn $name(&mut self, mut bits: $uint) -> Result<()> {
2208            // Calculate a few constants
2209            let int_width = mem::size_of::<$uint>() * 8;
2210            let exp_width = $exp_bits;
2211            let mantissa_width = int_width - 1 - exp_width;
2212            let bias = (1 << (exp_width - 1)) - 1;
2213            let max_exp = (1 as $sint) << (exp_width - 1);
2214            let min_exp = -max_exp + 1;
2215
2216            // Handle `NaN` and infinity specially
2217            let f = $float::from_bits(bits);
2218            if bits >> (int_width - 1) != 0 {
2219                bits ^= 1 << (int_width - 1);
2220                self.result.write_str("-")?;
2221            }
2222            if f.is_infinite() {
2223                self.result.start_literal()?;
2224                self.result.write_str("inf ")?;
2225                self.result.start_comment()?;
2226                write!(self.result, "(;={f};)")?;
2227                self.result.reset_color()?;
2228                return Ok(());
2229            }
2230            if f.is_nan() {
2231                let payload = bits & ((1 << mantissa_width) - 1);
2232                self.result.start_literal()?;
2233                if payload == 1 << (mantissa_width - 1) {
2234                    self.result.write_str("nan ")?;
2235                    self.result.start_comment()?;
2236                    write!(self.result, "(;={f};)")?;
2237                } else {
2238                    write!(self.result, "nan:{:#x} ", payload)?;
2239                    self.result.start_comment()?;
2240                    write!(self.result, "(;={f};)")?;
2241                }
2242                self.result.reset_color()?;
2243                return Ok(());
2244            }
2245
2246            // Figure out our exponent, but keep in mine that it's in an
2247            // integer width that may not be supported. As a result we do a few
2248            // tricks here:
2249            //
2250            // * Make the MSB the top bit of the exponent, then shift the
2251            //   exponent to the bottom. This means we now have a signed
2252            //   integer in `$sint` width representing the whole exponent.
2253            // * Do the arithmetic for the exponent (subtract)
2254            // * Next we only care about the lowest `$exp_bits` bits of the
2255            //   result, but we do care about the sign. Use sign-carrying of
2256            //   the signed integer shifts to shift it left then shift it back.
2257            //
2258            // Overall this should do basic arithmetic for `$exp_bits` bit
2259            // numbers and get the result back as a signed integer with `$sint`
2260            // bits in `exponent` representing the same decimal value.
2261            let mut exponent = (((bits << 1) as $sint) >> (mantissa_width + 1)).wrapping_sub(bias);
2262            exponent = (exponent << (int_width - exp_width)) >> (int_width - exp_width);
2263            let mut fraction = bits & ((1 << mantissa_width) - 1);
2264            self.result.start_literal()?;
2265            self.result.write_str("0x")?;
2266            if bits == 0 {
2267                self.result.write_str("0p+0")?;
2268            } else {
2269                self.result.write_str("1")?;
2270                if fraction > 0 {
2271                    fraction <<= (int_width - mantissa_width);
2272
2273                    // Apparently the subnormal is handled here. I don't know
2274                    // what a subnormal is. If someone else does, please let me
2275                    // know!
2276                    if exponent == min_exp {
2277                        let leading = fraction.leading_zeros();
2278                        if (leading as usize) < int_width - 1 {
2279                            fraction <<= leading + 1;
2280                        } else {
2281                            fraction = 0;
2282                        }
2283                        exponent -= leading as $sint;
2284                    }
2285
2286                    self.result.write_str(".")?;
2287                    while fraction > 0 {
2288                        write!(self.result, "{:x}", fraction >> (int_width - 4))?;
2289                        fraction <<= 4;
2290                    }
2291                }
2292                write!(self.result, "p{:+}", exponent)?;
2293            }
2294            self.result.start_comment()?;
2295            write!(self.result, " (;={};)", f)?;
2296            self.result.reset_color()?;
2297            Ok(())
2298        }
2299    };
2300}
2301
2302impl Printer<'_, '_> {
2303    print_float!(print_f32 f32 u32 i32 8);
2304    print_float!(print_f64 f64 u64 i64 11);
2305}
2306
2307impl Naming {
2308    fn new<'a>(
2309        name: &'a str,
2310        index: u32,
2311        group: &str,
2312        used: Option<&mut HashSet<&'a str>>,
2313    ) -> Naming {
2314        let mut kind = NamingKind::DollarName;
2315        if name.chars().any(|c| !is_idchar(c)) {
2316            kind = NamingKind::DollarQuotedName;
2317        }
2318
2319        // If the `name` provided can't be used as the raw identifier for the
2320        // item that it's describing then a synthetic name must be made. The
2321        // rules here which generate a name are:
2322        //
2323        // * Empty identifiers are not allowed
2324        // * Identifiers have a fixed set of valid characters
2325        // * For wasmprinter's purposes we "reserve" identifiers with the `#`
2326        //   prefix, which is in theory rare to encounter in practice.
2327        // * If the name has already been used for some other item and cannot
2328        //   be reused (e.g. because shadowing in this context is not possible).
2329        //
2330        // If any of these conditions match then we generate a unique identifier
2331        // based on `name` but not it exactly. By factoring in the `group`,
2332        // `index`, and `name` we get a guaranteed unique identifier (due to the
2333        // leading `#` prefix that we reserve and factoring in of the item
2334        // index) while preserving human readability at least somewhat (the
2335        // valid identifier characters of `name` still appear in the returned
2336        // name).
2337        if name.is_empty()
2338            || name.starts_with('#')
2339            || used.map(|set| !set.insert(name)).unwrap_or(false)
2340        {
2341            kind = NamingKind::SyntheticPrefix(format!("#{group}{index}"));
2342        }
2343        return Naming {
2344            kind,
2345            name: name.to_string(),
2346        };
2347
2348        // See https://webassembly.github.io/spec/core/text/values.html#text-id
2349        fn is_idchar(c: char) -> bool {
2350            matches!(
2351                c,
2352                '0'..='9'
2353                | 'a'..='z'
2354                | 'A'..='Z'
2355                | '!'
2356                | '#'
2357                | '$'
2358                | '%'
2359                | '&'
2360                | '\''
2361                | '*'
2362                | '+'
2363                | '-'
2364                | '.'
2365                | '/'
2366                | ':'
2367                | '<'
2368                | '='
2369                | '>'
2370                | '?'
2371                | '@'
2372                | '\\'
2373                | '^'
2374                | '_'
2375                | '`'
2376                | '|'
2377                | '~'
2378            )
2379        }
2380    }
2381
2382    fn write_identifier(&self, printer: &mut Printer<'_, '_>) -> Result<()> {
2383        match &self.kind {
2384            NamingKind::DollarName => {
2385                printer.result.write_str("$")?;
2386                printer.result.write_str(&self.name)?;
2387            }
2388            NamingKind::DollarQuotedName => {
2389                printer.result.write_str("$\"")?;
2390                printer.print_str_contents(&self.name)?;
2391                printer.result.write_str("\"")?;
2392            }
2393            NamingKind::SyntheticPrefix(prefix) => {
2394                printer.result.write_str("$\"")?;
2395                printer.result.write_str(&prefix)?;
2396                printer.result.write_str(" ")?;
2397                printer.print_str_contents(&self.name)?;
2398                printer.result.write_str("\"")?;
2399            }
2400        }
2401        Ok(())
2402    }
2403
2404    fn write(&self, dst: &mut Printer<'_, '_>) -> Result<()> {
2405        self.write_identifier(dst)?;
2406        match &self.kind {
2407            NamingKind::DollarName | NamingKind::DollarQuotedName => {}
2408
2409            NamingKind::SyntheticPrefix(_) => {
2410                dst.result.write_str(" ")?;
2411                dst.start_group("@name \"")?;
2412                dst.print_str_contents(&self.name)?;
2413                dst.result.write_str("\"")?;
2414                dst.end_group()?;
2415            }
2416        }
2417        Ok(())
2418    }
2419}
2420
2421/// Helper trait for the `NamingMap` type's `K` type parameter.
2422trait NamingNamespace {
2423    fn desc() -> &'static str;
2424}
2425
2426macro_rules! naming_namespaces {
2427    ($(struct $name:ident => $desc:tt)*) => ($(
2428        struct $name;
2429
2430        impl NamingNamespace for $name {
2431            fn desc() -> &'static str { $desc }
2432        }
2433    )*)
2434}
2435
2436naming_namespaces! {
2437    struct NameFunc => "func"
2438    struct NameGlobal => "global"
2439    struct NameMemory => "memory"
2440    struct NameLocal => "local"
2441    struct NameLabel => "label"
2442    struct NameTable => "table"
2443    struct NameType => "type"
2444    struct NameField => "field"
2445    struct NameData => "data"
2446    struct NameElem => "elem"
2447    struct NameTag => "tag"
2448}
2449
2450#[cfg(feature = "component-model")]
2451naming_namespaces! {
2452    struct NameModule => "module"
2453    struct NameInstance => "instance"
2454    struct NameValue => "value"
2455    struct NameComponent => "component"
2456}
2457
2458fn name_map<K>(into: &mut NamingMap<u32, K>, names: NameMap<'_>, name: &str) -> Result<()> {
2459    let mut used = HashSet::new();
2460    for naming in names {
2461        let naming = naming?;
2462        into.index_to_name.insert(
2463            naming.index,
2464            Naming::new(naming.name, naming.index, name, Some(&mut used)),
2465        );
2466    }
2467    Ok(())
2468}