Skip to content

wasmparser: Refactor canonical option validation and func type lowering #2163

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 28, 2025

Conversation

fitzgen
Copy link
Member

@fitzgen fitzgen commented Apr 28, 2025

Rather than repeatedly searching the list of canonical options, create a struct CanonicalOptions that summarizes their meaning when taken altogether. This struct is returned from check_options, where some initial, light validation occurs. Then, additional methods like options.require_memory()? can be called on the resulting struct depending on the use site (e.g. lifting vs. lowering vs. task.return vs. etc...).

This also makes it so that check_options does not require a LoweringInfo as a parameter. That presupposes that we already know the core function signature we will be lowering into. That will no longer be true with the combination of Wasm GC and the component model, where there will be a canonical option to specify the desired core function type, and this controls whether GC is used or not, among other things.

Finally, the ComponentFuncType::lower method is now invoked after canonical options are checked and takes a CanonicalOptions argument. Rather than setting info.requires_memory = true when it determines that a memory is required (for example) which was then validated in check_options later on, it has become fallible and calls options.require_memory()? itself to validate that a memory is declared. Again, this fallibility will be required for Wasm GC and component model integration in the future.

Rather than repeatedly searching the list of canonical options, create a `struct
CanonicalOptions` that summarizes their meaning when taken altogether. This
`struct` is returned from `check_options`, where some initial, light validation
occurs. Then, additional methods like `options.require_memory()?` can be called
on the resulting `struct` depending on the use site (e.g. lifting vs. lowering
vs. `task.return` vs. etc...).

This also makes it so that `check_options` does not require a `LoweringInfo` as
a parameter. That presupposes that we already know the core function signature
we will be lowering into. That will no longer be true with the combination of
Wasm GC and the component model, where there will be a canonical option to
specify the desired core function type, and this controls whether GC is used or
not, among other things.

Finally, the `ComponentFuncType::lower` method is now invoked after canonical
options are checked and takes a `CanonicalOptions` argument. Rather than setting
`info.requires_memory = true` when it determines that a memory is required (for
example) which was then validated in `check_options` later on, it has become
fallible and calls `options.require_memory()?` itself to validate that a memory
is declared. Again, this fallibility will be required for Wasm GC and component
model integration in the future.
@fitzgen fitzgen requested a review from alexcrichton April 28, 2025 21:19
Copy link
Member

@alexcrichton alexcrichton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice 👍

Comment on lines -2173 to 2314
let ty = types[self.core_function_at(*idx, offset)?].unwrap_func();
if ty.params()
let ty_id = self.core_function_at(*idx, offset)?;
let func_ty = types[ty_id].unwrap_func();
if func_ty.params()
!= [ValType::I32, ValType::I32, ValType::I32, ValType::I32]
|| ty.results() != [ValType::I32]
|| func_ty.results() != [ValType::I32]
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it might make sense to defer this type-check until CanonicalOptions::check_{lower,lift}? That's how post-return and callback options work for somewhat unrelated reasons, but in the future with memory64 integration it might be required for realloc as well

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to validate as much up front as possible, so that it is harder to forget to add things in the implementation of subsequent methods and so that it can be shared as much as possible. That said, I don't feel super strongly about it. My attitude is probably best summarized as

maybe? but it isn't clear to me. let's wait and cross that bridge when we get to it

@fitzgen
Copy link
Member Author

fitzgen commented Apr 28, 2025

Going to put this in the merge queue, if you feel more strongly about when/where we validate the realloc function's type, feel free to remove it from the queue and drop another comment.

@fitzgen fitzgen enabled auto-merge April 28, 2025 22:05
@fitzgen fitzgen added this pull request to the merge queue Apr 28, 2025
Merged via the queue into bytecodealliance:main with commit 040a222 Apr 28, 2025
32 checks passed
@fitzgen fitzgen deleted the split-check-options branch April 28, 2025 22:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants