Coverage Report

Created: 2026-10-31 07:49

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