| Commit message (Collapse) | Author | Age | Files | Lines |
... | |
|
|
| |
This hits the fuzzer when it tries to call reference exports with a null.
|
|
|
|
|
|
|
|
|
|
|
| |
The cast instruction may be unreachable but the intended type for the cast
still needs to be collected. Otherwise we end up with problems both during
optimizations that look at heap types and in printing (which will use the heap
type in code but not declare it).
Diff without whitespace is much smaller: this just moves code around so
that we can use a template to avoid code duplication. The actual change
is just to scan ->intendedType unconditionally, and not ignore it if the
cast is unreachable.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
When a field has no reads, we remove all its writes, but we did this:
(struct.set $foo A B)
=>
(drop A) (drop B)
We also need to trap if A, the reference, is null, which this PR
fixes,
(struct.set $foo A B)
=>
(drop (ref.as_non_null A)) (drop B)
|
| |
|
|
|
|
|
|
| |
This fixes two bugs: First, we need to compare the nominal types of function
constants when looking for constants to "merge", not just their structure.
Second, when creating the new function we must use the proper type of
those constants, and not just another type.
|
|
|
|
| |
Randomly selecting a depth is ok for structural typing, but in nominal it
must match the actual hierarchy of types.
|
|
|
|
|
| |
The same module will have a different type after some transformations, even
though that is not observable, like --roundtrip. Basically, we should not be
comparing types between separate modules, which is what the fuzzer does.
|
| |
|
|
|
|
|
|
|
| |
Related: emscripten-core/emscripten#15893 (comment)
--pass-arg=asyncify-side-module option will be used not only from
side modules, but also from main modules.
|
|
|
| |
As proposed in https://github.com/WebAssembly/relaxed-simd/issues/52.
|
|
|
|
|
|
|
|
|
| |
We can preserve return_calls in inlined functions when the inlined call site is
itself a return_call, since the call result types must transitively match in
that case. This solves a problem where the previous inlining logic could
introduce stack exhaustion by downgrading recursive return_calls to normal
calls.
Fixes #4587.
|
|
|
|
| |
Other opcode ends with `Inxm` or `Fnxm` (where n and m are integers),
while `i8x16.swizzle`'s opcode name doesn't have an `I` in there.
|
|
|
| |
As proposed in https://github.com/WebAssembly/relaxed-simd/issues/40.
|
|
|
|
| |
Instead do a clear()+resize() (#4580)
|
|
|
|
|
|
|
|
| |
247f4c20a1 introduced a bug that caused expressions that refer to data segments
to be associated with the wrong segments in the presence of other segments that
have no referring expressions at all.
Fixes #4569.
Fixes #4571.
|
|
|
|
|
|
|
|
| |
CoalesceLocals (#4574)
Normally we just replace unreachable local.gets with a constant (0, or null), but if
the local is non-nullable we can't do that.
Fixes #4573
|
|
|
|
|
| |
Fixes #4562
Fixes #4564
|
|
|
|
|
|
|
|
|
|
|
| |
As we recently noted in #4555, that Feature::All and FeatureSet.setAll()
are different is potentially confusing...
I think the best thing is to make them identical. This does that, and adds a
new Feature::AllPossible which is everything possible and not just the
set of all features that are enabled by -all.
This undoes part of #4555 as now the old/simpler code works properly.
|
|
|
|
|
| |
#4555 fixed validation for such tuples, but we also did not handle
them in "stacky" code using pops etc., due to a logic bug in the
binary reading code.
|
|
|
|
|
|
|
| |
V8 used to incorrectly parse the segment index on bulk memory instructions as a
signed LEB rather than an unsigned LEB, which meant it only worked correctly
with up to 63 data segments. That bug has been fixed for over two years now, so
lift the maximum number of segments generated by memory packing from 63 to the
specified max, 100k.
|
|
|
|
|
|
| |
Apply the same logic to tuple fields as we do for all other fields,
when checking whether a non-nullable value is valid.
Fixes #4554
|
|
|
|
|
|
|
|
|
|
|
| |
The memory packing pass previously used vectors with a slot for each data
segment to easily map segment indices to lists of "referrers," i.e. bulk memory
expressions that referred to the segments. The parallel analysis pass to collect
these referrers allocated one of these vectors for each function in a module.
Unfortunately, for a particularly large module with over 200k functions and over
75k data segments, this resulted in hundreds of gigabytes of memory allocations.
The vast majority of functions contain no referrers, so using a
std::unordered_map makes much more sense than using a vector to perform this
mapping.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
(#4553)
Previously we'd remove a field from a type if that field has no uses in any
sub- or super-type. In that case we'd remove it from all the types at once.
However, there is a case where we can remove a field only from a parent
but not from its children, if the field is at the end: if A has fields {x, y, z}
and its subtype B has fields {x, y, z, w}, and A pointers only access
field y while B pointers access all the fields, then we can remove z
from A. Removing it from the end is safe, and then B will not only add
w as it did before but also add z. Note that we cannot remove x,
because it is not at the end: removing it from just A but not B would
shift the indexes, making them incompatible.
|
|
|
|
|
| |
This basically just adds a call to ParamUtils::applyConstantValues, however,
we also need to be careful to not optimize in the presence of imports or
exports, so this adds a boolean that indicates unoptimizability.
|
|
|
|
|
|
|
|
|
|
|
|
| |
This moves more logic from ConstantFieldPropagation into PossibleConstantValues,
that is, instead of handling the two cases of a Literal or a Name before calling
PossibleConstantValues, move that code into the helper class. That way all users of
PossibleConstantValues can benefit from it. In particular, this makes
DeadArgumentElimination now support optimizing immutable globals, as well as
ref.func and ref.null.
(Changes to test/lit/passes/dae-gc-refine-params.wast are to avoid the new
optimizations from kicking in, so that it still tests what it tested before.)
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This adds a new signature-pruning pass that prunes parameters from
signature types where those parameters are never used in any function
that has that type. This is similar to DeadArgumentElimination but works
on a set of functions, and it can handle indirect calls.
Also move a little code from SignatureRefining into a shared place to
avoid duplication of logic to update signature types.
This pattern happens in j2wasm code, for example if all method functions
for some virtual method just return a constant and do not use the this
pointer.
|
| |
|
|
|
|
|
|
|
| |
DeadArgumentElimination (#4547)
Similar to #4544, this moves the code to a utility function, and also
slightly generalizes it to support a list of functions (and not just 1)
and also a list of call_refs (and not just calls).
|
|
|
|
| |
This just moves PossibleConstantValues to a new separate file
(as a preparation for other passes using it too).
|
|
|
|
|
|
|
|
|
|
|
|
| |
DeadArgumentElimination (#4544)
In preparation for removing dead arguments from all functions sharing a heap
type (which seems useful for j2wasm output), first this PR refactors that code
so it is reusable. This moves the code out of the pass into FunctionUtils, and
also generalizes it slightly by
supporting a set of functions and not just a single one, and
receiving a list of call_refs and not just calls
(no other changes to anything).
|
|
|
|
|
|
|
| |
I believe this old code was written before we had LocalGraph. It does a flow
analysis to see if the values arriving in parameters are actually used, but
there is no reason to do it manually since we have LocalGraph now which
makes that trivial, as it matches the values for each get, so we can just check
if any get can read the param's incoming value.
|
| |
|
|
|
| |
See https://github.com/WebAssembly/extended-const
|
|
|
|
|
|
|
| |
* use [[noreturn]] available since C++11 instead of compiler-specific attributes
* replace deprecated std::is_pod with is_trivial&&is_standard_layout (also available since C++11/14)
* explicitly capture this in [=] lambdas
* extra const functions in FeatureSet, fix implicit cast warning by using the features field directly
* Use CMAKE_CXX_STANDARD to ensure the C++ standard parameter is set on all targets, remove manual compiler flag workaround.
|
|
|
|
|
|
| |
Export an object with a `.value` property like the wasm JS API does
in browsers, and implement them with a getter and setter.
Fixes #4522
|
|
|
|
|
|
|
| |
When copying a MemorySize or MemoryGrow instruction (e.g. for inlining),
transfer the memory type also to the copy. Otherwise it will always be
i32, even if memory64 should be used.
This fixes issue #4530.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Merge similar functions that only differs constant values (like immediate
operand of const and call insts) by parameterization.
Performing this pass at post-link time can merge more functions across
objects. Inspired by Swift compiler's optimization which is derived from
LLVM's one:
https://github.com/apple/swift/blob/main/lib/LLVMPasses/LLVMMergeFunctions.cpp
https://github.com/llvm/llvm-project/blob/main/llvm/docs/MergeFunctions.rst
The basic ideas here are constant value parameterization and direct callee
parameterization by indirection.
Constant value parameterization is like below:
;; Before
(func $big-const-42 (result i32)
[[many instr 1]]
(i32.const 44)
[[many instr 2]]
)
(func $big-const-43 (result i32)
[[many instr 1]]
(i32.const 45)
[[many instr 2]]
)
;; After
(func $byn$mgfn-shared$big-const-42 (result i32)
[[many instr 1]]
(local.get $0) ;; parameterized!!
[[many instr 2]]
)
(func $big-const-42 (result i32)
(call $byn$mgfn-shared$big-const-42
(i32.const 42)
)
)
(func $big-const-43 (result i32)
(call $byn$mgfn-shared$big-const-42
(i32.const 43)
)
)
Direct callee parameterization is similar to the constant value parameterization,
but it parameterizes callee function i by ref.func instead. Therefore it is enabled
only when reference-types and typed-function-references features are enabled.
I saw 1 ~ 2 % reduction for SwiftWasm binary and Ruby's wasm port
using wasi-sdk, and 3 ~ 4.5% reduction for Unity WebGL binary when -Oz.
|
|
|
|
| |
We were missing this particular case, which we can in fact handle
when the cast is static.
|
|
|
|
| |
Instead of just reporting the type index that causes an error when building
types, report the name of the responsible type when parsing the text format.
|
|
|
|
|
| |
Introduce static consts with PassOptions Defaults.
Add assertion to verify that the default options are the Os options.
Also update the text in relevant tests.
|
| |
|
|
|
|
|
| |
Allow IndexedTypeNameGenerator to be configured with a custom prefix and also
allow it to be parameterized with an explicit fallback generator. This allows
multiple IndexedTypeNameGenerators to be composed together, for example.
|
|
|
|
|
|
|
| |
Add an option for running the asyncify transformation on the primary module
emitted by wasm-split. The idea is that the placeholder functions should be able
to unwind the stack while the secondary module is asynchronously loaded, then
once the placeholder functions have been patched out by the secondary module the
stack should be rewound and end up in the correct secondary function.
|
|
|
|
|
|
|
| |
Add a new fuzz checker to wasm-type-fuzzer that builds copies of the originally
built types, randomly selecting for each child type from all potential sources,
including both the originally built types and the not-yet-built duplicate types.
After building the new types, check that they are indeed identical to the old
types, which means that nothing has gone wrong with canonicalization.
|
| |
|
|
|
|
|
|
|
|
|
| |
We were already eagerly canonicalizing basic HeapTypes when building types so
the more complicated canonicalization algorithms would not have to handle
noncanonical heap types, but we were not doing the same for Types. Equirecursive
canonicalization was properly handling noncanonical Types everywhere, but
isorecursive canonicalization was not. Rather than update isorecursive
canonicalization in multiple places, remove the special handling from
equirecursive canonicalization and canonicalize types in a single location.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The previous printing system in the Types API would print the full recursive
structure of a Type or HeapType with special markers using de Bruijn indices to
avoid infinite recursion and a separate special marker for when the size
exceeded an arbitrary upper limit. In practice, the types printed by that system
were not human readable, so all that complexity was not useful.
Replace that system with a new system that always emits a HeapType name rather
than recursing into the structure of inner HeapTypes. Add methods for printing
Types and HeapTypes with custom HeapType name generators. Also add a new
wasm-type-printing.h header with off-the-shelf type name generators that
implement simple naming schemes sufficient for tests and the type fuzzer.
Note that these new printing methods and the old printing methods they augment
are not used for emitting text modules. Printing types as part of expressions
and modules is handled by separate code in Print.cpp and the printing API
modified in this PR is mostly used for debugging. However, the new printing
methods are general enough that Print.cpp should be able to use them as well, so
update the format used to print types in the modified printing system to match
the text format in anticipation of making that change in a follow-up PR.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Validating nominally declared supertypes depends on being able to test type
equality, which in turn depends on the compared types having already been
canonicalized. Previously we validated supertypes before canonicalization, so
validation would fail in cases where it should have succeeded. Fix the bug by
canonicalizing first. This means that the global type store can now end up
holding invalid types, but those types will never be exposed to the user, so
that's not a huge problem.
Also fix an unrelated bug that was preventing the test from passing, which is
that supertypes were being hashed and compared without the special logic for
detecting self-references. This bug preventing the equivalent recursion groups
in the test from being deduplicated.
|
|
|
|
| |
This makes it easier to get an overview of what methods exist by looking at the
shorter struct definition.
|
|
|
|
|
|
|
|
|
|
| |
Add support for isorecursive types to wasm-fuzz-types by generating recursion
groups and ensuring that children types are only selected from candidates
through the end of the current group. For non-isorecursive systems, treat all
the types as belonging to a single group so that their behavior is unchanged.
Also fix two small bugs found by the fuzzer: LUB calculation was taking the
wrong path for isorecursive types and isorecursive validation was not handling
basic heap types properly.
|