Coverage Report

Created: 2026-10-24 07:23

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