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