| Commit message (Collapse) | Author | Age | Files | Lines |
... | |
| |
|
| |
|
|
|
|
| |
We still support ref.is_func/i31 in the text format for now. After we verify that
no users depend on that we can remove it as well.
|
|
|
|
|
|
|
|
|
|
|
|
| |
TypeMerging previously tried to merge types with their supertypes and siblings
in a single step, but this could cause a misoptimization in which a type was
merged with its parent's sibling without being merged with its parent, breaking
subtyping.
Fix the bug by merging with supertypes and siblings separately. Since we now
have multiple merging steps, also take the opportunity to run the sibling
merging step multiple times to exploit more merging opportunities.
Fixes #5556.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
The fuzzer had code to avoid emitting `global.get` of locally defined (i.e.
non-imported) globals in global initializers and data segment offsets, but that
code only handled top-level `global.get` because it predated the extended-const
proposal. Unfortunately this bug went undetected until #5557, which fixed the
validator to make it reject invalid uses of `global.get` in constant
expressions.
Fix the bug so the validator no longer produces invalid modules.
|
|
|
|
|
|
|
|
|
|
|
| |
The nesting limit of around 20 was enough to cause exponential blowup. A 20K
input file lead to a 2GB wasm in one case I saw (!) which takes many seconds to
fuzz.
Instead, reduce the limit, and also check if random tells us that the random
input is done; when that's done we should stop, which limits us to O(input size).
Also do this for non-nullable types, and handle that in globals (we cannot emit a
RefAsNulNull there, so switch the global type if necessary).
|
|
|
|
|
|
| |
Even with a 1% chance of a huge array, there is a second problem aside from
hitting an allocation failure, which is DoS - building such a huge array of
Literals takes noticeable time in the fuzzer. Instead, just limit array max sizes,
which is consistent with what we do for struct sizes etc.
|
|
|
|
|
|
|
|
|
|
|
|
| |
When resolving `operator!=`, C++20 also considers `operator==` implementations
when the types on `operator!=` do not match exactly. This caused the modified
code to have no most-specific overload to choose, resulting in an error. This is
actually a bug in the language that is being fixed, but there exist compilers
without the fix applied.
Work around the problem by updating the types in the declaration of `operator==`
and `operator!=` to be more exact.
This is a copy of #5029 with formatting fixes.
|
|
|
|
|
|
|
|
|
|
| |
Previously we treated global.get as a constant expression and only
additionally verified that the target globals were immutable in some cases. But
global.get of a mutable global is never a constant expression, and further,
only imported globals are available in constant expressions unless GC is
enabled.
Fix constant expression validation to only allow global.get of immutable,
imported globals, and fix all the invalid tests.
|
|
|
|
| |
Only rarely return an uninhabitable subtype of an inhabitable one. This
avoids a major source of uninhabitability and immediate traps.
|
|
|
|
|
| |
The missing associated types will become necessary if we ever use these
iterators in a nontrivial manner. Make the parent reference into a pointer so
that the copy constructor and assignment operator are not implicitly deleted.
|
|
|
|
| |
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.
|