| Commit message (Collapse) | Author | Age | Files | Lines |
... | |
|
|
| |
As suggested in #5218
|
| |
|
| |
|
|
|
|
|
|
|
| |
It turns out that this assumption does not necessarily hold on Windows with
Visual Studio 2019. Instead of using `NAN` and `-NAN`, explicitly construct
positive and negative NaN values with `std::copysign`, which should be portable.
Fixes #5291.
|
|
|
|
| |
The caller fills the map with what is relevant anyhow, so we don't need to check
before looking for an item in the map.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Inlining had a bug where it gave return_calls in inlined callees concrete types
even when they should have remained unreachable. This bug flew under the radar
because validation had a bug where it allowed expressions to have concrete types
when they should have been unreachable. The fuzzer found this bug by adding
another pass after inlining where the unexpected types caused an assertion
failure.
Fix the bugs and add a test that would have triggered the inlining bug.
Unfortunately the test would have also passed before this change due to the
validation bug, but it's better than nothing.
Fixes #5294.
|
|
|
|
|
|
|
|
|
|
|
| |
The logic that is split out into mapTypes gets a map of old type => new type and then
updates the module to replace the old with the new.
This will be useful in a future pass to merge types. We will tell it to map the types to
be merged with the types we want to merge them into.
This removes an assert on all types being in the map to allow some of them not to be.
(the new pass that will use this will only want to map some types).
|
| |
|
| |
|
|
|
| |
The flag does nothing so far.
|
|
|
|
| |
Equirecursive is no longer standards track and its implementation is extremely
complex. Remove it.
|
|
|
|
|
|
|
|
|
|
| |
This makes Binaryen's default type system match the WasmGC spec.
Update the way type definitions without supertypes are printed to reduce the
output diff for MVP tests that do not involve WasmGC. Also port some
type-builder.cpp tests from test/example to test/gtest since they needed to be
rewritten to work with isorecursive type anyway.
A follow-on PR will remove equirecursive types completely.
|
|
|
|
|
| |
Dumping the text is nice sometimes, but on huge testcases the wat can be 1 GB
in size (!), and so dumping one per pass can lead to using 20 GB or so for the full
optimization pipeline. Emit just the binary to avoid that.
|
|
|
| |
Same testcase as in #5287 but in another pass.
|
|
|
| |
This reflects that naming used in the spec.
|
| |
|
|
|
| |
This addresses feedback missed in #5279.
|
|
|
|
|
|
|
|
|
| |
Update `HeapType::getFeatures` to report that GC is used for heap types that
have nontrivial recursion groups or supertypes. Update validation to check the
features on function heap types, not just their individual params and results.
This fixes a fuzz bug in #5239 where initial contents included a rec group but
the fuzzer disabled GC. Since the resulting module passed validation, the rec
groups made it into the binary output, making the type section malformed.
|
|
|
|
|
| |
Normally we ignore them anyhow (unreachability is an effect, either a trap or
a control flow switch), but in traps-never-happen mode we can ignore a trap, so
we need to check this manually.
|
|
|
| |
This workaround is no longer needed after commit emscripten-core/emscripten@ce4c405.
|
|
|
|
|
|
|
|
|
| |
std::string::back() is only well defined for non-empty strings.
Without the change, wasm-reduce fails if it is called from
$PATH, because then, the parent directory is an empty string.
A workaround is to explicitly set the binaryen path with -b,
and it is still necessary after this fix, but at least the program
ends with a comprehensible error message instead of a generic
assertion failure from the standard library.
|
|
|
|
|
|
|
| |
In this mode we don't remove the start/stop_em_asm symbols or data.
This is because with side modules we read this information directly
from the wasm binaryen at runtime.
See https://github.com/emscripten-core/emscripten/pull/18228
|
| |
|
| |
|
|
|
|
|
|
|
| |
Since we optimize assuming a closed world, optimizations can change the types
and structure of GC data even in externally-visible ways. Because differences
are expected, the fuzzer already did not compare reference-typed values from
before and after optimizations when running with nominal typing. Update it to
not compare these values under any type system.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
(some.operation
(ref.cast .. (local.get $ref))
(local.get $ref)
)
=>
(some.operation
(local.tee $temp
(ref.cast .. (local.get $ref))
)
(local.get $temp)
)
This can help cases where we cast for some reason but happen to not use the
cast value in all places. This occurs in j2wasm in itable calls sometimes: The
this pointer is is refined, but the itable may be done with an unrefined pointer,
which is less optimizable.
So far this is just inside basic blocks, but that is enough for the cast of itable
calls and other common patterns I see.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Fixes a longstanding problem with isorecursive canonicalization that only showed
up in MacOS and occasionally Windows builds. The problem was that
`RecGroupEquator` was not quite correct in the presence of self-references in
rec groups. Specifically, `RecGroupEquator` did not differentiate between
instances of the same type appearing across two rec groups where the type was a
self-reference in one group but not in the other.
The reason this only showed up occasionally on some platforms was that this bug
could only cause incorrect behavior if two groups that would incorrectly be
compared as equal were hashed into the same bucket of a hash map. Apparently the
hash map used on Linux never hashes the two problematic groups into the same
bucket.
|
|
|
|
|
|
|
|
|
| |
(#5273)
When `-Wheader-hygiene` is enabled, C compiler will warn when using
namespace directive in global context in header file.
When `-Wimplicit-const-int-float-conversion` is enabled C compiler will
warn on implicit integer to double conversions that change values.
|
|
|
|
| |
The previous error message was ambiguous and could easily be interpreted to mean
the opposite of what it meant.
|
|
|
|
|
| |
(#5266)
This reverts commit 570007dbecf86db5ddba8d303896d841fc2b2d27.
|
|
|
|
|
| |
This reverts commit b2054b72b7daa89b7ad161c0693befad06a20c90.
It looks like the necessary V8 change has not rolled out everywhere yet.
|
|
|
|
| |
If the target is a bottom type then it is a heap type but it is not a signature
type, and we should treat it as unreachable (and not crash).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
#5253 handled the case of just one possible global. It is also possible we have
multiple globals but just one value. This handles that case. (It slightly overlaps
with other passes, but as this pass actually identifies the creations of the objects
in globals, it has a guarantee of success that the others don't, and it is very easy
to just do given all the work done to handle the case of 2 values).
Also fix a minor bug in #5253 - we need to trap if the old reference were null.
That is, we know the reference must point to the only object ever created of
that type, but that is only if it is not null; if it's null we need to trap.
|
|
|
|
| |
This is more modern and (IMHO) easier to read than that old C typedef
syntax.
|
|
|
|
|
| |
Including support for parsing field indices. Although only numeric field indices
are supported at the moment, set up the code to make it straightforward to
implement type-dependent symbolic field names in the future.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Expand GlobalStructInference to operate on cases with a single possible global, and
not just 2 or more. Even the case of a single global is useful, it turns out, as we can
alter the reference in places like this:
(struct.get $type 0
(..ref..)
)
No matter what ref is, if there is a single global it must refer to, we can switch to
this:
(struct.get $type 0
(global.get $global)
)
That can unlock further opts later. Note that we can do this even if we don't know
what the value actually is - we may not know what the struct.get returns, but we
do know what it reads from.
|
|
|
|
| |
They were optional for a while to allow users to gracefully transition to using
them, but now make them mandatory to match the upstream WasmGC spec.
|
|
|
|
| |
Fixes #5250
|
|
|
|
|
|
|
|
|
|
| |
Pretty simple logic bug, but it ended up causing us to not optimize sometimes.
Sadly the original tests happened to not have anything that depended on the
index in isolation.
Fix + add comprehensive tests for using that index properly. Also test the
call.without.effects intrinsic, which is orthoginal to this, but also worth testing
as it is a big use case here.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
The offset and size were previously being sign extended from 32 to 64 bits,
which meant that negative sizes could make the bounds check pass and cause an
exception to be thrown by an overly large allocation. Switch to using uint64_t
from the start rather than mixing sizes and signs, and update the tests to
reproduce the error more robustly in the absence of the fix.
Also fix a bug in RemoveUnusedModuleElements triggered by the new test.
Fixes #5249.
|
|
|
|
| |
All that code did was filter contents by the type of the RefCast. We do that for all
expressions now, so it was redundant.
|
|
|
|
|
|
|
|
|
|
| |
We don't actually have the distributive property since our
PossibleContents representation is an approximation, and the fuzzer found
a case where that is noticeable. See more details in the new comment +
testcase.
I measured speed and memory usage and this actually causes almost no
noticeable change.
|
|
|
|
|
|
|
|
|
|
|
|
| |
First, we forgot to note the type annotation on `ArrayNewSeg` instructions, so
in small modules where these are the only annotated instructions, the type
section would be incomplete.
Second, in the interpreter we were reserving space for the array before checking
that the segment access was valid. This could cause huge allocations that threw
bad_alloc exceptions before the interpreter could get around to trapping. Fix
the problem by reserving the array after validating the arguements.
Fixes #5236.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Monomorphization finds cases where we send more refined types to a function
than it declares. In such cases we can copy the function and refine the parameters:
// B is a subtype of A
foo(new B());
function foo(x : A) { ..}
=>
foo_B(new B()); // call redirected to refined copy
function foo(x : A) { ..} // unchanged
function foo_B(x : B) { ..} // refined copy
This increases code size so it may not be worth it in all cases. This initial PR is
hopefully enough to start experimenting with this on performance, and so it does
not enable the pass by default.
This adds two variations of monomorphization, one that always does it, and the
default which is "careful": it sees whether monomorphizing lets the refined function
actually be better than the original (say, by removing a cast). If there is no
improvement then we do not make any changes. This saves a significant amount
of code size - on j2wasm the careful version increases by 13% instead of 20% -
but it does run more slowly obviously.
|
|
|
| |
Per the wasm spec, memory.grow instructions should return -1 when there is a failure to allocate enough memory. This PR adds support for returning this error code.
|
|
|
|
|
|
|
|
|
|
|
| |
OptimizeInstructions in rare cases can add unreachability. We propagate it out at
the end all at once. The fuzzer was smart enough to find a very special combination
of code + passes that can hit an issue, see the testcase.
As mentioned in the TODO, we should perhaps avoid adding unreachability in
OptimizeInstructions at all. If this happens again that might be worth the effort. But
also checking the type of the child as in this PR doesn't add much complexity in the
code.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* Update MemoryPacking for array.new_data
The MemoryPacking pass looks at all instructions that reference memory segments
to determine how they can be optimized. #5214 introduced a new instruction that
references memory segments, array.new_data, but did not update MemoryPacking
accordingly. This omission meant that MemoryPacking could produce invalid or
misoptimized modules in the presence of array.new_data.
Fix the problem by making MemoryPacking aware of array.new_data. Consider
array.new_data when determining whether a segment is used and update
array.new_data to reflect the new, optimized segment numberings afterward. To
keep things simple, do not try to split any segment that is referred to by
a array.new_data instruction.
* fix
* Add test explanations
* Fix possible-contents.h for `array.new_{data,elem}`
This code was not properly updated in #5214, so GUFA would incorrectly optimize
out `array.new_data` and `array.new_elem` instructions. Fix the problem by
making these instructions data flow roots.
* fix
* move tests
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* Update MemoryPacking for array.new_data
The MemoryPacking pass looks at all instructions that reference memory segments
to determine how they can be optimized. #5214 introduced a new instruction that
references memory segments, array.new_data, but did not update MemoryPacking
accordingly. This omission meant that MemoryPacking could produce invalid or
misoptimized modules in the presence of array.new_data.
Fix the problem by making MemoryPacking aware of array.new_data. Consider
array.new_data when determining whether a segment is used and update
array.new_data to reflect the new, optimized segment numberings afterward. To
keep things simple, do not try to split any segment that is referred to by
a array.new_data instruction.
* fix
* Add test explanations
|