| Commit message (Collapse) | Author | Age | Files | Lines |
... | |
| |
|
| |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
immediately (#5673)
Emit an unreachable, but guarded by a block as we do in other cases in this pass, to avoid
having unreachable code that is not fully propagated during the pass (as we only do a full
refinalize at the end). See existing comments starting with
"Make sure to emit a block with the same type as us" in the pass.
This is mostly not a problem with other casts, but ref.test returns an i32 which we have
lots of code that tries to optimize.
|
|
|
|
|
| |
And since the only type system left is the standard isorecursive type system,
remove `TypeSystem` and its associated APIs entirely. Delete a few tests that
only made sense under the isorecursive type system.
|
|
|
|
|
|
|
| |
Before this PR we hit the assert on the type not being basic.
We could also look into fixing the caller to skip bottom types, but as
bottom types trivially have no subtypes, it is more future-facing to
simply handle it.
|
|
|
|
|
|
|
|
|
|
|
|
| |
When we emit e.g. a struct.get's reference, this PR makes us prefer a non-nullable
value, and even to reuse an existing local if possible. By doing that we reduce
the risk of a trap, and also by using locals we end up testing operations on the
same data, like this:
x = new A();
x.a = ..
foo(x.a)
In contrast, without this PR each of those x. uses might be new A().
|
|
|
|
|
| |
After this change, the only type system usable from the tools will be the
standard isorecursive type system. The nominal type system is still usable via
the API, but it will be removed entirely in a follow-on PR.
|
| |
|
| |
|
| |
|
|
|
|
| |
These tests were easy to remove --nominal from because they already worked with
the standard type system as well.
|
|
|
|
| |
Remove stale check lines for --nominal mode checks that were removed in #5660
and rerun auto_update_checks.py to ensure the checks are stable.
|
|
|
| |
Fixes #5647
|
|
|
|
|
|
|
|
|
|
|
|
| |
In preparation to remove the nominal type system, which is nonstandard and not
usable for modules with nontrivial external linkage requirements, port an
initial batch of tests to use the standard isorecursive type system.
The port involves reordering input types to ensure that supertypes precede their
subtypes and inserting rec groups to ensure that structurally identical types
maintain their separate identities.
More tests will be ported in future PRs before the nominal type system is
removed entirely.
|
|
|
|
|
|
|
|
|
|
|
| |
Casting (ref nofunc) to (ref func) seems like it can succeed based on the rule
of "if it's a subtype, it can cast ok." But the fuzzer found a corner case where that
leads to a validation error (see testcase).
Refactor the cast evaluation logic to handle uninhabitable refs directly, and
return Unreachable for them (since the cast cannot even be reached).
Also reorder the rule checks there to always check for a non-nullable cast
of a bottom type (which always fails).
|
|
|
|
| |
A return value was unused, and we have BranchUtils::operateOnScopeNameDefs now
which can replace old manual code.
|
| |
|
|
|
|
|
|
|
|
| |
Without this, in certain complex operations we could end up calling a nested
make() operation that included nontrivial things, which could cause problems.
The specific problem I encountered was in fixAfterChanges() we tried to fix up
a duplicate label, but calling makeTrivial() emitted something very large that
happened to include a new block with a new label nested under a struct.get,
and that block's label conflicted with a label we'd already processed.
|
| |
|
|
|
|
|
|
|
| |
Without the hint, we always look for a valid name using name$0, $1, $2, etc.,
starting from 0, and in some cases that can lead to quadratic behavior.
Noticed on a testcase in the fuzzer that runs for over 24 seconds (I gave up at
that point) but takes only 2 seconds with this.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Technically we need to filter both before and after combining, that is,
if a location's contents will be filtered by F() then if the new contents
are x and old contents y then we need to end up with
F(F(x) U F(y)). That is, filtering before is necessary to ensure the union
of content does not end up unnecessarily large, and the filtering
after is necessary to ensure the final result is properly filtered to fit.
(If our representation were perfect then this would not be needed, but
it is not, as the union of two exact types can end up as a very large
cone, for example.)
For efficiency we have been filtering afterwards. But that is not enough
for packed fields, it turns out, where we must filter before. If we don't,
then if inputs 0 and 0x100 arrive to an i8 field then combining them
we get "unknown integer" (which is then filtered by 0xff, but it's too
late). By filtering before, the actual values are both 0 and we end up
with that as the only possible value.
It turns out that filtering before is enough for such fields, so do only
that.
|
|
|
| |
Like data.drop etc., it notices data segment identity.
|
|
|
|
|
| |
Memory data segments can be of large size, and might not fit in the stack.
fixes #5595
|
|
|
|
|
| |
We depended on ReFinalize doing it for us, and that usually works, but there is
a corner case that depends on knowing all the type changes being done. So use
our complete information to update those types in the pass.
|
|
|
|
|
|
|
|
| |
Do not optimize out or split segments that are referred to array.init_data
instructions. Fixes a bug where segments could get optimized out, producing
invalid modules. Doing the work to actually split segments used by
array.init_data is left for the future.
Also fix a latent UBSan failure revealed by the new test case.
|
| |
|
|
|
|
|
| |
The fuzzer found another case we were missing. I realized that we can just
check for this in replaceCurrent, at least for places that call that method,
which is the common case. So this simplifies the code while fixing a bug.
|
|
|
|
|
| |
The same bug was present in both: We ignored packing, so writing a larger
value than fits in the field would lead to us propagating that original value.
|
|
|
|
|
|
|
|
|
|
|
|
| |
Previously (ref.as_non_null (global.get ..)) would return the global with no changes,
and if the global was nullable then the type didn't match the output, which hit an
assertion (where GUFA checks that the contents match the declared type in the wasm).
To fix this, refine global types, that is, the type we track on GlobalInfo may be more
refined than the global itself. In the above example, if the global is nullable then
the GlobalInfo would point to that global but have a non-nullable type.
In fact the code was already prepared for this, and few changes were needed.
|
|
|
|
| |
(#5641)
|
| |
|
|
|
|
|
| |
These complement array.copy, which we already supported, as an initial complete
set of bulk array operations. Replace the WIP spec tests with the upstream spec
tests, lightly edited for compatibility with Binaryen.
|
|
|
|
|
|
|
| |
Trivial peephole optimization. Some work was needed in the tests as some of
them relied on that pattern for convenience, so I modified them to try to keep
them testing the same thing as much as possible (for one, struct.set.null.fallthrough,
I don't think we can actually keep testing the same, as the situation should not
be possible any more).
|
|
|
| |
This is the flip case of #5630
|
|
|
| |
Don't use a fixed 10% chance to mutate, but pick a mutation rate in each function.
|
|
|
|
| |
Fixes #5629
|
|
|
|
|
|
|
| |
We already did this for the first memory, and just needed to loop to handle initial
content in the test suite that has multiple memories.
Also clean up that code while I'm around, to avoid repeating
wasm.memories[0] all the time.
|
| |
|
|
|
|
|
| |
This saves the work of freeing and allocating for all the other maps. This is a
code path that is used by several passes so it showed up in profiling for
#5561
|
|
|
|
|
|
|
|
| |
Previously, the pointer type for newly emitted instructions was determined by
the type of the destination pointer on a memory.init instruction, but that did
not take into account that the destination pointer may be unreachable. Properly
look up the pointer type on the memory instead to fix the problem.
Fixes #5620.
|
|
|
|
|
|
|
|
|
| |
Repurpose makeBasicRef, makeCompoundRef to generate not just "constant"
refs but any reference, and use those to create StructNew/ArrayNew.
The key changes are to add makeCompoundRef to make(), and to make
the function call make() for children, where possible, instead of just
makeTrivial(). We also replace the i31-specific path with a call to
makeBasicRef which handles i31 among other things.
|
|
|
|
|
|
|
|
| |
Add support for memory and data segment module elements and treat them uniformly
with other module elements rather than as special cases. There is a cyclic
dependency between memories (or tables) and their active segments because
exported or accessed memories (or tables) keep their active segments alive, but
active segments for imported memories (or tables) keep their memories (or
tables) alive as well.
|
|
|
| |
When we remove a tee there, we must not change the type at all.
|
|
|
|
|
|
|
|
|
|
| |
All top-level Module elements are identified and referred to by Name, but for
historical reasons element and data segments were referred to by index instead.
Fix this inconsistency by using Names to refer to segments from expressions that
use them. Also parse and print segment names like we do for other elements.
The C API is partially converted to use names instead of indices, but there are
still many functions that refer to data segments by index. Finishing the
conversion can be done in the future once it becomes necessary.
|
|
|
|
| |
When removing a local.get we must replace it with something of the
identical type, and not make it non-nullable.
|
| |
|
|
|
|
|
| |
That code should only propagate unreachability, and not refine. If it refines when
we call finalize() then other code around it might end up invalid (as it could be
partially refined; see testcase).
|
|
|
|
| |
The pretty-printer will still serialize these using the old
func_subtype, array_subtype, and struct_subtype syntax, though.
|