/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 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. |
300 | | pub type ComponentCanonicalSectionReader<'a> = SectionLimited<'a, CanonicalFunction>; |
301 | | |
302 | | impl<'a> FromReader<'a> for CanonicalFunction { |
303 | 19.8k | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<CanonicalFunction> { |
304 | 19.8k | Ok(match reader.read_u8()? { |
305 | 2.26k | 0x00 => match reader.read_u8()? { |
306 | | 0x00 => CanonicalFunction::Lift { |
307 | 2.26k | core_func_index: reader.read_var_u32()?, |
308 | 2.26k | options: read_opts(reader)?, |
309 | 2.26k | type_index: reader.read_var_u32()?, |
310 | | }, |
311 | 0 | x => return reader.invalid_leading_byte(x, "canonical function lift"), |
312 | | }, |
313 | 3.26k | 0x01 => match reader.read_u8()? { |
314 | | 0x00 => CanonicalFunction::Lower { |
315 | 3.26k | func_index: reader.read_var_u32()?, |
316 | 3.26k | options: read_opts(reader)?, |
317 | | }, |
318 | 0 | x => return reader.invalid_leading_byte(x, "canonical function lower"), |
319 | | }, |
320 | | 0x02 => CanonicalFunction::ResourceNew { |
321 | 150 | resource: reader.read()?, |
322 | | }, |
323 | | 0x03 => CanonicalFunction::ResourceDrop { |
324 | 630 | resource: reader.read()?, |
325 | | }, |
326 | | 0x07 => CanonicalFunction::ResourceDropAsync { |
327 | 0 | resource: reader.read()?, |
328 | | }, |
329 | | 0x04 => CanonicalFunction::ResourceRep { |
330 | 156 | resource: reader.read()?, |
331 | | }, |
332 | 834 | 0x08 => CanonicalFunction::BackpressureSet, |
333 | 834 | 0x24 => CanonicalFunction::BackpressureInc, |
334 | 814 | 0x25 => CanonicalFunction::BackpressureDec, |
335 | | 0x09 => CanonicalFunction::TaskReturn { |
336 | 330 | result: crate::read_resultlist(reader)?, |
337 | 330 | options: read_opts(reader)?, |
338 | | }, |
339 | 844 | 0x0a => match reader.read_u8()? { |
340 | 844 | 0x7f => CanonicalFunction::ContextGet(reader.read_var_u32()?), |
341 | 0 | x => return reader.invalid_leading_byte(x, "context.get intrinsic type"), |
342 | | }, |
343 | 872 | 0x0b => match reader.read_u8()? { |
344 | 872 | 0x7f => CanonicalFunction::ContextSet(reader.read_var_u32()?), |
345 | 0 | x => return reader.invalid_leading_byte(x, "context.set intrinsic type"), |
346 | | }, |
347 | | 0x0c => CanonicalFunction::ThreadYield { |
348 | 866 | cancellable: reader.read()?, |
349 | | }, |
350 | 832 | 0x0d => CanonicalFunction::SubtaskDrop, |
351 | 176 | 0x0e => CanonicalFunction::StreamNew { ty: reader.read()? }, |
352 | | 0x0f => CanonicalFunction::StreamRead { |
353 | 182 | ty: reader.read()?, |
354 | 182 | options: read_opts(reader)?, |
355 | | }, |
356 | | 0x10 => CanonicalFunction::StreamWrite { |
357 | 178 | ty: reader.read()?, |
358 | 178 | options: read_opts(reader)?, |
359 | | }, |
360 | | 0x11 => CanonicalFunction::StreamCancelRead { |
361 | 172 | ty: reader.read()?, |
362 | 172 | async_: reader.read()?, |
363 | | }, |
364 | | 0x12 => CanonicalFunction::StreamCancelWrite { |
365 | 166 | ty: reader.read()?, |
366 | 166 | async_: reader.read()?, |
367 | | }, |
368 | 168 | 0x13 => CanonicalFunction::StreamDropReadable { ty: reader.read()? }, |
369 | 176 | 0x14 => CanonicalFunction::StreamDropWritable { ty: reader.read()? }, |
370 | 18 | 0x15 => CanonicalFunction::FutureNew { ty: reader.read()? }, |
371 | | 0x16 => CanonicalFunction::FutureRead { |
372 | 16 | ty: reader.read()?, |
373 | 16 | options: read_opts(reader)?, |
374 | | }, |
375 | | 0x17 => CanonicalFunction::FutureWrite { |
376 | 14 | ty: reader.read()?, |
377 | 14 | options: read_opts(reader)?, |
378 | | }, |
379 | | 0x18 => CanonicalFunction::FutureCancelRead { |
380 | 16 | ty: reader.read()?, |
381 | 16 | async_: reader.read()?, |
382 | | }, |
383 | | 0x19 => CanonicalFunction::FutureCancelWrite { |
384 | 14 | ty: reader.read()?, |
385 | 14 | async_: reader.read()?, |
386 | | }, |
387 | 14 | 0x1a => CanonicalFunction::FutureDropReadable { ty: reader.read()? }, |
388 | 16 | 0x1b => CanonicalFunction::FutureDropWritable { ty: reader.read()? }, |
389 | | 0x1c => CanonicalFunction::ErrorContextNew { |
390 | 0 | options: read_opts(reader)?, |
391 | | }, |
392 | | 0x1d => CanonicalFunction::ErrorContextDebugMessage { |
393 | 0 | options: read_opts(reader)?, |
394 | | }, |
395 | 0 | 0x1e => CanonicalFunction::ErrorContextDrop, |
396 | | |
397 | 782 | 0x1f => CanonicalFunction::WaitableSetNew, |
398 | | 0x20 => CanonicalFunction::WaitableSetWait { |
399 | 850 | cancellable: reader.read()?, |
400 | 850 | memory: reader.read()?, |
401 | | }, |
402 | | 0x21 => CanonicalFunction::WaitableSetPoll { |
403 | 864 | cancellable: reader.read()?, |
404 | 864 | memory: reader.read()?, |
405 | | }, |
406 | 804 | 0x22 => CanonicalFunction::WaitableSetDrop, |
407 | 850 | 0x23 => CanonicalFunction::WaitableJoin, |
408 | 0 | 0x26 => CanonicalFunction::ThreadIndex, |
409 | | 0x27 => CanonicalFunction::ThreadNewIndirect { |
410 | 0 | func_ty_index: reader.read()?, |
411 | 0 | table_index: reader.read()?, |
412 | | }, |
413 | | 0x28 => CanonicalFunction::ThreadSwitchTo { |
414 | 0 | cancellable: reader.read()?, |
415 | | }, |
416 | | 0x29 => CanonicalFunction::ThreadSuspend { |
417 | 0 | cancellable: reader.read()?, |
418 | | }, |
419 | 0 | 0x2a => CanonicalFunction::ThreadResumeLater, |
420 | | 0x2b => CanonicalFunction::ThreadYieldTo { |
421 | 0 | cancellable: reader.read()?, |
422 | | }, |
423 | | 0x06 => CanonicalFunction::SubtaskCancel { |
424 | 852 | async_: reader.read()?, |
425 | | }, |
426 | 796 | 0x05 => CanonicalFunction::TaskCancel, |
427 | | 0x40 => CanonicalFunction::ThreadSpawnRef { |
428 | 0 | func_ty_index: reader.read()?, |
429 | | }, |
430 | | 0x41 => CanonicalFunction::ThreadSpawnIndirect { |
431 | 0 | func_ty_index: reader.read()?, |
432 | 0 | table_index: reader.read()?, |
433 | | }, |
434 | 0 | 0x42 => CanonicalFunction::ThreadAvailableParallelism, |
435 | 0 | x => return reader.invalid_leading_byte(x, "canonical function"), |
436 | | }) |
437 | 19.8k | } |
438 | | } |
439 | | |
440 | 6.25k | fn read_opts(reader: &mut BinaryReader<'_>) -> Result<Box<[CanonicalOption]>> { |
441 | 6.25k | reader |
442 | 6.25k | .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? |
443 | 6.25k | .collect::<Result<_>>() |
444 | 6.25k | } |
445 | | |
446 | | impl<'a> FromReader<'a> for CanonicalOption { |
447 | 4.67k | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { |
448 | 4.67k | Ok(match reader.read_u8()? { |
449 | 250 | 0x00 => CanonicalOption::UTF8, |
450 | 0 | 0x01 => CanonicalOption::UTF16, |
451 | 0 | 0x02 => CanonicalOption::CompactUTF16, |
452 | 1.35k | 0x03 => CanonicalOption::Memory(reader.read_var_u32()?), |
453 | 244 | 0x04 => CanonicalOption::Realloc(reader.read_var_u32()?), |
454 | 1.86k | 0x05 => CanonicalOption::PostReturn(reader.read_var_u32()?), |
455 | 672 | 0x06 => CanonicalOption::Async, |
456 | 286 | 0x07 => CanonicalOption::Callback(reader.read_var_u32()?), |
457 | 0 | 0x08 => CanonicalOption::CoreType(reader.read_var_u32()?), |
458 | 0 | 0x09 => CanonicalOption::Gc, |
459 | 0 | x => return reader.invalid_leading_byte(x, "canonical option"), |
460 | | }) |
461 | 4.67k | } |
462 | | } |