Coverage Report

Created: 2025-01-09 07:53

/src/wasm-tools/crates/wasmparser/src/readers/component/canonicals.rs
Line
Count
Source (jump to first uncovered line)
1
use crate::limits::MAX_WASM_CANONICAL_OPTIONS;
2
use crate::prelude::*;
3
use crate::{BinaryReader, FromReader, Result, SectionLimited};
4
5
/// Represents options for component functions.
6
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7
pub enum CanonicalOption {
8
    /// The string types in the function signature are UTF-8 encoded.
9
    UTF8,
10
    /// The string types in the function signature are UTF-16 encoded.
11
    UTF16,
12
    /// The string types in the function signature are compact UTF-16 encoded.
13
    CompactUTF16,
14
    /// The memory to use if the lifting or lowering of a function requires memory access.
15
    ///
16
    /// The value is an index to a core memory.
17
    Memory(u32),
18
    /// The realloc function to use if the lifting or lowering of a function requires memory
19
    /// allocation.
20
    ///
21
    /// The value is an index to a core function of type `(func (param i32 i32 i32 i32) (result i32))`.
22
    Realloc(u32),
23
    /// The post-return function to use if the lifting of a function requires
24
    /// cleanup after the function returns.
25
    PostReturn(u32),
26
    /// Indicates that specified function should be lifted or lowered using the `async` ABI.
27
    Async,
28
    /// The function to use if the async lifting of a function should receive task/stream/future progress events
29
    /// using a callback.
30
    Callback(u32),
31
}
32
33
/// Represents a canonical function in a WebAssembly component.
34
#[derive(Debug, Clone, Eq, PartialEq)]
35
pub enum CanonicalFunction {
36
    /// The function lifts a core WebAssembly function to the canonical ABI.
37
    Lift {
38
        /// The index of the core WebAssembly function to lift.
39
        core_func_index: u32,
40
        /// The index of the lifted function's type.
41
        type_index: u32,
42
        /// The canonical options for the function.
43
        options: Box<[CanonicalOption]>,
44
    },
45
    /// The function lowers a canonical ABI function to a core WebAssembly function.
46
    Lower {
47
        /// The index of the function to lower.
48
        func_index: u32,
49
        /// The canonical options for the function.
50
        options: Box<[CanonicalOption]>,
51
    },
52
    /// A function which creates a new owned handle to a resource.
53
    ResourceNew {
54
        /// The type index of the resource that's being created.
55
        resource: u32,
56
    },
57
    /// A function which is used to drop resource handles of the specified type.
58
    ResourceDrop {
59
        /// The type index of the resource that's being dropped.
60
        resource: u32,
61
    },
62
    /// A function which returns the underlying i32-based representation of the
63
    /// specified resource.
64
    ResourceRep {
65
        /// The type index of the resource that's being accessed.
66
        resource: u32,
67
    },
68
    /// A function which spawns a new thread by invoking the shared function.
69
    ThreadSpawn {
70
        /// The index of the function to spawn.
71
        func_ty_index: u32,
72
    },
73
    /// A function which returns the number of threads that can be expected to
74
    /// execute concurrently
75
    ThreadHwConcurrency,
76
    /// A function which tells the host to enable or disable backpressure for
77
    /// the caller's instance.
78
    TaskBackpressure,
79
    /// A function which returns a result to the caller of a lifted export
80
    /// function.  This allows the callee to continue executing after returning
81
    /// a result.
82
    TaskReturn {
83
        /// Core function type whose parameters represent the flattened
84
        /// representation of the component-level results to be returned by the
85
        /// currently executing task.
86
        type_index: u32,
87
    },
88
    /// A function which waits for at least one outstanding async
89
    /// task/stream/future to make progress, returning the first such event.
90
    TaskWait {
91
        /// If `true`, indicates the caller instance maybe reentered.
92
        async_: bool,
93
        /// Memory to use when storing the event.
94
        memory: u32,
95
    },
96
    /// A function which checks whether any outstanding async task/stream/future
97
    /// has made progress.  Unlike `task.wait`, this does not block and may
98
    /// return nothing if no such event has occurred.
99
    TaskPoll {
100
        /// If `true`, indicates the caller instance maybe reentered.
101
        async_: bool,
102
        /// Memory to use when storing the event, if any.
103
        memory: u32,
104
    },
105
    /// A function which yields control to the host so that other tasks are able
106
    /// to make progress, if any.
107
    TaskYield {
108
        /// If `true`, indicates the caller instance maybe reentered.
109
        async_: bool,
110
    },
111
    /// A function to drop a specified task which has completed.
112
    SubtaskDrop,
113
    /// A function to create a new `stream` handle of the specified type.
114
    StreamNew {
115
        /// The `stream` type to instantiate.
116
        ty: u32,
117
    },
118
    /// A function to read from a `stream` of the specified type.
119
    StreamRead {
120
        /// The `stream` type to expect.
121
        ty: u32,
122
        /// Any options (e.g. string encoding) to use when storing values to
123
        /// memory.
124
        options: Box<[CanonicalOption]>,
125
    },
126
    /// A function to write to a `stream` of the specified type.
127
    StreamWrite {
128
        /// The `stream` type to expect.
129
        ty: u32,
130
        /// Any options (e.g. string encoding) to use when loading values from
131
        /// memory.
132
        options: Box<[CanonicalOption]>,
133
    },
134
    /// A function to cancel an in-progress read from a `stream` of the
135
    /// specified type.
136
    StreamCancelRead {
137
        /// The `stream` type to expect.
138
        ty: u32,
139
        /// If `false`, block until cancellation completes rather than return
140
        /// `BLOCKED`.
141
        async_: bool,
142
    },
143
    /// A function to cancel an in-progress write to a `stream` of the specified
144
    /// type.
145
    StreamCancelWrite {
146
        /// The `stream` type to expect.
147
        ty: u32,
148
        /// If `false`, block until cancellation completes rather than return
149
        /// `BLOCKED`.
150
        async_: bool,
151
    },
152
    /// A function to close the readable end of a `stream` of the specified
153
    /// type.
154
    StreamCloseReadable {
155
        /// The `stream` type to expect.
156
        ty: u32,
157
    },
158
    /// A function to close the writable end of a `stream` of the specified
159
    /// type.
160
    StreamCloseWritable {
161
        /// The `stream` type to expect.
162
        ty: u32,
163
    },
164
    /// A function to create a new `future` handle of the specified type.
165
    FutureNew {
166
        /// The `future` type to instantiate.
167
        ty: u32,
168
    },
169
    /// A function to read from a `future` of the specified type.
170
    FutureRead {
171
        /// The `future` type to expect.
172
        ty: u32,
173
        /// Any options (e.g. string encoding) to use when storing values to
174
        /// memory.
175
        options: Box<[CanonicalOption]>,
176
    },
177
    /// A function to write to a `future` of the specified type.
178
    FutureWrite {
179
        /// The `future` type to expect.
180
        ty: u32,
181
        /// Any options (e.g. string encoding) to use when loading values from
182
        /// memory.
183
        options: Box<[CanonicalOption]>,
184
    },
185
    /// A function to cancel an in-progress read from a `future` of the
186
    /// specified type.
187
    FutureCancelRead {
188
        /// The `future` type to expect.
189
        ty: u32,
190
        /// If `false`, block until cancellation completes rather than return
191
        /// `BLOCKED`.
192
        async_: bool,
193
    },
194
    /// A function to cancel an in-progress write to a `future` of the specified
195
    /// type.
196
    FutureCancelWrite {
197
        /// The `future` type to expect.
198
        ty: u32,
199
        /// If `false`, block until cancellation completes rather than return
200
        /// `BLOCKED`.
201
        async_: bool,
202
    },
203
    /// A function to close the readable end of a `future` of the specified
204
    /// type.
205
    FutureCloseReadable {
206
        /// The `future` type to expect.
207
        ty: u32,
208
    },
209
    /// A function to close the writable end of a `future` of the specified
210
    /// type.
211
    FutureCloseWritable {
212
        /// The `future` type to expect.
213
        ty: u32,
214
    },
215
    /// A function to create a new `error-context` with a specified debug
216
    /// message.
217
    ErrorContextNew {
218
        /// String encoding, memory, etc. to use when loading debug message.
219
        options: Box<[CanonicalOption]>,
220
    },
221
    /// A function to get the debug message for a specified `error-context`.
222
    ///
223
    /// Note that the debug message might not necessarily match what was passed
224
    /// to `error.new`.
225
    ErrorContextDebugMessage {
226
        /// String encoding, memory, etc. to use when storing debug message.
227
        options: Box<[CanonicalOption]>,
228
    },
229
    /// A function to drop a specified `error-context`.
230
    ErrorContextDrop,
231
}
232
233
/// A reader for the canonical section of a WebAssembly component.
234
pub type ComponentCanonicalSectionReader<'a> = SectionLimited<'a, CanonicalFunction>;
235
236
impl<'a> FromReader<'a> for CanonicalFunction {
237
97.6k
    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<CanonicalFunction> {
238
97.6k
        Ok(match reader.read_u8()? {
239
42.3k
            0x00 => match reader.read_u8()? {
240
                0x00 => {
241
42.3k
                    let core_func_index = reader.read_var_u32()?;
242
42.3k
                    let options = reader
243
42.3k
                        .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?
244
42.3k
                        .collect::<Result<_>>()?;
245
42.3k
                    let type_index = reader.read_var_u32()?;
246
42.3k
                    CanonicalFunction::Lift {
247
42.3k
                        core_func_index,
248
42.3k
                        options,
249
42.3k
                        type_index,
250
42.3k
                    }
251
                }
252
0
                x => return reader.invalid_leading_byte(x, "canonical function lift"),
253
            },
254
35.2k
            0x01 => match reader.read_u8()? {
255
                0x00 => CanonicalFunction::Lower {
256
35.2k
                    func_index: reader.read_var_u32()?,
257
35.2k
                    options: reader
258
35.2k
                        .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?
259
35.2k
                        .collect::<Result<_>>()?,
260
                },
261
0
                x => return reader.invalid_leading_byte(x, "canonical function lower"),
262
            },
263
            0x02 => CanonicalFunction::ResourceNew {
264
5.28k
                resource: reader.read()?,
265
            },
266
            0x03 => CanonicalFunction::ResourceDrop {
267
9.44k
                resource: reader.read()?,
268
            },
269
            0x04 => CanonicalFunction::ResourceRep {
270
5.28k
                resource: reader.read()?,
271
            },
272
            0x05 => CanonicalFunction::ThreadSpawn {
273
0
                func_ty_index: reader.read()?,
274
            },
275
0
            0x06 => CanonicalFunction::ThreadHwConcurrency,
276
0
            0x08 => CanonicalFunction::TaskBackpressure,
277
            0x09 => CanonicalFunction::TaskReturn {
278
0
                type_index: reader.read()?,
279
            },
280
            0x0a => CanonicalFunction::TaskWait {
281
0
                async_: reader.read()?,
282
0
                memory: reader.read()?,
283
            },
284
            0x0b => CanonicalFunction::TaskPoll {
285
0
                async_: reader.read()?,
286
0
                memory: reader.read()?,
287
            },
288
            0x0c => CanonicalFunction::TaskYield {
289
0
                async_: reader.read()?,
290
            },
291
0
            0x0d => CanonicalFunction::SubtaskDrop,
292
0
            0x0e => CanonicalFunction::StreamNew { ty: reader.read()? },
293
            0x0f => CanonicalFunction::StreamRead {
294
0
                ty: reader.read()?,
295
0
                options: reader
296
0
                    .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?
297
0
                    .collect::<Result<_>>()?,
298
            },
299
            0x10 => CanonicalFunction::StreamWrite {
300
0
                ty: reader.read()?,
301
0
                options: reader
302
0
                    .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?
303
0
                    .collect::<Result<_>>()?,
304
            },
305
            0x11 => CanonicalFunction::StreamCancelRead {
306
0
                ty: reader.read()?,
307
0
                async_: reader.read()?,
308
            },
309
            0x12 => CanonicalFunction::StreamCancelWrite {
310
0
                ty: reader.read()?,
311
0
                async_: reader.read()?,
312
            },
313
0
            0x13 => CanonicalFunction::StreamCloseReadable { ty: reader.read()? },
314
0
            0x14 => CanonicalFunction::StreamCloseWritable { ty: reader.read()? },
315
0
            0x15 => CanonicalFunction::FutureNew { ty: reader.read()? },
316
            0x16 => CanonicalFunction::FutureRead {
317
0
                ty: reader.read()?,
318
0
                options: reader
319
0
                    .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?
320
0
                    .collect::<Result<_>>()?,
321
            },
322
            0x17 => CanonicalFunction::FutureWrite {
323
0
                ty: reader.read()?,
324
0
                options: reader
325
0
                    .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?
326
0
                    .collect::<Result<_>>()?,
327
            },
328
            0x18 => CanonicalFunction::FutureCancelRead {
329
0
                ty: reader.read()?,
330
0
                async_: reader.read()?,
331
            },
332
            0x19 => CanonicalFunction::FutureCancelWrite {
333
0
                ty: reader.read()?,
334
0
                async_: reader.read()?,
335
            },
336
0
            0x1a => CanonicalFunction::FutureCloseReadable { ty: reader.read()? },
337
0
            0x1b => CanonicalFunction::FutureCloseWritable { ty: reader.read()? },
338
            0x1c => CanonicalFunction::ErrorContextNew {
339
0
                options: reader
340
0
                    .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?
341
0
                    .collect::<Result<_>>()?,
342
            },
343
            0x1d => CanonicalFunction::ErrorContextDebugMessage {
344
0
                options: reader
345
0
                    .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?
346
0
                    .collect::<Result<_>>()?,
347
            },
348
0
            0x1e => CanonicalFunction::ErrorContextDrop,
349
0
            x => return reader.invalid_leading_byte(x, "canonical function"),
350
        })
351
97.6k
    }
352
}
353
354
impl<'a> FromReader<'a> for CanonicalOption {
355
74.8k
    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
356
74.8k
        Ok(match reader.read_u8()? {
357
1.16k
            0x00 => CanonicalOption::UTF8,
358
0
            0x01 => CanonicalOption::UTF16,
359
0
            0x02 => CanonicalOption::CompactUTF16,
360
12.7k
            0x03 => CanonicalOption::Memory(reader.read_var_u32()?),
361
1.66k
            0x04 => CanonicalOption::Realloc(reader.read_var_u32()?),
362
32.6k
            0x05 => CanonicalOption::PostReturn(reader.read_var_u32()?),
363
18.6k
            0x06 => CanonicalOption::Async,
364
7.92k
            0x07 => CanonicalOption::Callback(reader.read_var_u32()?),
365
0
            x => return reader.invalid_leading_byte(x, "canonical option"),
366
        })
367
74.8k
    }
368
}