wasmparser/readers/component/
canonicals.rs

1use crate::limits::MAX_WASM_CANONICAL_OPTIONS;
2use crate::prelude::*;
3use crate::{BinaryReader, ComponentValType, FromReader, Result, SectionLimited};
4
5/// Represents options for component functions.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub 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    /// The core function type to lower this component function to.
32    CoreType(u32),
33    /// Use the GC version of the canonical ABI.
34    Gc,
35}
36
37/// Represents a canonical function in a WebAssembly component.
38#[derive(Debug, Clone, Eq, PartialEq)]
39pub enum CanonicalFunction {
40    /// The function lifts a core WebAssembly function to the canonical ABI.
41    Lift {
42        /// The index of the core WebAssembly function to lift.
43        core_func_index: u32,
44        /// The index of the lifted function's type.
45        type_index: u32,
46        /// The canonical options for the function.
47        options: Box<[CanonicalOption]>,
48    },
49    /// The function lowers a canonical ABI function to a core WebAssembly function.
50    Lower {
51        /// The index of the function to lower.
52        func_index: u32,
53        /// The canonical options for the function.
54        options: Box<[CanonicalOption]>,
55    },
56    /// A function which creates a new owned handle to a resource.
57    ResourceNew {
58        /// The type index of the resource that's being created.
59        resource: u32,
60    },
61    /// A function which is used to drop resource handles of the specified type.
62    ResourceDrop {
63        /// The type index of the resource that's being dropped.
64        resource: u32,
65    },
66    /// Same as `ResourceDrop`, but implements the `async` ABI.
67    ResourceDropAsync {
68        /// The type index of the resource that's being dropped.
69        resource: u32,
70    },
71    /// A function which returns the underlying i32-based representation of the
72    /// specified resource.
73    ResourceRep {
74        /// The type index of the resource that's being accessed.
75        resource: u32,
76    },
77    /// A function which spawns a new thread by invoking the shared function.
78    ThreadSpawnRef {
79        /// The index of the function type to spawn.
80        func_ty_index: u32,
81    },
82    /// A function which spawns a new thread by invoking the shared function
83    /// passed as an index into a `funcref` table.
84    ThreadSpawnIndirect {
85        /// The index of the function type to spawn.
86        func_ty_index: u32,
87        /// The index of the table to use for the indirect spawn.
88        table_index: u32,
89    },
90    /// A function which returns the number of threads that can be expected to
91    /// execute concurrently
92    ThreadAvailableParallelism,
93    /// A function which tells the host to enable or disable backpressure for
94    /// the caller's instance.
95    BackpressureSet,
96    /// A function which returns a result to the caller of a lifted export
97    /// function.  This allows the callee to continue executing after returning
98    /// a result.
99    TaskReturn {
100        /// The result type, if any.
101        result: Option<ComponentValType>,
102        /// The canonical options for the function.
103        options: Box<[CanonicalOption]>,
104    },
105    /// A function to acknowledge cancellation of the current task.
106    TaskCancel,
107    /// A `context.get` intrinsic for the `i`th slot of task-local storage.
108    ContextGet(u32),
109    /// A `context.set` intrinsic for the `i`th slot of task-local storage.
110    ContextSet(u32),
111    /// A function which yields control to the host so that other tasks are able
112    /// to make progress, if any.
113    Yield {
114        /// If `true`, indicates the caller instance maybe reentered.
115        async_: bool,
116    },
117    /// A function to drop a specified task which has completed.
118    SubtaskDrop,
119    /// A function to cancel an in-progress task.
120    SubtaskCancel {
121        /// If `false`, block until cancellation completes rather than return
122        /// `BLOCKED`.
123        async_: bool,
124    },
125    /// A function to create a new `stream` handle of the specified type.
126    StreamNew {
127        /// The `stream` type to instantiate.
128        ty: u32,
129    },
130    /// A function to read from a `stream` of the specified type.
131    StreamRead {
132        /// The `stream` type to expect.
133        ty: u32,
134        /// Any options (e.g. string encoding) to use when storing values to
135        /// memory.
136        options: Box<[CanonicalOption]>,
137    },
138    /// A function to write to a `stream` of the specified type.
139    StreamWrite {
140        /// The `stream` type to expect.
141        ty: u32,
142        /// Any options (e.g. string encoding) to use when loading values from
143        /// memory.
144        options: Box<[CanonicalOption]>,
145    },
146    /// A function to cancel an in-progress read from a `stream` of the
147    /// specified type.
148    StreamCancelRead {
149        /// The `stream` type to expect.
150        ty: u32,
151        /// If `false`, block until cancellation completes rather than return
152        /// `BLOCKED`.
153        async_: bool,
154    },
155    /// A function to cancel an in-progress write to a `stream` of the specified
156    /// type.
157    StreamCancelWrite {
158        /// The `stream` type to expect.
159        ty: u32,
160        /// If `false`, block until cancellation completes rather than return
161        /// `BLOCKED`.
162        async_: bool,
163    },
164    /// A function to drop the readable end of a `stream` of the specified
165    /// type.
166    StreamDropReadable {
167        /// The `stream` type to expect.
168        ty: u32,
169    },
170    /// A function to drop the writable end of a `stream` of the specified
171    /// type.
172    StreamDropWritable {
173        /// The `stream` type to expect.
174        ty: u32,
175    },
176    /// A function to create a new `future` handle of the specified type.
177    FutureNew {
178        /// The `future` type to instantiate.
179        ty: u32,
180    },
181    /// A function to read from a `future` of the specified type.
182    FutureRead {
183        /// The `future` type to expect.
184        ty: u32,
185        /// Any options (e.g. string encoding) to use when storing values to
186        /// memory.
187        options: Box<[CanonicalOption]>,
188    },
189    /// A function to write to a `future` of the specified type.
190    FutureWrite {
191        /// The `future` type to expect.
192        ty: u32,
193        /// Any options (e.g. string encoding) to use when loading values from
194        /// memory.
195        options: Box<[CanonicalOption]>,
196    },
197    /// A function to cancel an in-progress read from a `future` of the
198    /// specified type.
199    FutureCancelRead {
200        /// The `future` type to expect.
201        ty: u32,
202        /// If `false`, block until cancellation completes rather than return
203        /// `BLOCKED`.
204        async_: bool,
205    },
206    /// A function to cancel an in-progress write to a `future` of the specified
207    /// type.
208    FutureCancelWrite {
209        /// The `future` type to expect.
210        ty: u32,
211        /// If `false`, block until cancellation completes rather than return
212        /// `BLOCKED`.
213        async_: bool,
214    },
215    /// A function to drop the readable end of a `future` of the specified
216    /// type.
217    FutureDropReadable {
218        /// The `future` type to expect.
219        ty: u32,
220    },
221    /// A function to drop the writable end of a `future` of the specified
222    /// type.
223    FutureDropWritable {
224        /// The `future` type to expect.
225        ty: u32,
226    },
227    /// A function to create a new `error-context` with a specified debug
228    /// message.
229    ErrorContextNew {
230        /// String encoding, memory, etc. to use when loading debug message.
231        options: Box<[CanonicalOption]>,
232    },
233    /// A function to get the debug message for a specified `error-context`.
234    ///
235    /// Note that the debug message might not necessarily match what was passed
236    /// to `error.new`.
237    ErrorContextDebugMessage {
238        /// String encoding, memory, etc. to use when storing debug message.
239        options: Box<[CanonicalOption]>,
240    },
241    /// A function to drop a specified `error-context`.
242    ErrorContextDrop,
243    /// A function to create a new `waitable-set`.
244    WaitableSetNew,
245    /// A function to block on the next item within a `waitable-set`.
246    WaitableSetWait {
247        /// Whether or not the guest can be reentered while calling this
248        /// function.
249        async_: bool,
250        /// Which memory the results of this operation are stored in.
251        memory: u32,
252    },
253    /// A function to check if any items are ready within a `waitable-set`.
254    WaitableSetPoll {
255        /// Whether or not the guest can be reentered while calling this
256        /// function.
257        async_: bool,
258        /// Which memory the results of this operation are stored in.
259        memory: u32,
260    },
261    /// A function to drop a `waitable-set`.
262    WaitableSetDrop,
263    /// A function to add an item to a `waitable-set`.
264    WaitableJoin,
265}
266
267/// A reader for the canonical section of a WebAssembly component.
268pub type ComponentCanonicalSectionReader<'a> = SectionLimited<'a, CanonicalFunction>;
269
270impl<'a> FromReader<'a> for CanonicalFunction {
271    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<CanonicalFunction> {
272        Ok(match reader.read_u8()? {
273            0x00 => match reader.read_u8()? {
274                0x00 => CanonicalFunction::Lift {
275                    core_func_index: reader.read_var_u32()?,
276                    options: read_opts(reader)?,
277                    type_index: reader.read_var_u32()?,
278                },
279                x => return reader.invalid_leading_byte(x, "canonical function lift"),
280            },
281            0x01 => match reader.read_u8()? {
282                0x00 => CanonicalFunction::Lower {
283                    func_index: reader.read_var_u32()?,
284                    options: read_opts(reader)?,
285                },
286                x => return reader.invalid_leading_byte(x, "canonical function lower"),
287            },
288            0x02 => CanonicalFunction::ResourceNew {
289                resource: reader.read()?,
290            },
291            0x03 => CanonicalFunction::ResourceDrop {
292                resource: reader.read()?,
293            },
294            0x07 => CanonicalFunction::ResourceDropAsync {
295                resource: reader.read()?,
296            },
297            0x04 => CanonicalFunction::ResourceRep {
298                resource: reader.read()?,
299            },
300            0x08 => CanonicalFunction::BackpressureSet,
301            0x09 => CanonicalFunction::TaskReturn {
302                result: crate::read_resultlist(reader)?,
303                options: read_opts(reader)?,
304            },
305            0x0a => match reader.read_u8()? {
306                0x7f => CanonicalFunction::ContextGet(reader.read_var_u32()?),
307                x => return reader.invalid_leading_byte(x, "context.get intrinsic type"),
308            },
309            0x0b => match reader.read_u8()? {
310                0x7f => CanonicalFunction::ContextSet(reader.read_var_u32()?),
311                x => return reader.invalid_leading_byte(x, "context.set intrinsic type"),
312            },
313            0x0c => CanonicalFunction::Yield {
314                async_: reader.read()?,
315            },
316            0x0d => CanonicalFunction::SubtaskDrop,
317            0x0e => CanonicalFunction::StreamNew { ty: reader.read()? },
318            0x0f => CanonicalFunction::StreamRead {
319                ty: reader.read()?,
320                options: read_opts(reader)?,
321            },
322            0x10 => CanonicalFunction::StreamWrite {
323                ty: reader.read()?,
324                options: read_opts(reader)?,
325            },
326            0x11 => CanonicalFunction::StreamCancelRead {
327                ty: reader.read()?,
328                async_: reader.read()?,
329            },
330            0x12 => CanonicalFunction::StreamCancelWrite {
331                ty: reader.read()?,
332                async_: reader.read()?,
333            },
334            0x13 => CanonicalFunction::StreamDropReadable { ty: reader.read()? },
335            0x14 => CanonicalFunction::StreamDropWritable { ty: reader.read()? },
336            0x15 => CanonicalFunction::FutureNew { ty: reader.read()? },
337            0x16 => CanonicalFunction::FutureRead {
338                ty: reader.read()?,
339                options: read_opts(reader)?,
340            },
341            0x17 => CanonicalFunction::FutureWrite {
342                ty: reader.read()?,
343                options: read_opts(reader)?,
344            },
345            0x18 => CanonicalFunction::FutureCancelRead {
346                ty: reader.read()?,
347                async_: reader.read()?,
348            },
349            0x19 => CanonicalFunction::FutureCancelWrite {
350                ty: reader.read()?,
351                async_: reader.read()?,
352            },
353            0x1a => CanonicalFunction::FutureDropReadable { ty: reader.read()? },
354            0x1b => CanonicalFunction::FutureDropWritable { ty: reader.read()? },
355            0x1c => CanonicalFunction::ErrorContextNew {
356                options: read_opts(reader)?,
357            },
358            0x1d => CanonicalFunction::ErrorContextDebugMessage {
359                options: read_opts(reader)?,
360            },
361            0x1e => CanonicalFunction::ErrorContextDrop,
362
363            0x1f => CanonicalFunction::WaitableSetNew,
364            0x20 => CanonicalFunction::WaitableSetWait {
365                async_: reader.read()?,
366                memory: reader.read()?,
367            },
368            0x21 => CanonicalFunction::WaitableSetPoll {
369                async_: reader.read()?,
370                memory: reader.read()?,
371            },
372            0x22 => CanonicalFunction::WaitableSetDrop,
373            0x23 => CanonicalFunction::WaitableJoin,
374            0x06 => CanonicalFunction::SubtaskCancel {
375                async_: reader.read()?,
376            },
377            0x05 => CanonicalFunction::TaskCancel,
378            0x40 => CanonicalFunction::ThreadSpawnRef {
379                func_ty_index: reader.read()?,
380            },
381            0x41 => CanonicalFunction::ThreadSpawnIndirect {
382                func_ty_index: reader.read()?,
383                table_index: reader.read()?,
384            },
385            0x42 => CanonicalFunction::ThreadAvailableParallelism,
386            x => return reader.invalid_leading_byte(x, "canonical function"),
387        })
388    }
389}
390
391fn read_opts(reader: &mut BinaryReader<'_>) -> Result<Box<[CanonicalOption]>> {
392    reader
393        .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?
394        .collect::<Result<_>>()
395}
396
397impl<'a> FromReader<'a> for CanonicalOption {
398    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
399        Ok(match reader.read_u8()? {
400            0x00 => CanonicalOption::UTF8,
401            0x01 => CanonicalOption::UTF16,
402            0x02 => CanonicalOption::CompactUTF16,
403            0x03 => CanonicalOption::Memory(reader.read_var_u32()?),
404            0x04 => CanonicalOption::Realloc(reader.read_var_u32()?),
405            0x05 => CanonicalOption::PostReturn(reader.read_var_u32()?),
406            0x06 => CanonicalOption::Async,
407            0x07 => CanonicalOption::Callback(reader.read_var_u32()?),
408            0x08 => CanonicalOption::CoreType(reader.read_var_u32()?),
409            0x09 => CanonicalOption::Gc,
410            x => return reader.invalid_leading_byte(x, "canonical option"),
411        })
412    }
413}