Coverage Report

Created: 2026-08-15 07:39

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