Skip to main content

wasmparser/readers/component/
canonicals.rs

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