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}