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