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}