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}