| Commit message (Collapse) | Author | Age | Files | Lines |
... | |
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Since #5347 public types are never updated by type optimizations, but the
optimization passes have not yet been updated to take that into account, so they
are all buggy under an open world assumption. In #5359 we worked around many
closed world validation errors in the fuzzer by treating --closed-world like a
feature flag and checking whether it was necessary for fuzzer input, but that
did not prevent the type optimization passes from running under an open world,
so it did not work around all the potential issues.
Work around the problem more thoroughly by not running any type optimization
passes in the fuzzer without --closed-world. Also add logic to those passes to
error out if they are run without --closed-world and update the tests
accordingly.
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
| |
This is a pretty subtle point that was missed in #4811 - we need to first visit the
child, then compute the size, as the child may alter that size.
Found by the fuzzer.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
An overview of this is in the README in the diff here (conveniently, it is near the
top of the diff). Basically, we fix up nn locals after each pass, by default. This keeps
things easy to reason about - what validates is what is valid wasm - but there are
some minor nuances as mentioned there, in particular, we ignore nameless blocks
(which are commonly added by various passes; ignoring them means we can keep
more locals non-nullable).
The key addition here is LocalStructuralDominance which checks which local
indexes have the "structural dominance" property of 1a, that is, that each get has
a set in its block or an outer block that precedes it. I optimized that function quite
a lot to reduce the overhead of running that logic after each pass. The overhead
is something like 2% on J2Wasm and 0% on Dart (0%, because in this mode we
shrink code size, so there is less work actually, and it balances out).
Since we run fixups after each pass, this PR removes logic to manually call the
fixup code from various places we used to call it (like eh-utils and various passes).
Various passes are now marked as requiresNonNullableLocalFixups => false.
That lets us skip running the fixups after them, which we normally do automatically.
This helps avoid overhead. Most passes still need the fixups, though - any pass
that adds a local, or a named block, or moves code around, likely does.
This removes a hack in SimplifyLocals that is no longer needed. Before we
worked to avoid moving a set into a try, as it might not validate. Now, we just do it
and let fixups happen automatically if they need to: in the common code they
probably don't, so the extra complexity seems not worth it.
Also removes a hack from StackIR. That hack tried to avoid roundtrip adding a
nondefaultable local. But we have the logic to fix that up now, and opts will
likely keep it non-nullable as well.
Various tests end up updated here because now a local can be non-nullable -
previous fixups are no longer needed.
Note that this doesn't remove the gc-nn-locals feature. That has been useful for
testing, and may still be useful in the future - it basically just allows nn locals in
all positions (that can't read the null default value at the entry). We can consider
removing it separately.
Fixes #4824
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The "ignore trap" logic there is not close to enough for what we'd need to
actually fuzz in a way that ignores traps, so this removes it. Atm that logic
just allows a trap to happen without causing an error (that is, when comparing
two results, one might trap and the other not, but they'd still be considered
"equal"). But due to how we optimize traps in TrapsNeverHappens mode, the
optimizer is free to assume the trap never occurs, which might remove side
effects that are noticeable later. To actually handle that, we'd need to refactor
the code to retain results per function (including the Loggings) and then to
ignore everything from the very first trapping function. That is somewhat
complicated to do, and a simpler thing is done in #4936, so we won't need
it here.
|
|
|
|
|
|
|
| |
RTTs were removed from the GC spec and if they are added back in in the future,
they will be heap types rather than value types as in our implementation.
Updating our implementation to have RTTs be heap types would have been more work
than deleting them for questionable benefit since we don't know how long it will
be before they are specced again.
|
|
|
| |
This can give us some chance to catch bugs like #4839 in the fuzzer.
|
|
|
|
|
| |
The encoding here is simple: we store i31 values in the literal.i32
field. The top bit says if a value exists, which means literal.i32 == 0 is the
same as null.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
class (#4479)
As recently discussed, the interpreter code is way too complex. Trying to add
ctor-eval stuff I need, I got stuck and ended up spending some time to get rid
of some of the complexity.
We had a ModuleInstanceBase class which was basically an instance of a
module, that is, an execution of it. And internally we have RuntimeExpressionRunner
which is a runner that integrates with the ModuleInstanceBase - basically, it uses
the runtime info to execute code. For example, the MIB has globals info, and the
RER would read it from there.
But these two classes are really just one functionality - an execution of a module.
We get rid of some complexity by removing the separation between them, ending
up with a class that can run a module.
One set of problems we avoid is that we can now extend the single class in a
simple way. Before, we would need to extend both - and inform each other of
those changes. That gets "fun" with CRTP which we use everywhere. In other
words, each of the two classes depended on the other / would need to be
templated on the other. Specifically, MIB.callFunction would need to be given
the RER to run with, and so that would need to be templated on it. This ends up
leading to a bunch more templating all around - all complexity that we just
don't need. See the simplification to the wasm-ctor-eval for some of that (and
even worse complexity would have been needed without this PR in the next
steps for that tool to eval GC stuff).
The final single class is now called ModuleRunner.
Also fixes a pre-existing issue uncovered by this PR. We had the delegate
target on the runner, but it should be tied to a function scope. This happened
to not be a problem if one always created a new runner for each scope, but
this PR makes the runner longer-lived, so the stale data ended up mattering.
The PR moves that data to the proper place.
Note: Diff without whitespace is far, far smaller.
|
|
|
|
|
| |
We emitted the right text to stdout to indicate a trap in one code path, but did
not return a Trap from the function. As a result, we'd continue and hit the
assert on the next line.
|
|
|
|
|
|
|
|
| |
We used to only compare return values, and in #4369 we started comparing
whether an uncaught exception was thrown. This also adds whether a trap
occurred to `ExecutionResults`. So in `--fuzz-exec`, if a program with a
trap loses the trap or vice versa, it will error out saying the result
has changed, unless either of `--ignore-implicit-traps` or
`--trans-never-happen` is set.
|
|
|
|
|
|
|
|
|
| |
When a wasm exception is thrown and uncaught in the interpreter, it
caused the whole interpreter to crash, rather than gracefully reporting
it. This fixes the problem, and also compares whether an uncaught
exception happened when comparing the results before and after
optimizations in `--fuzz-exec`. To do that, when `--fuzz-exec` is given,
we now compare results even when the function does not have return
values. Logs for some existing test have changed because of this.
|
|
|
|
|
|
|
|
|
|
|
|
| |
Allocation and cast instructions without explicit RTTs should use the canonical
RTTs for the given types. Furthermore, the RTTs for nominal types should reflect
the static type hierarchy. Previously, however, we implemented allocations and
casts without RTTs using an alternative system that only used static types
rather than RTT values. This alternative system would work fine in a world
without first-class RTTs, but it did not properly allow mixing instructions that
use RTTs and instructions that do not use RTTs as intended by the M4 GC spec.
This PR fixes the issue by using canonical RTTs where appropriate and cleans up
the relevant casting code using std::variant.
|
|
Use the new capability in a new test of RTT behavior that will be fixed in #4284,
|