| Commit message (Collapse) | Author | Age | Files | Lines |
... | |
|
|
| |
`doVisitFunction` does not exist.
|
|
|
|
|
|
|
|
| |
For example,
-O3 --skip-pass=vacuum
will run -O3 normally but it will not run the vacuum pass at all
(which normally runs more than once in -O3).
|
|
|
| |
StructSet cannot be dropped.
|
|
|
|
|
|
|
|
|
|
| |
When using JSPI with wasm-split, any calls to secondary module functions
will now first check a global to see if the module is loaded. If not
loaded it will call a JSPI'ed function that will handle loading module.
The setup is split into the JSPI pass and wasm-split tool since the JSPI
pass is first run by emscripten and we need to JSPI'ify the load secondary
module function. wasm-split then injects all the checks and calls to the
load function.
|
|
|
|
|
|
| |
We cannot modify the input string safely. To avoid that, copy where needed.
Fixes #5440
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
GlobalTypeRewriter made sure to order supertypes before their subtypes so that
type building would succeed, but this ordering previously did not account for
the fact that supertypes might be replaced by the type updating. When a
supertype is replaced, the replacement might not previously have had a
supertype/subtype relationship with the subtype, so it might have happened to be
ordered after the subtype.
Fix the problem by taking supertype replacements into account when ordering
types in the GlobalTypeRewriter. This requires generalizing the
`SupertypesFirst` utility in wasm-type-ordering.h to allow users to modify how
supertypes are found.
|
|
|
|
|
|
|
|
|
|
| |
In TypeMerging we previously merged all subsequent types in a refined partition
into whichever type happened to be first in the partition, but when that first
type happened to be a subtype of one of the other types in the partition, that
would cause type-updating.cpp to try to update that subtype's supertype to be
itself, causing an assertion failure.
Fix the problem by ensuring that the merge target is not a subtype of any other
types in the partition.
|
|
|
|
|
|
|
|
|
|
| |
The TypeMerging optimization usually tries to merge types into their supertypes,
but it can also merge sibling types together without merging them into their
common supertype. Implement this kind of sibling merging for root types that
have no nontrivial supertypes. Root types were previously never merged.
The implementation requires hashing and comparing the top-level structure of the
root types so that root types with the same structure can be assigned to the
same partition for DFA minimization.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Analyze type merging candidates as states in a DFA, using a partition refining
DFA minimization algorithm to more aggressively find sets of mergeable types.
The new implementation can merge types that the previous iteration would have
taken an arbitrary number of iterations to merge or would not have been able to
merge at all.
The new implementation is also careful in its treatment of private and public
types and should work as-is under an open world assumption or a relaxed
closed-world assumption that admits more public types. Specifically, the new
code avoids merging public types into their supertypes, but still allows
private subtypes to be merged into their public supertypes.
The new implementation supports merging function types, which the old
implementation did not.
Finally, the new implementation is able to merge identical sibling types even
when the analysis determines that they cannot be merged into their common
supertype. Extending this capability to sibling top-level types without
nontrivial supertypes is left to a follow-on PR.
|
|
|
|
|
|
|
|
|
| |
If the module does not have a name for a particular type, the new utility falls
back to use a different user-configurable type name generator, just like the
existing IndexedTypeNameGenerator does.
Also change how heap types are printed by this printing machinery (which is
currently only used for debugging) so that their names are printed in addition
to their contents. This makes the printer much more useful for debugging.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
type-updating.cpp implemented a topological sorts on heap types that would visit
supertypes first. Since this same sort will be used by TypeMerging.cpp in #5432,
factor it out into a shared utility in a new wasm-type-ordering.h header.
At the same time, fix a bug in which the sort would visit types not in the input
collection. Concretely, this bug would cause public supertypes of private types
to be visited when only private types should have been visited. This
functionality change will be tested in #5432.
In principle the subtype-first sort used in subtypes.h could also be moved to
this header, but that is not yet duplicated in the code base and is more
efficient because it depends on implementation details of its current context,
so do not move it for now.
|
|
|
|
|
|
|
|
| |
We used to have this algorithm in wasm-type.cpp, where we used it to implement
equirecursive type canonicalization, but we removed it when we removed
equirecursive typing. Bring the algorithm back as a standalone utility for
future use in optimization passes. In particular, it will be useful in
TypeMerging for identifying the greatest fixed point of mergeable types rather
than the smallest fixed point.
|
|
|
|
|
|
| |
Before, we'd potentially add a new item to the queue multiple times, then
do nothing when popping it from the queue in the second and later times.
With this PR we add a new item to the reachable set and to the queue at
the same time, so items cannot appear more than once in the queue.
|
|
|
|
|
|
| |
(#5427)
For subtyping to not break, we must leave the number of fields equal in both
super and subtype, for each such pair.
|
|
|
|
| |
This allows tools like wasm-reduce to be told to operate in closed-world mode. That
lets them validate in the more strict way of that mode.
|
|
|
|
|
|
| |
Optimize ref.cast instructions that must succeed by simply replacing them with
their child in the case where the child has a more refined type or by
propagating a further removed fallthrough value with a more refined type using a
tee.
|
|
|
|
|
|
| |
If traps are assumed never to happen, then ref.cast and call_indirect
instructions cannot differentiate between types because they always succeed.
Take advantage of this fact by only having these instructions inhibit type
merges when we are not assuming traps never happen.
|
|
|
|
|
|
|
|
|
|
| |
Support function subtyping with contravariant parameters and covariant results.
The actual change is a single line in wasm-type.cpp, so most of the patch is
updating the type fuzzer to generate interesting function subtypes. Since
function parameters are covariant, generating a function subtype requires
generating supertypes of its parameter types, which required new functionality
in the fuzzer. Also update the fuzzer to choose to reuse types at a finer grain,
so for example individual function parameters or results might be reused
unmodified while other parameters or results are still modified.
|
|
|
|
|
|
|
|
|
| |
Instead of only looking at the final fallthrough value and seeing whether it is
a `RefNull` expression to determine if we are casting a null value, check the
type of each intermediate fallthrough value to see if it is a null reference.
Also improve `evaluateCastCheck` to return `Failure` instead of
`SuccessOnlyIfNonNull` if the cast value is a reference to bottom type, since
those can never be non-null.
|
|
|
|
|
|
|
|
|
|
| |
The cast finding code in TypeMerging has been broken since we refactored how
casts work to support nullable casts. The cast finding code only considered
HeapType fields and the return type of `RefCast` to be potential cast targets,
but `RefTest` and `BrOn` instructions now store their cast types as `Type`
fields. Since cast targets are represented more heterogenously now, do not use
the delegations macros to find them.
Add tests showing that each cast instruction independently inhibits merging.
|
|
|
|
|
|
|
|
| |
`skipCast` takes an optional parameter that bounds how general the resulting
type is allowed to be. That parameter previously had a default value of `anyref`
with the intention of allowing all casts to be skipped, but that default
inadvertently prevented any casts in the `func` or `extern` type hierarchies
from being skipped. Update `skipCast` so that the default parameter allows all
casts to be skipped in all hierarchies.
|
|
|
|
|
|
|
|
| |
Since we refactored all the old kind-checking instructions to be represented as
general cast instructions, `GCTypeUtils::evaluateKindCheck` had become a
vestigial wrapper around `GCTypeUtils::evaluateCastCheck` that was only used in
RemoveUnusedBrs. Remove `evaluateKindCheck` and use `evaluateCastCheck` in
RemoveUnusedBrs without changing any functionality. A future PR may use the
extra information from `evaluateCastCheck` to further optimize branching casts.
|
| |
|
|
|
| |
Without this we hit an assertion on unreachable not being a heap type.
|
|
|
|
| |
We already handled Success and Failure. Also handle SuccessOnlyIfNull and
SuccessOnlyIfNonNull.
|
|
|
|
|
|
| |
`struct` has replaced `data` in the upstream spec, so update Binaryen's types to
match. We had already supported `struct` as an alias for data, but now remove
support for `data` entirely. Also remove instructions like `ref.is_data` that
are deprecated and do not make sense without a `data` type.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
These operations are deprecated and directly representable as casts, so remove
their opcodes in the internal IR and parse them as casts instead. For now, add
logic to the printing and binary writing of RefCast to continue emitting the
legacy instructions to minimize test changes. The few test changes necessary are
because it is no longer valid to perform a ref.as_func on values outside the
func type hierarchy now that ref.as_func is subject to the ref.cast validation
rules.
RefAsExternInternalize, RefAsExternExternalize, and RefAsNonNull are left
unmodified. A future PR may remove RefAsNonNull as well, since it is also
expressible with casts.
|
|
|
| |
Add a new evaluateCastCheck() utility and use that in relevant places.
|
| |
|
|
|
| |
Fixes #5406
|
|
|
|
|
|
|
|
| |
Look for definitely-failing casts along all the fallthrough values. Specifically, if any
cast in the middle proves the final cast will fail, then we know we will trap.
Fully optimize redundant casts, considering both the type and the heap type.
Combine a cast with a ref.as_non_null.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* Replace `RefIs` with `RefIsNull`
The other `ref.is*` instructions are deprecated and expressible in terms of
`ref.test`. Update binary and text parsing to parse those instructions as
`RefTest` expressions. Also update the printing and emitting of `RefTest`
expressions to emit the legacy instructions for now to minimize test changes and
make this a mostly non-functional change. Since `ref.is_null` is the only
`RefIs` instruction left, remove the `RefIsOp` field and rename the expression
class to `RefIsNull`.
The few test changes are due to the fact that `ref.is*` instructions are now
subject to `ref.test` validation, and in particular it is no longer valid to
perform a `ref.is_func` on a value outside of the `func` type hierarchy.
|
|
|
|
|
|
|
|
| |
In particular, do not treat the converted value as "falling through" the
conversion. Since the conversions cross type hierarchies, treating the converted
values as fallthrough values would make subsequent casts look like they must
fail, when in fact they may not.
Fixes #5407.
|
|
|
|
|
|
| |
We use TypeUpdater there, which handles updating unreachability. But with wasm GC
we also need to refinalize if we refine types. Somehow, this was not noticed until now,
but the new ref.cast null assertion on not losing type info was enough to uncover
this long-existing issue.
|
| |
|
|
|
|
|
|
|
| |
We were considering casts between unrelated types as unconditionally failing,
but in the case where the unrelated types are nullable, the cast could still
succeed if the value is null.
This bug was introduced in #5397.
|
|
|
|
|
|
| |
Also add some comments on related optimization opportunities.
Also delete a test of a combination of types between hierarchies, which will soon
not be expressible at all in the IR.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The `br_on{_non}_{data,i31,func}` operations are deprecated and directly
representable in terms of the new `br_on_cast` and `br_on_cast_fail`
instructions, so remove their dedicated IR opcodes in favor of representing them
as casts. `br_on_null` and `br_on_non_null` cannot be consolidated the same way
because their behavior is not directly representable in terms of `br_on_cast`
and `br_on_cast_fail`; when the cast to null bottom type succeeds, the null
check instructions implicitly drop the null value whereas the cast instructions
would propagate it.
Add special logic to the binary writer and printer to continue emitting the
deprecated instructions for now. This will allow us to update the test suite in
a separate future PR with no additional functional changes.
Some tests are updated because the validator no longer allows passing non-func
data to `br_on_func`. Doing so has not made sense since we separated the three
reference type hierarchies.
|
|
|
|
|
|
|
|
|
|
| |
ref.as_non_null (#5398)
We were checking the heap type, but now casts care about the nullability as
well.
If the nullability is the only problem, that is, the heap type will be fine but we
might have a null, we can at least switch a ref.cast (non-null) to a
ref.as_non_null.
|
|
|
|
|
|
|
|
|
| |
As well as br_on_cast_fail null. Unlike the existing br_on_cast* instructions,
these new instructions treat the cast as succeeding when the input is a null.
Update the internal representation of the cast type in `BrOn` expressions to be
a `Type` rather than a `HeapType` so it will include nullability information.
Also update and improve `RemoveUnusedBrs` to handle the new instructions
correctly and optimize in more cases.
|
|
|
| |
This fixes an oversight in #5395
|
|
|
|
| |
(#5395)
|
|
|
|
|
|
|
|
|
| |
visitRefCast can use trapOnNonNull. To make this not regress, add fallthrough
analysis there as well.
Minor test changes are due to trapOnNonNull using getDroppedChildren which
only emits drops of necessary children. It also tells us to refinalize so it is ok for it
to change the type to unreachable.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Parse both the folded and unfolded forms of blocks and structure the code to
make supporting additional block instructions like if-else and try-catch
relatively simple.
Parsing block types is extra fun because they may implicitly define new
signature heap types via a typeuse, but only if their types are not given by a
single result type. To figuring out whether a new type may be introduced in all
the relevant parsing stages, always track at least the arity of parsed results.
The parser parses block labels, but more work will be required to support branch
instructions that use them.
|
|
|
|
|
|
|
| |
As noted in #4739, legacy language emitting nan and infinity
exists, with the observation that it can be removed once asm.js
is no longer used and global NaN is available.
This commit removes that asm.js-specific code accordingly.
|
|
|
|
| |
It is implemented as an import, but functionally it is a call within the
module, so it does not cause types to be public.
|
|
|
|
|
|
|
|
|
|
|
| |
As noted in #4806, trying to optimize past level 0 can result in
passes emitting non-JS code, which is then unable to be converted during
final output.
This commit creates a new targetJS option in PassOptions, which can
be checked inside each pass where non-JS code might be emitted.
This commit initially adds that logic to OptimizeInstructions, where
this issue was first noticed.
|
|
|
|
|
|
|
| |
This new cast configuration was not expressible with the legacy cast
instructions. Although it is valid in Wasm, do not allow nullable casts of
non-nullable references, since those would unnecessarily lose type information.
Convert such casts to be non-nullable during expression finalization.
|
|
|
|
|
|
|
| |
After making the pass error when not in closed world, some testcases
required changes. One forward-looking testcase can just be removed - the
point of it was to see what happens if a type escapes, and now closed-world
errors on it - and another testcase needed to avoid types on the boundary,
and to use anyref+casts.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
We have a data structure there, typeGlobals, which maps types to the list of
globals for that type. Previously we used the convention of not having an
entry in the map to mean that a type is unoptimizable. However, this was not
used consistently, and in fact one place could insert to the map in a dangerous
way: a subtype's global is added to the list of globals of the super, and
typeGlobals[super].add(sub-global) would then effectively make an unoptimizable
super into an optimizable one.
To fix that, check for unoptimizability before propagating sub-globals. We do
still use the convention of not keeping data in typeGlobals for unoptimizable
things as it is a minor optimization to avoid wasted work.
Fixes #5379
|