| Commit message (Collapse) | Author | Age | Files | Lines |
... | |
|
|
|
| |
In particular, the removed code path here that did a RefAsNonNull of a null
was causing a lot of code to just trap.
|
|
|
|
|
|
|
|
|
|
| |
Previously we emitted it early, and would then modify it in random ways
like other initial content. But this function is called frequently during
execution, so if we were unlucky and modded that function to trap then
basically all other functions would trap as well.
After fixing this, some places assert on not having any functions or types
to pick a random one from, so fix those places too.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
With this we generate random GC types that may be used in creating
instructions later.
We don't create many instructions yet, which will be the next step after
this.
Also add some trivial assertions in some places, that have helped
debugging in the past.
Stop fuzzing TypeMerging for now due to #5556 , which this PR
uncovers.
|
| |
|
|
|
|
|
| |
The main fuzzer needs to be able to filter out uninhabitable types and the type
fuzzer has code for finding uninhabitable types. Move and refactor the code to
expose a `getInhabitable` function that can be used for both purposes.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This became an issue because the timeline was this:
* We added non-nullable locals support. At the time, obviously
CodePushing did not require any fixups for that, since it just moved
code forward in a single block (and not past any uses). So we marked
the pass as not needing such fixups.
* We added pushing of code into ifs. But moving code into an if
can affect non-nullable validation since it is based on block scoping.
So we need to remove the mark on the pass, which will make it check and
apply fixups as necessary. See the testcase for an example.
|
|
|
| |
We'd need to handle contravariance to optimize them.
|
|
|
|
|
|
| |
Function references are always inhabitable because functions can be created with
any function type, even types that refer to uninhabitable types. Take advantage
of this by skipping function references when finding non-nullable reference
cycles that cause uninhabitability.
|
|
|
|
|
|
|
| |
For now just skip them, to avoid problems. In the future we should look
into modifying their children, when possible.
Fixes #5463
|
|
|
|
|
|
|
|
| |
As with #5535, this was not noticed because it can only happen on very
small modules where the param/result type appears nowhere else but
in a function signature.
Use generic heap type scanning, which also scans into struct and array
types etc.
|
|
|
|
|
|
| |
In #5437 we updated type printing so that printing a heap type would print its
name in addition to its contents. We had already been separately printing type
names in the type fuzzer, so after that change we were printing each type name
twice. Remove the redundant printing in the fuzzer to fix the error.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Some valid GC types, such as non-nullable references to bottom heap types and
types that contain non-nullable references to themselves, are uninhabitable,
meaning it is not possible to construct values of those types. This can cause
problems for the fuzzer, which generally needs to be able to construct values of
arbitrary types.
To simplify things for the fuzzer, introduce a utility for transforming type
graphs such that all their types are inhabitable. The utility performs a DFS to
find cycles of non-nullable references and breaks those cycles by introducing
nullability.
The new utility is itself fuzzed in the type fuzzer.
|
|
|
|
| |
Without this we hit an assertion on trying to write the binary, on a missing
heap type.
|
|
|
|
| |
Only very rarely ask to create a huge array, as that can easily hit a host
size limit and cause a run to be ignored.
|
|
|
|
|
| |
We can't just skip host limits (#5534) but must also ignore execution at that
point, as optimizations can change the results if they change whether we reach
a host limit.
|
|
|
|
|
|
| |
This was not noticed before because normally if there is a function type
with multiple results then there is also a function with that property. But
it is possible to make small testcases without such a function, and one might
be imported etc., so we do need to validate this.
|
|
|
|
| |
This makes it possible to get the JSPI'ed version of the function from the
function table.
|
|
|
|
| |
We handle this like the existing handling of TrapException: we skip running
this module (since we can't even instantiate it, so there is nothing to run).
|
|
|
| |
It is not a constant instruction and cannot be used in globals.
|
|
|
|
| |
(#5529)
|
| |
|
|
|
|
|
|
|
|
|
| |
This is a (more) standard name for `array.init_static`. (The full upstream name
in the spec repo is `array.new_canon_fixed`, but I'm still hoping we can drop
`canon` from all the instruction names and it doesn't appear elsewhere in
Binaryen).
Update all the existing tests to use the new name and add a test specifically to
ensure the old name continues parsing.
|
|
|
|
|
|
|
|
| |
To match the standard instruction name, rename the expression class without
changing any parsing or printing behavior. A follow-on PR will take care of the
functional side of this change while keeping support for parsing the old name.
This change will allow `ArrayInit` to be used as the expression class for the
upcoming `array.init_data` and `array.init_elem` instructions.
|
|
|
|
|
| |
With this, the sourcemap testcase outputs the exact same thing as the input.
Followup to #5504
|
|
|
|
|
| |
Without this fix, the common idiom of using `INT_MAX` in C source to mean an
unlimited number of waiters should be woken up actually compiled down to an
argument of -1 in JS, causing zero waiters to be woken.
|
|
|
|
|
|
|
|
|
|
| |
Before, a single ctor with GC worked, but any subsequent ones simply dropped
the globals from the previous ones, because we were missing an addGlobal in
an important place.
Also, we can get confused about which global names are in use in the module, so fix
that as well by storing them directly (we keep removing and re-adding globals, so
we can't use the normal module mechanism to find which names are in use).
|
|
|
|
| |
Like MemoryInit, this instruction cares about segment identity, so merging
segments into one big one for flattening is disallowed.
|
|
|
|
| |
The stack logic was incorrect, and led to source locations being emitted
on parents instead of children.
|
|
|
| |
Fixes #5511
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Previously the idea was that we started with HANG_LIMIT = 10 or so, and we'd decrement
it by one in each potentially-recursive call and loop entry. When we reached 0 we'd start
to unwind the stack. Then, after we unwound it all the way, we'd reset HANG_LIMIT before
calling the next export.
That approach adds complexity that each "execution wrapper", like for JS or for --fuzz-exec,
had to manually reset HANG_LIMIT. That was done by calling an export. Calls to those
exports had to appear in various places, which is sort of a hack.
The new approach here does the following when the hang limit reaches zero: It resets
HANG_LIMIT, and it traps. The trap unwinds the call stack all the way out. When the next
export is called, it will have a fresh hang limit since we reset it before the trap.
This does have downsides. Before, we did not always trap when we hit the hang limit but
rather we'd emit something unreachable, like a return. The idea was that we'd leave the
current function scope at least, so we don't hang forever. That let us still execute a small
amount of code "on the way out" as we unwind the stack. I'm not sure it's worth the
complexity for that.
The advantages of this PR are to simplify the code, and also it makes more fuzzing
approaches easy to implement. I'd like to add a wasm-ctor-eval fuzzer, and having to add
hacks to call the hang limit init export in it would be tricky. With this PR, the execution
model is simple in the fuzzer: The exports are called one by one, in order, and that's it -
no extra magic execution needs to be done.
Also bump the hang limit from 10 to 100, just to give some more chance for code to run.
|
|
|
|
| |
Until we get full support for serializing table changes, stop evalling so we do
not break things.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
(#5510)
Simply loop over the values and use tuple.make.
This also adds a lit test for ctor-eval. I found that the problem blocking us
before was the logging, which confuses the update script. As this test at
least does not require that logging, this PR adds a --quiet flag that
disables the logging, and then a lit test just works.
|
|
|
| |
This is enough to test RSE.
|
| |
|
|
|
| |
This is enough for DAE and other opts to run on string consts.
|
|
|
|
|
| |
This is necessary to avoid fuzzer breakage after #5497 as it added a test with
strings. We could also ignore that file, like we do for other string files, but this
was not much work so just implement it.
|
|
|
|
| |
Half the time, never add any unreachable code. This ensures we run the
most code we possibly can half the time, at least.
|
|
|
|
| |
string.eq does, and when we added string.compare I forgot to adjust the
boolean property for that new opcode.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This makes the fuzzer replace things with an unreachable instruction in
rare situations. The hope was to find bugs like #5487, but instead it's
mostly found bugs in the inliner actually (#5492, #5493).
This also fixes an uncovered bug in the fuzzer, where we refinalized in
more than one place. It is unsafe to do so before labels are fixed up
(as duplicate labels can confuse us as to which types are needed; this
is actually the same issue as in #5492). To fix that, remove the extra
refinalize that was too early, and also rename the fixup function since
it does a general fixup for all the things.
|
|
|
|
|
|
|
|
|
|
|
|
| |
See example in the new comment. In general, we never want to go from
unreachable to reachable (refinalize doesn't even try), as it misses out on
DCE opportunities. Also it may have validation issues, which is how the
fuzzer found this.
Remove code in the same place that was redundant after the refinalize
was added in #5492. That simplifies some existing testcases slightly, by
removing an unneeded br we added, and now we add a new unreachable
at the end in other cases that need it.
|
|
|
|
|
|
|
|
|
|
| |
Store string data as GC data. Inefficient (one Const per char), but ok for now.
Implement string.new_wtf16 and string.const, enough for basic testing.
Create strings in makeConstantExpression, which enables ctor-eval support.
Print strings in fuzz-exec which makes testing easier.
|
|
|
|
|
|
|
|
|
|
|
|
| |
We must refinalize as inlining unreachable code can lead to
more things becoming unreachable.
We also must uniquify label names before refinalizing, as the
IR must be valid at that time, so that code is moved.
This causes some minor changes to existing test code (some
label changes, and refinalization makes more things
unreachable), but only the two new tests show actual problems
that needed to be fixed.
|
|
|
|
|
| |
The assertion that the offset is zero does not necessarily hold for code that
uses this instruction via the clang builtin. Add support so that Emscripten
wasm2js tests pass in the presence of such code.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This can handle e.g.
(drop
(i32.add
(call ..)
(call ..)
)
)
We can remove the add and just leave two dropped calls:
(drop
(call ..)
)
(drop
(call ..)
)
|
|
|
|
|
|
|
|
|
| |
A cast to a non-nullable null (an impossible type) must trap.
In traps-never-happen mode, a cast that either returns a null or traps will
definitely return a null.
Followup to #5461 which emits casts to bottom types.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Exposes the constants
**Unary**
* BinaryenRelaxedTruncSVecF32x4ToVecI32x4
* BinaryenRelaxedTruncSVecF32x4ToVecI32x4
* BinaryenRelaxedTruncZeroSVecF64x2ToVecI32x4
* BinaryenRelaxedTruncZeroUVecF64x2ToVecI32x4
**Binary**
* BinaryenRelaxedSwizzleVecI8x16
* BinaryenRelaxedMinVecF32x4
* BinaryenRelaxedMaxVecF32x4
* BinaryenRelaxedMinVecF64x2
* BinaryenRelaxedMaxVecF64x2
* BinaryenRelaxedQ15MulrSVecI16x8
* BinaryenDotI8x16I7x16SToVecI16x8
**SIMDTernary**
* BinaryenRelaxedFmaVecF32x4
* BinaryenRelaxedFmsVecF32x4
* BinaryenRelaxedFmaVecF64x2
* BinaryenRelaxedFmsVecF64x2
* BinaryenLaneselectI8x16
* BinaryenLaneselectI16x8
* BinaryenLaneselectI32x4
* BinaryenLaneselectI64x2
* BinaryenDotI8x16I7x16AddSToVecI32x4
so the respective instructions can be produced and inspected with the C API.
|
|
|
| |
See WebAssembly/stringref#60
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
If a type hierarchy has abstract classes in the middle, that is, types that
are never instantiated, then we can optimize casts and other operations
to them. Say in Java that we have `AbstractList`, and it only has one
subclass `IntList` that is ever created, then any place we have an `AbstractList`
we must actually have an `IntList`, or a null. (Or, if no subtype is instantiated,
then the value must definitely be a null.)
The actual implementation does a type mapping, that is, it finds all places
using an abstract type and makes them refer to the single instantiated
subtype (or null). After that change, no references to the abstract type
remain in the program, so this both refines types and also cleans up the
type section.
|