Skip to content
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

threads: improve tests #1719

Merged
merged 8 commits into from
Aug 15, 2024
Merged

Conversation

abrown
Copy link
Collaborator

@abrown abrown commented Aug 12, 2024

These changes improve shared-everything-threads tests; see commit messages for more details.

@abrown
Copy link
Collaborator Author

abrown commented Aug 12, 2024

I would like to add two more Binaryen tests here but can't yet:

  • for shared-polymorphism.wasm, wasm-tools needs some easier to validate both the shared and unshared version of a type; e.g., self.pop_operand(Some(...), can_be_shared)?
  • for shared-i31.wast, I just need to figure out what should be brought over (all? parts?)

@abrown abrown marked this pull request as draft August 12, 2024 22:12
Comment on lines 637 to 649
/// Pop a reference type from the operand stack, checking if it matches
/// `expected` or the shared version of `expected`. This function will panic
/// if `expected` is shared or a concrete type.
fn pop_maybe_shared_ref(&mut self, expected: RefType) -> Result<Option<RefType>> {
assert!(!self.resources.is_shared_ref_type(expected));
let actual = self._calculate_operand_type(Some(expected.into()))?;
let actual_ref = match self._as_ref_type(actual)? {
Some(rt) => rt,
None => return Ok(None),
};
// Change our expectation based on whether we're dealing with an actual
// shared or unshared type.
let expected = if self.resources.is_shared_ref_type(actual_ref) {
expected
.shared()
.expect("this only expects abstract heap types")
} else {
expected
};
self._check_operand_type(expected.into(), actual)?;
Ok(Some(actual_ref))
}
Copy link
Member

Choose a reason for hiding this comment

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

This method feels like roughly the right signature but I'm not sure it requires the other refactorings in this PR. Some changes I might recommend:

  • Don't add is_shared_ref_type and instead debug_assert! here that expected is an abstract heap type with the shared flag unset
  • Use pop_ref internally here which doesn't take an expected argument
  • Given a popped ref test if it's a subtype of the given expected either with the shared flag set or unset.
  • Return Result<Option<(RefType, bool)>> so callers don't have to recalculate shared-vs-not.

I think that should satisfy most use cases and avoid the need for larger refactorings?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Sure, let's try that. I think we need to keep is_shared_ref_type or something like it, though, because we need need to be able to figure out the sharedness of an actual concrete type. We can debug_assert! away the checks for expected but, because actual can actually be concrete, we need to be able to resolve the index to the underlying type somehow to inspect its sharedness.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

A side note: at some point in earlier PRs I had a RefType::is_shared(&self) -> Option<bool> that would check sharedness only for the abstract types but I made do without it until now — even if I re-added it, it wouldn't be enough here because we still have to check sharedness for concrete types.

crates/wasmparser/src/validator/operators.rs Outdated Show resolved Hide resolved
crates/wasmparser/src/validator/operators.rs Show resolved Hide resolved
This change simply renames the shared-everything-threads tests to use
more conventional names within the repository.
@tlively has been working on Binaryen support for
shared-everything-threads and has upstreamed several [tests] that are
useful here. This change incorporates some "bottom type" checks for
arrays and structs as a `shared-ref_eq.wast` test checking `ref.eq`
behavior for shared types (renamed to `ref-equivalence.wast` here).

To make these added tests pass, validation for `ref.eq` now allows it to
check both shared and ushared `eqref` types the the `ref.i31_shared`
returns the correct type.

[tests]: https://github.com/WebAssembly/binaryen/blob/main/test/spec
[shared-ref_eq.wast]: https://github.com/WebAssembly/binaryen/blob/main/test/spec/shared-ref_eq.wast
Certain instructions accept both shared and unshared references:
`ref.eq`, `i31.get_s`, `i31.get_u`, `array.len`, `any.convert_extern`,
and `extern.convert_any`. Validation needs to handle these special cases
to pass Binaryen's `polymorphism.wast` test. This change refactors the
`pop_operand` family of functions with several helpers to add
`pop_maybe_shared_ref`; `pop_maybe_shared_ref` lets the validator pass
an unshared `RefType` expectation but adapts it to being shared if that
is what is on the stack.
This change undoes previous work to rationalize the duplication in
`_pop_operand`, `pop_ref`, and now `pop_maybe_shared_ref`. As suggested
by @alexcrichton, this attempt keeps the status quo by reusing `pop_ref`
and doing a bit more work after the fact (re-checking the subtype
relationship).
This validator's existing logic assumed that the bottom and heap bottom
types matched any reference type (see `_pop_operand`). This change
surfaces that logic to `visit_ref_eq` as well: if `pop_maybe_shared_ref`
returns `None` (a bottom or heap bottom) for either value to `ref.eq`,
we skip checking the shared-ness match, assuming like we do in
`_pop_operand` that a bottom or heap bottom matches any reference type
(we've already checked that the types are subtypes of `eqref`).
@abrown
Copy link
Collaborator Author

abrown commented Aug 14, 2024

Ok, I refactored and rewrote parts of this to address the feedback. I kept the self.resources.is_shared_ref_type since I didn't have any other way to check shared-ness of concrete types (though we could definitely rename it is_shared if that's preferable — the type should be self-evident). I didn't return a shared-ness bool from pop_maybe_shared_ref but I could; it just felt like if we have self.resources.is_shared_ref_type we might as well use it and keep pop_maybe_shared_ref that much simpler. I also ended up having to rebase to bring in #1724; let's see if that gets rid of the CI errors.

@abrown abrown marked this pull request as ready for review August 14, 2024 22:21
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.

Looks good to me! I see now as well yeah how is_shared_ref_type is needed, but I think we can cut down on the usage of it a bit by returning a bool from pop_maybe_shared_ref

crates/wasmparser/src/validator/operators.rs Outdated Show resolved Hide resolved
crates/wasmparser/src/validator/operators.rs Show resolved Hide resolved
@alexcrichton alexcrichton added this pull request to the merge queue Aug 15, 2024
Merged via the queue into bytecodealliance:main with commit b8f0db3 Aug 15, 2024
28 checks passed
@abrown abrown deleted the set-more-tests branch August 15, 2024 17:37
alexcrichton added a commit to alexcrichton/wasm-tools that referenced this pull request Aug 15, 2024
This was an idea I had after bytecodealliance#1719 landed to statically ensure that the
asserts won't trip.
github-merge-queue bot pushed a commit that referenced this pull request Aug 15, 2024
This was an idea I had after #1719 landed to statically ensure that the
asserts won't trip.
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