| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
I am working to bring up the fuzzer on comparisons between VMs.
Comparing between the binaryen interpreter and v8, it found some
atomics issues:
Atomic operations, including loads and stores, must be aligned
or they trap.
AtomicRMW did the wrong thing with the operands.
AtomicCmpxchg must wrap the input to the proper size (if we
only load 1 byte, only look at 1 byte of the expected value too).
AtomicWait and AtomicNotify must take into account their
offsets. Also SIMDLoadExtend was missing that. This was
confusing in the code as two getFinalAddresses existed,
one that doesn't compute with an offset, and one that does.
I renamed the one without to getFinalAddressWithoutOffset
so it's explicit and we can easily see we only call that one on
an instruction without an offset (which is the case for
MemoryInit, MemoryCopy, and MemoryFill).
AtomicNotify must check its address to see if it should trap,
even though we don't actually have multiple threads running.
Atomic loads of fewer bytes than the type always do an
unsigned extension, not signed.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Instead of using indices into the global interned type table. This
means that a lock is *never* needed to access an expanded Type. The
Type lock is now only acquired when a complex Type is created. On a
real-world wasm2js workload this improves wall clock time by 23% on my
machine with 72 cores and makes traffic on the Type lock entirely
insignificant.
**Before**
72 cores
real 0m6.914s
user 184.014s
sys 0m3.995s
1 core
real 0m25.903s
user 0m25.658s
sys 0m0.253s
**After**
72 cores
real 5.349s
user 70.309s
sys 9.691s
1 core
real 25.859s
user 25.615s
sys 0.253s
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
In wasm2js we ignore things that trap in wasm that we can't
really handle, like a load from memory out of bounds would
trap in wasm, but in JS we don't want to emit a bounds check
on each load. So wasm2js focuses on programs that don't
trap.
However, this is annoying in the fuzzer as it turns out that
our behavior for places where wasm would trap was not
deterministic. That is, wasm would trap, wasm2js would not
trap and do behavior X, and wasm2js with optimizations
would also not trap but do behavior Y != X. This produced
false positives in the fuzzer (and might be annoying in
manual debugging too).
As a workaround, this adds a --deterministic flag to wasm2js,
which tries to be deterministic about what it does for cases
where wasm would trap. This handles the case of an int
division by 0 which traps in wasm but without this flag could
have different behavior in wasm2js with or without opts
(see details in the patch).
|
|
|
| |
Fixes #2751.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
We used std::cerr as a workaround for that this logging
interfered with spec testing. But it's easy enough to filter
out this stuff for the spec tests.
The benefit to using std::cout is that as you can see in
the test output here, this is relevant test output - it's not
a side channel for debugging. If the rest of the interpreter
output is in std::cout but only traps are in std::cerr then
they might end up out of order etc., so best to keep them
all together.
This will allow easier additions of tests for fuzz testcases
|
|
|
|
| |
We shouldn't actually nop, we forgot that the value may have
side effects, so just drop it (opts will remove it later, if possible).
|
|
|
|
|
|
|
|
|
| |
These seem to be accidentally introduced in when we enforced use of
`Type::` on type names in #2434.
By the way TIL this actually compiles, and don't know why:
```
Type::Type::Type::Type::Type::Type::Type::Type::none
```
|
|
|
| |
Fixes #2749
|
|
|
|
|
| |
The fuzzer was previously unconditionally emitting one event parameter
more than it was supposed to, which meant multivalue events were
emitted when multivalue was not enabled.
|
|
|
|
| |
Based on freedback in #2741 it looks like we can use the existing
`simplify-globals-optimizing` pass to trigger this cleanups we need.
|
|
|
|
|
| |
Since the global is never read, we know that any write operation
will be unobservable.
|
|
|
|
|
|
| |
Avoid taking the type interning lock to look up the size when the
provided ID corresponds to a statically known type. This eliminates a
considerable amount of unnecessary lock traffic when using the C or JS
APIs.
|
|
|
|
|
| |
Instead of adding globals for hardcoded basic types, traverse the
module to collect all call types that might need to be handled and
emit a global for each of them. Adapted from #2712.
|
|
|
|
|
|
|
|
| |
`BinaryIndexes` was only used in two places (Print.cpp and
wasm-binary.h), so it didn't seem to be a great fit for
module-utils.h. This change moves it to wasm-binary.h and removes its
usage in Print.cpp. This means that function indexes are no longer
printed, but those were of limited utility and were the source of
annoying noise when updating tests, anyway.
|
|
|
|
|
|
|
| |
Cache type sizes in unused bits from the type ID and rewrite some Type
methods to avoid unnecessary calls to `expand` when the type is known
to be a basic non-tuple type. This eliminates most of the locking
traffic and reduces wall clock time by 52% and CPU time by 73% percent
for one real-world program on my machine.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
We realized it is not valid to do these f$, g$ optimizations in
main and side modules, as a symbol might appear in both (like
RTTI or a weak symbol). We do need one of the appearances
to "win". This does the g$ optimization in main modules only,
that is, if a global appears in a main module then we can avoid
a g$ import and instead compute its location directly in the
module, since we will "win" over other modules with the same
symbol anyhow.
|
|
|
|
|
|
|
|
|
|
|
| |
coalesce-locals is nonlinear in the number of locals, so it is
greatly beneficial to reorder the locals (which then drops the
unused ones at the end automatically). The default passes
do this already, but wasm2js does some custom work, and
this was missing.
With this change that pass takes 10x less time on poppler
with --flatten --flatten --simplify-locals-notee-nostructure
which approximates what wasm2js does.
|
|
|
|
|
| |
I think the history here is that localNames used to be a
vector, then we made it a map, but didn't update this pass...
so in rare cases it could end up emitting wrong stuff.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The post-commit Mac bot on github failed to compile #2727 with
Undefined symbols for architecture x86_64:
"wasm::ReorderLocals::UNSEEN", referenced from:
wasm::ReorderLocals::doWalkFunction(wasm::Function*) in ReorderLocals.cpp.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
That seems odd, it's defined like this?
static const Index UNSEEN = -1;
Perhaps we are hitting a weird compiler bug. Anyhow, just use an
enum to be safe.
Also for clarity switch to 0 for the unseen value.
|
|
|
|
|
|
|
|
| |
The original code here is quite old and I guess we assumed
that it was ok to use maps for this, but on really huge amounts
of locals it ends up mattering a lot. This makes the pass 3x
faster on poppler after --flatten --flatten (double flatten creates
lots of new locals, and is generally similar to what wasm2js
does).
|
|
|
|
|
|
|
|
| |
Weak symbols and interposition etc. mean that we should not
replace an fp$ call with a symbol from the module itself if there
is a chance there is another symbol that would have overridden it.
In side modules this risk exists and so this PR makes us stop
doing that. In main modules it is ok because they are loaded
first and so any symbol they provide will "win" over others anyhow.
|
|
|
|
|
| |
If wasm-emscripten-finalize is given the BigInt flag, then we will
be using BigInts on the JS side, and need no legalization at all
since i64s will just be BigInts.
|
|
|
|
|
|
| |
Unless the multivalue feature is enabled. The validation for events
recently changed to disallow events returning multiple items unless
the multivalue feature is enabled, but the fuzzer was not updated
accordingly. This PR fixes the glitch.
|
|
|
|
|
|
|
| |
Since it wasn't easy to support tuples in Asyncify's call support
using temporary functions, we decided to allow tuple-typed globals
after all. This PR adds support for parsing, printing, lowering, and
interpreting tuple globals and also adds validation ensuring that
imported and exported globals do not have tuple types.
|
|
|
|
|
|
|
|
| |
This reverts commit 5ddda8d2e6a3287ff6adcd69493e1e1c8b6c3872.
We decided it would be easier to allow tuple-typed globals than to
make calls work here after all. Reverts that change, but keeps small
improvements it made for clarity.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Now that we update the dylink section properly, we can
do the same optimization in side modules as in main ones:
if the module provides a function, don't call an $fp method
during startup, instead add it to the table ourselves and use
the relative offset to the table base.
Fix an issue when the table has no segments initially: the
code just added an offset of 0, but that's not right. Instead,
an a __table_base import and use that as the offset. As
this is ABI-specific I did it on wasm-emscripten-finalize,
leaving TableUtils to just assert on having a singleton
segment.
Add a test of a wasm file with a dylink section to the lld tests.
|
|
|
|
| |
Update it from wasm-emscripten-finalize when we append
to the table.
|
|
|
|
|
| |
This calls `Fatal()` when EH instructions are used in unsupported code.
Currently EH instructions are unsupported in Flatten, ReReloop, and
DataFlow-using passes.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Depends on emscripten-core/emscripten#10741
which ensures that table indexes are unique. With that guarantee,
a main module can just add its function pointers into the table, and
use them based on that index. The loader will then see them in the
table and then give other modules the identical function pointer for
a function, ensuring function pointer equality.
This avoids calling fp$ functions during startup for the main
module's own functions (which are slow). We do still call fp$s
of things we import from outside, as we don't have anything to
put in the table for them, we depend on the loader for that.
I suspect this can also be done with SIDE_MODULES, but did not
want to try too much at once.
|
|
|
|
| |
Adds functions for creating and inspecting tuple.make and
tuple.extract expressions in the C and JS APIs.
|
|
|
|
|
| |
This will be easier to extend for tuples.
Also add more clarifying comments.
|
|
|
|
|
|
|
|
|
| |
Previously the multivalue feature enabled tuples in control flow
positions, but tuples elsewhere did not require the multivalue
feature. However, allowing tuple operations and locals in MVP modules
means that all passes and tools need to support tuples, even if it
isn't a high priority for them to support multivalue. Allowing tuples
in MVP modules doesn't provide much value, so this changes disallows
them entirely unless multivalue is enabled.
|
|
|
| |
The version of V8 pulled in by JSVU recently updated to expect the new ordering of the event section, so this PR should fix the CI.
|
|
|
|
|
|
| |
Some optimizations may replace tuple elements with simpler values, and
those simpler values may be a subtype of the original value. Tuple
operations should continue to validate without being refinalized in
these cases.
|
|
|
|
|
|
| |
Adds full support for the {i8x16,i16x8,i32x4}.abs instructions merged
to the SIMD proposal in https://github.com/WebAssembly/simd/pull/128
as well as the {i8x16,i16x8,i32x4}.bitmask instructions proposed in
https://github.com/WebAssembly/simd/pull/201.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
We previously thought unreachable `tuple.make` instructions did not
require special unreachable handling, but consider the following wast:
```
(module
(func $foo
(tuple.make
(unreachable)
(i32.const 42)
)
)
)
```
This validates because the only expression in the body is unreachable,
but when it is emitted as a binary it becomes
```
unreachable
i32.const 42
```
This does not validate because it ends with an i32, but the function
expected an empty stack at the end. The fix is to emit an extra
`unreachable` after unreachable `tuple.make`
instructions. Unfortunately it is impossible to write a test for this
right now because the binary parser silently drops the `i32.const 42`,
making the function valid again.
|
|
|
| |
Iterate over tuple locals and separately load or store each component.
|
|
|
|
|
|
| |
The meaning we intend is "constant", and not the "Const"
node (which contains a number). So I think the full
name is less confusing.
|
|
|
|
|
| |
It should be a signed LEB128, not an unsigned LEB128. This bug was
causing modules to be invalid when the number of signatures in the
type section was large and multivalue blocks were present.
|
|
|
|
|
| |
RemoveUnusedBrs produces selects for some patterns, but selects of
multivalue types are not valid. This change checks that types are not
tuple types before producing selects.
|
|
|
|
|
|
|
|
|
| |
Previously the signature collection mechanism responsible for
populating the type section with signatures used by instructions only
collected signatures from indirect call and block instructions. This
works as long as all other control flow constructs like ifs, loops,
and tries contain blocks with the same signature. But it is possible
to have an if with non-block children, and we would need to collect
its signature as well.
|
| |
|
|
|
|
| |
Also increases the usefulness of a couple wasm-builder methods that
are useful here.
|
| |
|
|
|
|
|
|
|
|
| |
Also makes it work with any other constant expression such as a
ref.func or ref.null instructions. This optimization may not be very
important, but it illustrates how simple it can be to update a pass to
handle tuples (and also I was already looking at it because of the
prior changes that had to be made to it).
|
|
|
|
|
|
| |
This involves replacing `Literal::makeZero` with `Literal::makeZeroes`
and `Literal::makeSingleZero` and updating `isConstantExpression` to
handle constant tuples as well. Also makes `Literals` its own struct
and adds convenience methods on it.
|
|
|
|
| |
Updates the interpreter to properly flow vectors of values, including
at function boundaries. Adds a small spec test for multivalue return.
|
|
|
| |
Using CRTP, yay!
|