| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
|
| |
Component binary format: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Binary.md#component-definitions
Context:
https://github.com/WebAssembly/binaryen/issues/6728#issuecomment-2231288924
|
|
|
|
|
|
|
| |
`ref.null` of shared types should only be allowed when shared-everything
is enabled, but we were previously checking only that reference types
were enabled when validating `ref.null`. Update the code to check all
features required by the null type and factor out shared logic for
printing lists of missing feature options in error messages.
|
|
|
| |
--skip-pass can now be specified more than once on the commandline.
|
|
|
|
|
|
|
| |
`ref.null` of shared types should only be allowed when shared-everything
is enabled, but we were previously checking only that reference types
were enabled when validating `ref.null`. Update the code to check all
features required by the null type and factor out shared logic for
printing lists of missing feature options in error messages.
|
|
|
|
| |
The logic for adding the shared-everything feature was not previously
executed for shared basic heap types.
|
|
|
|
|
|
|
| |
Add functions to:
* Set and get the trapsNeverHappen, closedWorld, generateStackIR and optimizeStackIR flags
* Manage the list of passes to skip.
|
|
|
|
| |
When creating a new subtype, make sure to copy the supertype's
shareability.
|
|
|
|
|
|
|
| |
Normally, values of different types can never compare equal to each
other, but since i31refs are not actually allocations, `ref.eq` has no
way to differentiate a shared i31ref and an unshared i31ref with the
same value, so it will report them as equal. Update the implementation
of value equality to reflect this correctly.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
flexibleCopy always visited parents before children, but it visited
vector children in reverse order:
(call ;; 1
(call $a) ;; 3
(call $b) ;; 2
)
The order of children happened to not matter in any user of this code,
and that's just what you get when you iterate over children in a vector
and push them to a stack before visiting them, so this odd ordering
was not noticed.
For a new user I will introduce soon, however, it would be nice to have
the normal pre-order:
(call ;; 1
(call $a) ;; 2
(call $b) ;; 3
)
(2 & 3 swapped).
This cannot be tested in the current code as it is NFC, but the later PR
will depend on it and test it heavily.
|
|
|
|
|
|
| |
When we switched to the new type printing machinery, we inserted this
extra space to minimize the diff in the test output compared with the
previous type printer. Improve the quality of the printed output by
removing it.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
When creating a reference to `func`, fix the probability of choosing to
continue on to choose some function other than the last one rather than
making it depend on the number of functions. Then, do not eagerly pick
from the rest of the candidate functions. Instead, fall through to the
more general logic that will already pick a random candidate function.
Also move the logic for coming up with a concrete signature down to
where it is needed.
These simplifications will make it easier to update the code to handle
shared types.
|
|
|
|
|
|
|
|
|
|
|
|
| |
Each pass instance can now store an argument for it, which can be different.
This may be a breaking change for the corner case of running a pass multiple
times and setting the pass's argument multiple times as well (before, the last
pass argument affected them all; now, it affects the last instance only). This
only affects arguments with the name of a pass; others remain global, as
before (and multiple passes can read them, in fact). See the CHANGELOG for
details.
Fixes #6646
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
We now consider a drop to be part of the call context: If we see
(drop
(call $foo)
)
(func $foo (result i32)
(i32.const 42)
)
Then we'd monomorphize to this:
(call $foo_1) ;; call the specialized function instead
(func $foo_1 ;; the specialized function returns nothing
(drop ;; the drop was moved into here
(i32.const 42)
)
)
With the drop now in the called function, we may be able to optimize out unused work.
Refactor a bit of code out of DAE that we can reuse here, into a new return-utils.h.
|
|
|
|
| |
The standard name for the instruction is `ref.i31`. Remove support for
the non-standard name and update tests that were still using it.
|
|
|
|
|
|
|
| |
Implement `ref.i31_shared` the new instruction for creating references
to shared i31s. Implement binary and text parsing and emitting as well
as interpretation. Copy the upstream spec test for i31 and modify it so
that all the heap types are shared. Comment out some parts that we do
not yet support.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
E.g. loading 4 bytes from 2^32 - 2 should error: 2 bytes are past the maximum
address. Before this PR we added 2^32 - 2 + 4 and overflowed to 2, which we
saw as a low and safe address. This PR adds an extra check for an overflow in
that add.
Also add unreachables after calls to segfault(), which reduces the overhead of
the extra check here (the unreachable apparently allows VMs to see that
control flow ends, after the segfault() which is truly no-return).
Fixes emscripten-core/emscripten#21557
|
|
|
|
|
|
|
|
| |
The full syntax for an expression in an element syntax looks like
`(item (ref.null none))`, but we have been printing the abbreviated
version, which omits the `(item ...)`. This abbreviation is only valid
when the item has only a single instruction, so it is not always correct
to use it. Rather than determining whether or not to use the
abbreviation on a case-by-case basis, always print the full syntax.
|
|
|
| |
This edge case make the lowering a little more tricky.
|
|
|
|
|
| |
Eventually we will need to do some tuning of compile time speed, but for
now it is going to be simpler to do all the opts, in particular because it makes
writing tests simpler.
|
|
|
|
|
| |
`any.convert_extern` and `extern.convert_any` return references to
shared heap types iff their operands are references to shared heap
types.
|
|
|
|
|
|
|
| |
Rather than trying to trampoline primary-to-secondary calls through an
existing table, just create a fresh table for this purpose. This ensures
that modifications to the existing tables cannot interfere with
primary-to-secondary calls and conversely that loading the secondary
module cannot overwrite modifications to the tables.
|
|
|
|
|
|
|
| |
Previously we just did not optimize cases where our escape analysis showed an
allocation flowed into a cast that failed. However, after inlining there can be
real-world cases where that happens, even in traps-never-happen mode (if the
cast is behind a conditional branch), so it seems worth optimizing.
|
|
|
|
|
| |
This is a tiny bit more code but it is more consistent with other
operations, and it saves work later.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Previously the pass would monomorphize a call when we were sending more
refined types than the target expects. This generalizes the pass to also consider
the case where we send a constant in a parameter.
To achieve that, this refactors the pass to explicitly define the "call context",
which is the code around the call (inputs and outputs) that may end up leading
to optimization opportunities when combined with the target function. Also
add comments about the overall design + roadmap.
The existing test is mostly unmodified, and the diff there is smaller when
ignoring whitespace. We do "regress" those tests by adding more local.set
operations, as in the refactoring that makes things a lot simpler, that is, to
handle the general case of an operand having either a refined type or be a
constant, we copy it inside the function, which works either way. This
"regression" is only in the testing version of the pass (the normal version
runs optimizations, which would remove that extra code).
This also enables the pass when GC is disabled. Previously we only handled
refined types, so only GC could benefit. Add a test for MVP content
specifically to show we operate there as well.
|
| |
|
|
|
|
|
|
|
|
|
| |
Normally we use it when optimizing (above a certain level). This lets the user
prevent it from being used even then.
Also add optimization options to wasm-metadce so that this is possible
there as well and not just in wasm-opt (this also opens the door to running
more passes in metadce, which may be useful later).
|
|
|
|
|
|
|
|
|
| |
There are times after collecting a profile, we wish to manually include
specific functions into the primary module.
It could be due to non-deterministic profiling or functions for error
scenarios (e.g. _trap).
This PR helps to unlock this workflow by honoring both the
`--keep-funcs` flag as well as the `--profile` flag
|
|
|
|
|
| |
(#6721)
Fixes #6718
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Anything else right before an unreachable is removed by the main DCE
pass anyhow, but because of the structured form of BinaryenIR we can't remove
a drop. That is, this is the difference between
(i32.eqz
(i32.const 42)
(unreachable)
)
and
(drop
(call $foo)
)
(unreachable)
In both cases the unreachable is preceded by something we don't need,
but in the latter case it must remain in BinaryenIR for validation.
To optimize this, add a rule in StackIR.
Fixes #6715
|
|
|
|
|
|
|
|
|
| |
Rename instructions `extern.internalize` into `any.convert_extern` and
`extern.externalize` into `extern.convert_any` to follow more closely
the spec. This was changed in
https://github.com/WebAssembly/gc/issues/432.
The legacy name is still accepted in text inputs and in the C and JS
APIs.
|
|
|
|
|
|
|
|
|
| |
(#6709)
Previously the replacement select got the debug info, but we should also copy it
to the values, as often optimizations lead to one of those values remaining by
itself.
Similar to #6652 in general form.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
RefTest (#6692)
CFP focuses on finding when a field always contains a constant, and then replaces
a struct.get with that constant. If we find there are two constant values, then in some
cases we can still optimize, if we have a way to pick between them. All we have is the
struct.get and its reference, so we must use a ref.test:
(struct.get $T x (..ref..))
=>
(select
(..constant1..)
(..constant2..)
(ref.test $U (..ref..))
)
This is valid if, of all the subtypes of $T, those that pass the test have
constant1 in that field, and those that fail the test have constant2. For
example, a simple case is where $T has two subtypes, $T is never created
itself, and each of the two subtypes has a different constant value.
This is a somewhat risky operation, as ref.test is not necessarily cheap.
To mitigate that, this is a new pass, --cfp-reftest that is not run by
default, and also we only optimize when we can use a ref.test on what
we think will be a final type (because ref.test on a final type can be
faster in VMs).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Give the type fuzzer the ability to generate shared heap types when the
shared-everything feature is enabled. It correctly ensures that shared
structs and arrays cannot reference unshared heap types, but that
unshared heap types can reference any heap type.
Update the main fuzzer so that for the time being it never uses the
shared-everything feature when generating additional heap types, so it
never generates shared types. We can lift this restriction once the main
fuzzer has been updated to properly handle shared types.
As a drive-by, fix some logic for subtracting feature sets from each
other that is used in this commit.
|
|
|
|
|
| |
If an allocation does not escape, then we can compute ref.eq for it: when
compared to itself the result is 1, and when compared to anything else it
is 0 (since it did not escape, anything else must be different).
|
|
|
|
| |
Such as `ref.eq`, `i31.get_{s,u}`, and `array.len`. Also validate that
struct and array operations work on shared structs and arrays.
|
|
|
| |
Add spec tests checking validation for structs and arrays.
|
|
|
| |
Fixes #6695
|
|
|
|
|
|
| |
That child must be a reference, as `finalize()` assumes so. To avoid an
assertion, error early.
Fixes #6696
|
|
|
|
|
|
|
|
| |
We tracked which expressions we saw an allocated struct/array reach, and then
quickly exited when another one did (as when two allocations mix, we can
optimize neither). It turns out that this helps very little in actual measurements
(looks like within noise - likely we are ruling out the un-optimizable cases early
otherwise anyhow). Also the complexity it adds is a problem for an improvement
I want to make to the pass, so remove it.
|
|
|
| |
Fixes #6690
|
|
|
|
|
| |
The result cannot be `none` or `unreachable` etc.
Fixes #6694
|
|
|
|
|
|
|
| |
This pass receives a list of functions to trace, and then wraps them in calls to
imports. This can be useful for tracing malloc/free calls, for example, but is
generic.
Fixes #6548
|
|
|
|
|
|
| |
We were missing code to mangle such names for JS. Without that, the name
of a temp var for the type `(ref $foo)` would end up with `(`, `)` in
the name, which is not valid in JS.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
(#6688)
If we have
(global $g (struct.new $S
(i32.const 1)
(struct.new $T ..)
(ref.func $f)
))
then before this PR if we wanted to read the middle field we'd stop, as it is non-constant.
However, we can un-nest it, making it constant:
(global $g.unnested (struct.new $T ..))
(global $g (struct.new $S
(i32.const 1)
(global.get $g.unnested)
(ref.func $f)
))
Now the field is a global.get of an immutable global, which is constant. Using this
technique we can handle anything in a struct field, constant or not. The cost of adding
a global is likely offset by the benefit of being able to refer to it directly, as that opens
up more opportunities later.
Concretely, this replaces the constant values we look for in GSI with a variant over
constants or expressions (we do still want to group constants, as multiple globals
with the same constant field can be treated as a whole). And we note cases where we
need to un-nest, and handle those at the end.
|
|
|
|
|
| |
For 32-bit memories, the offset value must be in the u32 range. Update
the address.wast spec test to assert that a module with an overlarge
offset value is invalid rather than malformed.
|
|
|
| |
This will hopefully fix the build on the coverage builder.
|
|
|
|
|
|
| |
Add an `isUTF8` utility and use it in both the text and binary parsers.
Add missing checks for overlong encodings and overlarge code points in
our WTF8 reader, which the new utility uses. Re-enable the spec tests
that test UTF-8 validation.
|