/src/wasm-tools/crates/wasmparser/src/readers/component/canonicals.rs
Line | Count | Source |
1 | | use crate::limits::MAX_WASM_CANONICAL_OPTIONS; |
2 | | use crate::prelude::*; |
3 | | use crate::{BinaryReader, ComponentValType, FromReader, Result, SectionLimited}; |
4 | | |
5 | | /// Represents options for component functions. |
6 | | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
7 | | pub 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)] |
39 | | pub 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 thread. |
278 | | ThreadSwitchTo { |
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 schedule the given thread to be resumed later. |
288 | | ThreadResumeLater, |
289 | | /// A function to suspend the current thread and switch to the given thread. |
290 | | ThreadYieldTo { |
291 | | /// Whether or not the thread can be cancelled while yielding. |
292 | | cancellable: bool, |
293 | | }, |
294 | | } |
295 | | |
296 | | /// A reader for the canonical section of a WebAssembly component. |
297 | | pub type ComponentCanonicalSectionReader<'a> = SectionLimited<'a, CanonicalFunction>; |
298 | | |
299 | | impl<'a> FromReader<'a> for CanonicalFunction { |
300 | 26.0k | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<CanonicalFunction> { |
301 | 26.0k | Ok(match reader.read_u8()? { |
302 | 2.29k | 0x00 => match reader.read_u8()? { |
303 | | 0x00 => CanonicalFunction::Lift { |
304 | 2.29k | core_func_index: reader.read_var_u32()?, |
305 | 2.29k | options: read_opts(reader)?, |
306 | 2.29k | type_index: reader.read_var_u32()?, |
307 | | }, |
308 | 0 | x => return reader.invalid_leading_byte(x, "canonical function lift"), |
309 | | }, |
310 | 3.81k | 0x01 => match reader.read_u8()? { |
311 | | 0x00 => CanonicalFunction::Lower { |
312 | 3.81k | func_index: reader.read_var_u32()?, |
313 | 3.81k | options: read_opts(reader)?, |
314 | | }, |
315 | 0 | x => return reader.invalid_leading_byte(x, "canonical function lower"), |
316 | | }, |
317 | | 0x02 => CanonicalFunction::ResourceNew { |
318 | 170 | resource: reader.read()?, |
319 | | }, |
320 | | 0x03 => CanonicalFunction::ResourceDrop { |
321 | 720 | resource: reader.read()?, |
322 | | }, |
323 | | 0x07 => CanonicalFunction::ResourceDropAsync { |
324 | 0 | resource: reader.read()?, |
325 | | }, |
326 | | 0x04 => CanonicalFunction::ResourceRep { |
327 | 170 | resource: reader.read()?, |
328 | | }, |
329 | 1.25k | 0x24 => CanonicalFunction::BackpressureInc, |
330 | 1.25k | 0x25 => CanonicalFunction::BackpressureDec, |
331 | | 0x09 => CanonicalFunction::TaskReturn { |
332 | 470 | result: crate::read_resultlist(reader)?, |
333 | 470 | options: read_opts(reader)?, |
334 | | }, |
335 | 1.25k | 0x0a => match reader.read_u8()? { |
336 | 1.25k | 0x7f => CanonicalFunction::ContextGet(reader.read_var_u32()?), |
337 | 0 | x => return reader.invalid_leading_byte(x, "context.get intrinsic type"), |
338 | | }, |
339 | 1.25k | 0x0b => match reader.read_u8()? { |
340 | 1.25k | 0x7f => CanonicalFunction::ContextSet(reader.read_var_u32()?), |
341 | 0 | x => return reader.invalid_leading_byte(x, "context.set intrinsic type"), |
342 | | }, |
343 | | 0x0c => CanonicalFunction::ThreadYield { |
344 | 1.25k | cancellable: reader.read()?, |
345 | | }, |
346 | 1.25k | 0x0d => CanonicalFunction::SubtaskDrop, |
347 | 244 | 0x0e => CanonicalFunction::StreamNew { ty: reader.read()? }, |
348 | | 0x0f => CanonicalFunction::StreamRead { |
349 | 244 | ty: reader.read()?, |
350 | 244 | options: read_opts(reader)?, |
351 | | }, |
352 | | 0x10 => CanonicalFunction::StreamWrite { |
353 | 244 | ty: reader.read()?, |
354 | 244 | options: read_opts(reader)?, |
355 | | }, |
356 | | 0x11 => CanonicalFunction::StreamCancelRead { |
357 | 244 | ty: reader.read()?, |
358 | 244 | async_: reader.read()?, |
359 | | }, |
360 | | 0x12 => CanonicalFunction::StreamCancelWrite { |
361 | 244 | ty: reader.read()?, |
362 | 244 | async_: reader.read()?, |
363 | | }, |
364 | 244 | 0x13 => CanonicalFunction::StreamDropReadable { ty: reader.read()? }, |
365 | 244 | 0x14 => CanonicalFunction::StreamDropWritable { ty: reader.read()? }, |
366 | 46 | 0x15 => CanonicalFunction::FutureNew { ty: reader.read()? }, |
367 | | 0x16 => CanonicalFunction::FutureRead { |
368 | 46 | ty: reader.read()?, |
369 | 46 | options: read_opts(reader)?, |
370 | | }, |
371 | | 0x17 => CanonicalFunction::FutureWrite { |
372 | 46 | ty: reader.read()?, |
373 | 46 | options: read_opts(reader)?, |
374 | | }, |
375 | | 0x18 => CanonicalFunction::FutureCancelRead { |
376 | 46 | ty: reader.read()?, |
377 | 46 | async_: reader.read()?, |
378 | | }, |
379 | | 0x19 => CanonicalFunction::FutureCancelWrite { |
380 | 46 | ty: reader.read()?, |
381 | 46 | async_: reader.read()?, |
382 | | }, |
383 | 46 | 0x1a => CanonicalFunction::FutureDropReadable { ty: reader.read()? }, |
384 | 46 | 0x1b => CanonicalFunction::FutureDropWritable { ty: reader.read()? }, |
385 | | 0x1c => CanonicalFunction::ErrorContextNew { |
386 | 0 | options: read_opts(reader)?, |
387 | | }, |
388 | | 0x1d => CanonicalFunction::ErrorContextDebugMessage { |
389 | 0 | options: read_opts(reader)?, |
390 | | }, |
391 | 0 | 0x1e => CanonicalFunction::ErrorContextDrop, |
392 | | |
393 | 1.25k | 0x1f => CanonicalFunction::WaitableSetNew, |
394 | | 0x20 => CanonicalFunction::WaitableSetWait { |
395 | 1.25k | cancellable: reader.read()?, |
396 | 1.25k | memory: reader.read()?, |
397 | | }, |
398 | | 0x21 => CanonicalFunction::WaitableSetPoll { |
399 | 1.25k | cancellable: reader.read()?, |
400 | 1.25k | memory: reader.read()?, |
401 | | }, |
402 | 1.25k | 0x22 => CanonicalFunction::WaitableSetDrop, |
403 | 1.25k | 0x23 => CanonicalFunction::WaitableJoin, |
404 | 0 | 0x26 => CanonicalFunction::ThreadIndex, |
405 | | 0x27 => CanonicalFunction::ThreadNewIndirect { |
406 | 0 | func_ty_index: reader.read()?, |
407 | 0 | table_index: reader.read()?, |
408 | | }, |
409 | | 0x28 => CanonicalFunction::ThreadSwitchTo { |
410 | 0 | cancellable: reader.read()?, |
411 | | }, |
412 | | 0x29 => CanonicalFunction::ThreadSuspend { |
413 | 0 | cancellable: reader.read()?, |
414 | | }, |
415 | 0 | 0x2a => CanonicalFunction::ThreadResumeLater, |
416 | | 0x2b => CanonicalFunction::ThreadYieldTo { |
417 | 0 | cancellable: reader.read()?, |
418 | | }, |
419 | | 0x06 => CanonicalFunction::SubtaskCancel { |
420 | 1.25k | async_: reader.read()?, |
421 | | }, |
422 | 1.25k | 0x05 => CanonicalFunction::TaskCancel, |
423 | | 0x40 => CanonicalFunction::ThreadSpawnRef { |
424 | 0 | func_ty_index: reader.read()?, |
425 | | }, |
426 | | 0x41 => CanonicalFunction::ThreadSpawnIndirect { |
427 | 0 | func_ty_index: reader.read()?, |
428 | 0 | table_index: reader.read()?, |
429 | | }, |
430 | 0 | 0x42 => CanonicalFunction::ThreadAvailableParallelism, |
431 | 0 | x => return reader.invalid_leading_byte(x, "canonical function"), |
432 | | }) |
433 | 26.0k | } |
434 | | } |
435 | | |
436 | 7.16k | fn read_opts(reader: &mut BinaryReader<'_>) -> Result<Box<[CanonicalOption]>> { |
437 | 7.16k | reader |
438 | 7.16k | .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? |
439 | 7.16k | .collect::<Result<_>>() |
440 | 7.16k | } |
441 | | |
442 | | impl<'a> FromReader<'a> for CanonicalOption { |
443 | 5.60k | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { |
444 | 5.60k | Ok(match reader.read_u8()? { |
445 | 294 | 0x00 => CanonicalOption::UTF8, |
446 | 0 | 0x01 => CanonicalOption::UTF16, |
447 | 0 | 0x02 => CanonicalOption::CompactUTF16, |
448 | 1.84k | 0x03 => CanonicalOption::Memory(reader.read_var_u32()?), |
449 | 258 | 0x04 => CanonicalOption::Realloc(reader.read_var_u32()?), |
450 | 1.82k | 0x05 => CanonicalOption::PostReturn(reader.read_var_u32()?), |
451 | 1.03k | 0x06 => CanonicalOption::Async, |
452 | 344 | 0x07 => CanonicalOption::Callback(reader.read_var_u32()?), |
453 | 0 | 0x08 => CanonicalOption::CoreType(reader.read_var_u32()?), |
454 | 0 | 0x09 => CanonicalOption::Gc, |
455 | 0 | x => return reader.invalid_leading_byte(x, "canonical option"), |
456 | | }) |
457 | 5.60k | } |
458 | | } |