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 tells the host to enable backpressure by incrementing
97    /// the component's counter by 1.
98    BackpressureInc,
99    /// A function which tells the host to disable backpressure by decrementing
100    /// the component's counter by 1.
101    BackpressureDec,
102    /// A function which returns a result to the caller of a lifted export
103    /// function.  This allows the callee to continue executing after returning
104    /// a result.
105    TaskReturn {
106        /// The result type, if any.
107        result: Option<ComponentValType>,
108        /// The canonical options for the function.
109        options: Box<[CanonicalOption]>,
110    },
111    /// A function to acknowledge cancellation of the current task.
112    TaskCancel,
113    /// A `context.get` intrinsic for the `i`th slot of task-local storage.
114    ContextGet(u32),
115    /// A `context.set` intrinsic for the `i`th slot of task-local storage.
116    ContextSet(u32),
117    /// A function which yields control to the host so that other tasks are able
118    /// to make progress, if any.
119    ThreadYield {
120        /// If `true`, indicates the caller instance maybe reentered.
121        cancellable: bool,
122    },
123    /// A function to drop a specified task which has completed.
124    SubtaskDrop,
125    /// A function to cancel an in-progress task.
126    SubtaskCancel {
127        /// If `false`, block until cancellation completes rather than return
128        /// `BLOCKED`.
129        async_: bool,
130    },
131    /// A function to create a new `stream` handle of the specified type.
132    StreamNew {
133        /// The `stream` type to instantiate.
134        ty: u32,
135    },
136    /// A function to read from a `stream` of the specified type.
137    StreamRead {
138        /// The `stream` type to expect.
139        ty: u32,
140        /// Any options (e.g. string encoding) to use when storing values to
141        /// memory.
142        options: Box<[CanonicalOption]>,
143    },
144    /// A function to write to a `stream` of the specified type.
145    StreamWrite {
146        /// The `stream` type to expect.
147        ty: u32,
148        /// Any options (e.g. string encoding) to use when loading values from
149        /// memory.
150        options: Box<[CanonicalOption]>,
151    },
152    /// A function to cancel an in-progress read from a `stream` of the
153    /// specified type.
154    StreamCancelRead {
155        /// The `stream` type to expect.
156        ty: u32,
157        /// If `false`, block until cancellation completes rather than return
158        /// `BLOCKED`.
159        async_: bool,
160    },
161    /// A function to cancel an in-progress write to a `stream` of the specified
162    /// type.
163    StreamCancelWrite {
164        /// The `stream` type to expect.
165        ty: u32,
166        /// If `false`, block until cancellation completes rather than return
167        /// `BLOCKED`.
168        async_: bool,
169    },
170    /// A function to drop the readable end of a `stream` of the specified
171    /// type.
172    StreamDropReadable {
173        /// The `stream` type to expect.
174        ty: u32,
175    },
176    /// A function to drop the writable end of a `stream` of the specified
177    /// type.
178    StreamDropWritable {
179        /// The `stream` type to expect.
180        ty: u32,
181    },
182    /// A function to create a new `future` handle of the specified type.
183    FutureNew {
184        /// The `future` type to instantiate.
185        ty: u32,
186    },
187    /// A function to read from a `future` of the specified type.
188    FutureRead {
189        /// The `future` type to expect.
190        ty: u32,
191        /// Any options (e.g. string encoding) to use when storing values to
192        /// memory.
193        options: Box<[CanonicalOption]>,
194    },
195    /// A function to write to a `future` of the specified type.
196    FutureWrite {
197        /// The `future` type to expect.
198        ty: u32,
199        /// Any options (e.g. string encoding) to use when loading values from
200        /// memory.
201        options: Box<[CanonicalOption]>,
202    },
203    /// A function to cancel an in-progress read from a `future` of the
204    /// specified type.
205    FutureCancelRead {
206        /// The `future` type to expect.
207        ty: u32,
208        /// If `false`, block until cancellation completes rather than return
209        /// `BLOCKED`.
210        async_: bool,
211    },
212    /// A function to cancel an in-progress write to a `future` of the specified
213    /// type.
214    FutureCancelWrite {
215        /// The `future` type to expect.
216        ty: u32,
217        /// If `false`, block until cancellation completes rather than return
218        /// `BLOCKED`.
219        async_: bool,
220    },
221    /// A function to drop the readable end of a `future` of the specified
222    /// type.
223    FutureDropReadable {
224        /// The `future` type to expect.
225        ty: u32,
226    },
227    /// A function to drop the writable end of a `future` of the specified
228    /// type.
229    FutureDropWritable {
230        /// The `future` type to expect.
231        ty: u32,
232    },
233    /// A function to create a new `error-context` with a specified debug
234    /// message.
235    ErrorContextNew {
236        /// String encoding, memory, etc. to use when loading debug message.
237        options: Box<[CanonicalOption]>,
238    },
239    /// A function to get the debug message for a specified `error-context`.
240    ///
241    /// Note that the debug message might not necessarily match what was passed
242    /// to `error.new`.
243    ErrorContextDebugMessage {
244        /// String encoding, memory, etc. to use when storing debug message.
245        options: Box<[CanonicalOption]>,
246    },
247    /// A function to drop a specified `error-context`.
248    ErrorContextDrop,
249    /// A function to create a new `waitable-set`.
250    WaitableSetNew,
251    /// A function to block on the next item within a `waitable-set`.
252    WaitableSetWait {
253        /// Whether or not the guest can be reentered while calling this
254        /// function.
255        cancellable: bool,
256        /// Which memory the results of this operation are stored in.
257        memory: u32,
258    },
259    /// A function to check if any items are ready within a `waitable-set`.
260    WaitableSetPoll {
261        /// Whether or not the guest can be reentered while calling this
262        /// function.
263        cancellable: bool,
264        /// Which memory the results of this operation are stored in.
265        memory: u32,
266    },
267    /// A function to drop a `waitable-set`.
268    WaitableSetDrop,
269    /// A function to add an item to a `waitable-set`.
270    WaitableJoin,
271    /// A function to get the index of the current thread.
272    ThreadIndex,
273    /// A function to create a new thread with the specified start function.
274    ThreadNewIndirect {
275        /// The index of the function type to use as the start function.
276        func_ty_index: u32,
277        /// The index of the table to use.
278        table_index: u32,
279    },
280    /// A function to suspend the current thread and switch to the given thread.
281    ThreadSwitchTo {
282        /// Whether or not the thread can be cancelled while awaiting resumption.
283        cancellable: bool,
284    },
285    /// A function to suspend the current thread, immediately yielding to any transitive async-lowered calling component.
286    ThreadSuspend {
287        /// Whether or not the thread can be cancelled while suspended.
288        cancellable: bool,
289    },
290    /// A function to schedule the given thread to be resumed later.
291    ThreadResumeLater,
292    /// A function to suspend the current thread and switch to the given thread.
293    ThreadYieldTo {
294        /// Whether or not the thread can be cancelled while yielding.
295        cancellable: bool,
296    },
297}
298
299/// A reader for the canonical section of a WebAssembly component.
300pub type ComponentCanonicalSectionReader<'a> = SectionLimited<'a, CanonicalFunction>;
301
302impl<'a> FromReader<'a> for CanonicalFunction {
303    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<CanonicalFunction> {
304        Ok(match reader.read_u8()? {
305            0x00 => match reader.read_u8()? {
306                0x00 => CanonicalFunction::Lift {
307                    core_func_index: reader.read_var_u32()?,
308                    options: read_opts(reader)?,
309                    type_index: reader.read_var_u32()?,
310                },
311                x => return reader.invalid_leading_byte(x, "canonical function lift"),
312            },
313            0x01 => match reader.read_u8()? {
314                0x00 => CanonicalFunction::Lower {
315                    func_index: reader.read_var_u32()?,
316                    options: read_opts(reader)?,
317                },
318                x => return reader.invalid_leading_byte(x, "canonical function lower"),
319            },
320            0x02 => CanonicalFunction::ResourceNew {
321                resource: reader.read()?,
322            },
323            0x03 => CanonicalFunction::ResourceDrop {
324                resource: reader.read()?,
325            },
326            0x07 => CanonicalFunction::ResourceDropAsync {
327                resource: reader.read()?,
328            },
329            0x04 => CanonicalFunction::ResourceRep {
330                resource: reader.read()?,
331            },
332            0x08 => CanonicalFunction::BackpressureSet,
333            0x24 => CanonicalFunction::BackpressureInc,
334            0x25 => CanonicalFunction::BackpressureDec,
335            0x09 => CanonicalFunction::TaskReturn {
336                result: crate::read_resultlist(reader)?,
337                options: read_opts(reader)?,
338            },
339            0x0a => match reader.read_u8()? {
340                0x7f => CanonicalFunction::ContextGet(reader.read_var_u32()?),
341                x => return reader.invalid_leading_byte(x, "context.get intrinsic type"),
342            },
343            0x0b => match reader.read_u8()? {
344                0x7f => CanonicalFunction::ContextSet(reader.read_var_u32()?),
345                x => return reader.invalid_leading_byte(x, "context.set intrinsic type"),
346            },
347            0x0c => CanonicalFunction::ThreadYield {
348                cancellable: reader.read()?,
349            },
350            0x0d => CanonicalFunction::SubtaskDrop,
351            0x0e => CanonicalFunction::StreamNew { ty: reader.read()? },
352            0x0f => CanonicalFunction::StreamRead {
353                ty: reader.read()?,
354                options: read_opts(reader)?,
355            },
356            0x10 => CanonicalFunction::StreamWrite {
357                ty: reader.read()?,
358                options: read_opts(reader)?,
359            },
360            0x11 => CanonicalFunction::StreamCancelRead {
361                ty: reader.read()?,
362                async_: reader.read()?,
363            },
364            0x12 => CanonicalFunction::StreamCancelWrite {
365                ty: reader.read()?,
366                async_: reader.read()?,
367            },
368            0x13 => CanonicalFunction::StreamDropReadable { ty: reader.read()? },
369            0x14 => CanonicalFunction::StreamDropWritable { ty: reader.read()? },
370            0x15 => CanonicalFunction::FutureNew { ty: reader.read()? },
371            0x16 => CanonicalFunction::FutureRead {
372                ty: reader.read()?,
373                options: read_opts(reader)?,
374            },
375            0x17 => CanonicalFunction::FutureWrite {
376                ty: reader.read()?,
377                options: read_opts(reader)?,
378            },
379            0x18 => CanonicalFunction::FutureCancelRead {
380                ty: reader.read()?,
381                async_: reader.read()?,
382            },
383            0x19 => CanonicalFunction::FutureCancelWrite {
384                ty: reader.read()?,
385                async_: reader.read()?,
386            },
387            0x1a => CanonicalFunction::FutureDropReadable { ty: reader.read()? },
388            0x1b => CanonicalFunction::FutureDropWritable { ty: reader.read()? },
389            0x1c => CanonicalFunction::ErrorContextNew {
390                options: read_opts(reader)?,
391            },
392            0x1d => CanonicalFunction::ErrorContextDebugMessage {
393                options: read_opts(reader)?,
394            },
395            0x1e => CanonicalFunction::ErrorContextDrop,
396
397            0x1f => CanonicalFunction::WaitableSetNew,
398            0x20 => CanonicalFunction::WaitableSetWait {
399                cancellable: reader.read()?,
400                memory: reader.read()?,
401            },
402            0x21 => CanonicalFunction::WaitableSetPoll {
403                cancellable: reader.read()?,
404                memory: reader.read()?,
405            },
406            0x22 => CanonicalFunction::WaitableSetDrop,
407            0x23 => CanonicalFunction::WaitableJoin,
408            0x26 => CanonicalFunction::ThreadIndex,
409            0x27 => CanonicalFunction::ThreadNewIndirect {
410                func_ty_index: reader.read()?,
411                table_index: reader.read()?,
412            },
413            0x28 => CanonicalFunction::ThreadSwitchTo {
414                cancellable: reader.read()?,
415            },
416            0x29 => CanonicalFunction::ThreadSuspend {
417                cancellable: reader.read()?,
418            },
419            0x2a => CanonicalFunction::ThreadResumeLater,
420            0x2b => CanonicalFunction::ThreadYieldTo {
421                cancellable: reader.read()?,
422            },
423            0x06 => CanonicalFunction::SubtaskCancel {
424                async_: reader.read()?,
425            },
426            0x05 => CanonicalFunction::TaskCancel,
427            0x40 => CanonicalFunction::ThreadSpawnRef {
428                func_ty_index: reader.read()?,
429            },
430            0x41 => CanonicalFunction::ThreadSpawnIndirect {
431                func_ty_index: reader.read()?,
432                table_index: reader.read()?,
433            },
434            0x42 => CanonicalFunction::ThreadAvailableParallelism,
435            x => return reader.invalid_leading_byte(x, "canonical function"),
436        })
437    }
438}
439
440fn read_opts(reader: &mut BinaryReader<'_>) -> Result<Box<[CanonicalOption]>> {
441    reader
442        .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?
443        .collect::<Result<_>>()
444}
445
446impl<'a> FromReader<'a> for CanonicalOption {
447    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
448        Ok(match reader.read_u8()? {
449            0x00 => CanonicalOption::UTF8,
450            0x01 => CanonicalOption::UTF16,
451            0x02 => CanonicalOption::CompactUTF16,
452            0x03 => CanonicalOption::Memory(reader.read_var_u32()?),
453            0x04 => CanonicalOption::Realloc(reader.read_var_u32()?),
454            0x05 => CanonicalOption::PostReturn(reader.read_var_u32()?),
455            0x06 => CanonicalOption::Async,
456            0x07 => CanonicalOption::Callback(reader.read_var_u32()?),
457            0x08 => CanonicalOption::CoreType(reader.read_var_u32()?),
458            0x09 => CanonicalOption::Gc,
459            x => return reader.invalid_leading_byte(x, "canonical option"),
460        })
461    }
462}