| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
| |
And use it to port the very simple untee test.
|
|
|
|
|
|
| |
In conjunction with the `foreach` tool, allows autogenerating checks for lit
tests containing multiple modules. Supporting this will help automatically port
existing bespoke wast tests to be lit tests, since many of those tests contain
multiple modules per file.
|
|
|
|
|
|
|
| |
We only tested that feature on the text format. For binary support, the reader needs
to know that the feature is enabled, so that it allows non-nullable locals in that
case (i.e., does not apply the workarounds to remove them).
Fixes #3953
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
As suggested in
https://github.com/WebAssembly/binaryen/pull/3955#issuecomment-871016647
This applies commandline features first. If the features section is present, and
disallows some of them, then we warn. Otherwise, the features can combine
(for example, a wasm may enable feature X because it has to use it, and a user
can simply add the flag for feature Y if they want the optimizer to try to use it;
both flags will then be enabled).
This is important because in some cases we need to know the features before
parsing the wasm, in the case that the wasm does not use the features section.
In particular, non-nullable GC locals have an effect during parsing. (Typed
function references also does, but we found a way to apply its effect all the time,
that is, always use the refined type, and that happened to not break the case
where the feature is disabled - but such a workaround is not possible with
non-nullable locals.)
To make this less error-prone, add a FeatureSet input as a parameter to
WasmBinaryBuilder. That is, when building a module, we must give it the
features to use while doing so.
This will unblock #3955 . That PR will also add a test for the actual usage
of a feature during loading (the test can only be added there, after that PR
unbreaks things).
|
|
|
|
|
|
|
|
| |
Add an --all-items flag to update_lit_checks.py to emit checks for all module
items, not just those that match items in the input. Update two tests to use
generated input with the new flag.
Also, to improve readability, insert an empty line between consecutive checks
for different items.
|
|
|
|
|
|
|
|
|
| |
When using nominal types, func.ref of two functions with identical signatures
but different HeapTypes will yield different types. To preserve these semantics,
Functions need to track their HeapTypes, not just their Signatures.
This PR replaces the Signature field in Function with a HeapType field and adds
new utility methods to make it almost as simple to update and query the function
HeapType as it was to update and query the Function Signature.
|
|
|
|
|
|
|
|
|
|
| |
That traversal did not mention BrOn, which led to it doing incorrect work in
SimplifyLocals.
Also add assertions at the end, that aim to prevent future issues.
The rest of the fix is to make SimplifyLocals not assume that things
are a Switch if they are not an If/Block/etc., so that we don't crash
on a BrOn.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The code for printing and emitting the experimental nominal type constructors
added in #3933 assumes that supertypes were only returned from `getSuperType`
when nominal typing was enabled. `getSuperType` in turn was assuming that the
supertype field would only be set if nominal typing was enabled, but this was
not the case. This bug caused use-after-free errors because equirecursive
canonicalization left the supertype field pointing to a temporary HeapTypeInfo
that would be freed at the end of parsing but then accessed during module
writing.
To fix the issue, only set `supertype` if nominal typing is enabled, as
originally intended.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Instead of only generating checks for functions, generate checks for all named top-level module items, such as types, tags, tables, and memories. Because module items can be in different orders in the input and the output but FileCheck checks must follow the order of the output, we need to be slightly clever about when we emit the checks. Consider these types in the input file:
```
(type $A (...))
(type $B (...))
```
If their order is reversed in the output file, then the checks for $B need to be emitted before the checks for $A, so the resulting module will look like this:
```
;; CHECK: (type $B (...))
;; CHECK: (type $A (...))
(type $A (...))
(type $B (...))
```
Rather than this, which looks nicer but would be incorrect:
```
;; CHECK: (type $A (...))
(type $A (...))
;; CHECK: (type $B (...))
(type $B (...))
```
|
|
|
|
|
|
|
|
|
| |
PostEmscripten will turn an invoke of a constant function
pointer index into a direct call. However, due to UB it is possible to
have invalid function pointers, and we should not crash on that
(and do nothing to optimize, of course).
Mostly whitespace; to avoid deep nesting, I added more
early returns.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Previously, ref.func instructions would be assigned the canonical (i.e. first
parsed) heap type for the referenced function signature rather than the HeapType
actually specified in the type definition. In nominal mode, this could cause
validation failures because the types assigned to ref.func instructions would
not be correct.
Fix the problem by tracking function HeapTypes rather than function Signatures
when parsing the text format.
There can still be validation failures when round-tripping modules because
function HeapTypes are not properly preserved after parsing, but that will be
addressed in a follow-up PR.
|
|
|
|
|
|
|
|
|
| |
This removes `attribute` field from `Tag` class, making the reserved and
unused field known only to binary encoder and decoder. This also removes
the `attribute` parameter from `makeTag` and `addTag` methods in
wasm-builder.h, C API, and Binaryen JS API.
Suggested in
https://github.com/WebAssembly/binaryen/pull/3946#pullrequestreview-687756523.
|
|
|
|
|
|
|
|
| |
This attribute is always 0 and reserved for future use. In Binayren's
unofficial text format we were writing this field as `(attr 0)`, but we
have recently come to the conclusion that this is not necessary.
Relevant discussion:
https://github.com/WebAssembly/exception-handling/pull/160#discussion_r653254680
|
|
|
|
|
|
| |
We don't need to assign a zero value for such locals (and we can't, as no
default value exists for them).
Fixes #3944
|
|
|
|
|
|
|
|
|
|
|
| |
We recently decided to change 'event' to 'tag', and to 'event section'
to 'tag section', out of the rationale that the section contains a
generalized tag that references a type, which may be used for something
other than exceptions, and the name 'event' can be confusing in the web
context.
See
- https://github.com/WebAssembly/exception-handling/issues/159#issuecomment-857910130
- https://github.com/WebAssembly/exception-handling/pull/161
|
|
|
|
|
|
|
|
|
|
| |
RedundantSetElimination checks if a local already has the default
value when we assign the default to it. For a non-nullable local, however,
there is no initial value - it cannot be used before it is assigned to. So
we just need to skip such locals, and not assume they contain a default
value we can compare against (we would assert on trying to create a
"zero" for such a non-nullable type).
Fixes #3942
|
|
|
|
|
|
|
|
| |
This is a useful alternative to extract-function when you don't know the
function's name.
Also moves the extract-function tests to be lit tests and re-uses them as
extract-function-index tests.
|
|
|
|
|
|
|
| |
The major drawback of lit tests is that so far they have only supported a single
module per test file. This commit adds a new utility script that splits an input
file into multiple files and runs a command on each of them, giving lit tests a
simple way to test multiple modules per file.
|
|
|
|
|
| |
Improve the legibility of the option documentation by adding vertical space
between options. This is particularly helpful to delimit the text of options
with longer explanations.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Assertions were previously parsed by replacing "invoke" with "call" and using
the normal s-expr parser. The parseCall method of the s-expr parser uses the
call target to look up the correct signature on the module, but the invoke
targets in assertions use export names rather than internal function names, so
the signature lookups were inserting new bogus entries with default values.
This issue didn't seem to cause any big problems before, but #3935 turns it into
a hard error because the default `HeapType` does not have an associated
signature.
Fix the problem (at least in the common case of trivial arguments and expected
results) by manually construction a `Call` expression rather than depending on
the s-expr parser to construct it.
|
|
|
|
|
|
|
|
|
|
| |
This is the same as rtt.sub, but creates a "new" rtt each time. See
https://docs.google.com/document/d/1DklC3qVuOdLHSXB5UXghM_syCh-4cMinQ50ICiXnK3Q/edit#
The old Literal implementation of rtts becomes a little more complex here,
as it was designed for the original spec where only structure matters. It may
be worth a complete redesign there, but for now as the spec is in flux I think
the approach here is good enough.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This adds a new feature flag, GCNNLocals that enables support for
non-nullable locals. No validation is applied to check that they are
actually assigned before their use yet - this just allows experimentation
to begin.
This feature is not enabled by default even with -all. If we enabled it,
then it would take effect in most of our tests and likely confuse current
users as well. Instead, the flag must be opted in explicitly using
--enable-gc-nn-locals. That is, this is an experimental feature flag,
and as such must be explicitly enabled. (Once the spec stabilizes,
we will remove the feature anyhow when we implement the
final status of non-nullability. )
|
|
|
|
|
|
|
| |
Adds a `--nominal` option to switch the type machinery from equirecursive to
nominal. Implements binary and text parsing and emitting of nominal types using
new type constructor opcodes and an `(extends $super)` text syntax extension.
When not in nominal mode, these extensions will still be parsed but will not
have any effect and will not be used when emitting.
|
|
|
|
|
|
| |
The new instruction emits a file containing a map between placeholder index and
the name of the split out function that placeholder is replacing in the table.
This map is intended to be useful for debugging, as discussed in
https://github.com/emscripten-core/emscripten/issues/14330.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Add methods to the TypeBuilder interface to declare subtyping relationships
between the built types. These relationships are validated and recorded globally
as part of type building. If the relationships are not valid, a fatal error is
produced. In the future, it would be better to report the error to the
TypeBuilder client code, but this behavior is sufficient for now. Also updates
SubTyper and TypeBounder to be aware of nominal mode so that subtyping and LUBs
are correctly calculated.
Tests of the failing behavior will be added in a future PR that exposes this
functionality to the command line, since the current `example` testing
infrastructure cannot handle testing fatal errors.
|
|
|
|
| |
This removes the restriction that `try` should have at least one
`catch`/`catch_all`/`delegate`. See WebAssembly/exception-handling#157.
|
| |
|
|
|
|
|
|
| |
The noteBreak call was in the wrong place, causing us to not note breaks
from BrOnNull for example, which could make validation miss errors.
Noticed in #3926
|
|
|
|
| |
This converts most EH tests in test/passes into test/lit/passes. Fixed
some files to follow 2-space indentation and improved some comments.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
In nominal mode, HeapType constructors besides the Signature constructor always
produce fresh types distinct from any previously created types. The HeapType
constructor that takes a Signature maintains its previous behavior of
constructing a canonical representative of the given signature because it is
used frequently throughout the code base and never in a situation that would
benefit from creating a fresh type. It is left as future work to clean up this
discrepancy between the Signature HeapType constructor and other HeapType
constructors.
TypeBuilder skips shape and global canonicalization in nominal mode and always
creates a fresh type for each of its entries. For this to work without any
canonicalization, the TypeBuilder allocates temporary types on the global Type
store and does not support building basic HeapTypes in nominal mode.
The new mode is not available in any of the Binaryen tools yet because it is
still missing critical functionality like the ability to declare subtyping
relations and correctly calculate LUBs. This functionality will be implemented
in future PRs.
|
|
|
| |
fixes part of #3906
|
|
|
|
|
|
|
| |
Given a list of profiles for the same module, --merge-profiles produces a single
combined profile the contains the minimum timestamp among the original profiles
for each function. When verbose output is enabled, also emit a message for each
profile that could individually be removed without affecting the set of
functions in the combined profile, as suggested in #3912.
|
|
|
|
|
|
| |
They are basically the flip versions. The only interesting part in the impl is that their
returned typed and sent types are different.
Spec: https://docs.google.com/document/d/1DklC3qVuOdLHSXB5UXghM_syCh-4cMinQ50ICiXnK3Q/edit
|
|
|
|
|
|
| |
In anticipation of adding a third wasm-split mode, merge-profiles, in addition
to the existing split and instrument modes, refactor wasm-split's option
validation to let the valid modes be declared for each option. This approach is
more scalable and robust than the ad-hoc validation we had previously.
|
|
|
|
|
|
|
|
|
| |
wasm-split would previously use internal function names to create the external
names of the functions that are newly exported from the primary module to be
imported into the secondary module. When the input module contains full function
names (as is commonly the case when emitting symbol maps), this caused the
function names to be preserved as the export names, even when names are
otherwise being stripped. To save on code size and properly anonymize functions,
generate minimal export names when debuginfo is disabled instead.
|
|
|
|
|
|
|
|
| |
Spec for it is here:
https://docs.google.com/document/d/1DklC3qVuOdLHSXB5UXghM_syCh-4cMinQ50ICiXnK3Q/edit#
Also reorder some things in wasm.h that were not in the canonical order (that has
no effect, but it is confusing to read).
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Without adding logic there, it simply ignored the branch, which could
lead to bad optimizations (thinking code is unreachable when it was).
There isn't a trivial way to add a static error to force us to add new
classes to CFGWalker. But this PR generalizes the code there to
handle all branches and all unreachable instructions in a generic
way. The only thing we'll need to remember to do in the future is to
add control flow structures. (And normally the fuzzer should quickly
find such bugs, but we don't have full fuzzing enabled for GC yet.)
Fixes #3907
|
|
|
|
|
|
| |
Even when other names are stripped, it can be useful for wasm-split to preserve
the module name so that the split modules can be differentiated in stack traces.
Adding this option to wasm-split requires adding similar options to ModuleWriter
and WasmBinaryWriter.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
`Walker::TaskFunc` has changed from a function pointer to
`std::function` in #3494, mainly to make the EH support for `CFGWalker`
easier. We didn't notice much performance difference then, but it was
recently reported that it creased binaryen.js code size and performance.
This changes `Walker::TaskFunc` back to a function pointer and does a
little more work to manage catch index in `CFGWalker` side.
Hopefully fixes #3857.
|
|
|
|
|
|
|
|
| |
Imported functions come first when modules are emitted, so to ensure the
function indices are correct, they need to come first in the symbol maps. We
never noticed this bug before because imported functions are always the first
functions when a module is parsed, so the bug never mattered in practice.
However, wasm-split adds new imported functions after parsing and these were
causing the symbol map indices to be incorrect.
|
|
|
|
|
| |
The new option emits a symbol map file for each of the split modules. The file
names are created by appending ".symbols" to each of the Wasm output file
names.
|
|
|
|
|
|
|
|
|
| |
As found in #3682, the current implementation of type ordering is not correct,
and although the immediate issue would be easy to fix, I don't think the current
intended comparison algorithm is correct in the first place. Rather than try to
switch to using a correct algorithm (which I am not sure I know how to
implement, although I have an idea) this PR removes Type ordering entirely. In
places that used Type ordering with std::set or std::map because they require
deterministic iteration order, this PR uses InsertOrdered{Set,Map} instead.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Previously we would try to stop using the allocation as much as possible,
for example not writing it to locals any more, and leaving it to other passes
to actually remove it (and remove gets of those locals etc.). This seemed
simpler and more modular, but does not actually work in some cases as
the fuzzer has found. Specifically, if we stop writing our allocation to
locals, then if we do a (ref.as_non_null (local.get ..)) of that, then we
will trap on the null present in the local.
Instead, this changes our rewriting to do slightly more work, but it is
simpler in the end. We replace the allocation with a null, and replace
all the places that use it accordingly, for example, updating types to be
nullable, and removing RefAsNonNulls, etc. This literally gets rid of the
allocation and all the places it flows to (leaving less for other passes to
do later).
|
|
|
|
| |
Similar to struct operations, if the reference is unreachable then we do
not know the heap type, and cannot print the full expression.
|
|
|
|
|
|
|
|
|
|
|
| |
If we run a pass that removes DWARF followed by one that could destroy it, then
there is no possible problem - there is nothing left to destroy. We can run the later
pass with no issues (and no warnings).
Also add an assertion on running a pass runner only once. That has always been
the assumption, and now that we track whether the added passes remove debug
info, we need to check it.
Fixes emscripten-core/emscripten#14161
|
|
|
|
|
|
|
|
|
|
| |
wasm-as supports --symbolmap=FOO as an argument. We got a request to
support the same in wasm-opt. wasm-opt does have --print-function-map which
does the same, but as a pass. To unify them, use the new pass arg sugar from
#3882 which allows us to add a --symbolmap pass whose argument can be
set as --symbolmap=FOO. That perfectly matches the wasm-as notation.
For now, keep the old --print-function-map notation as well, to not break
emscripten. After we remove it there we can remove it here.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
We have --pass-arg that allows sending an argument to a pass, like this:
wasm-opt --do-stuff --pass-arg=do-stuff@FUNCTION_NAME
With this PR that is equivalent to this:
wasm-opt --do-stuff=FUNCTION_NAME
That is,one can just give an argument to a pass on the commandline.
This fixes the Optional mode in command-line.h/cpp. That was not
actually used anywhere before this PR.
Also rename --extract-function's pass argument to match it. That is, the usage
used to be
wasm-opt --extract-function --pass-arg=extract@FUNCTION_NAME
Note how the pass name differed from the pass-arg name. This changes it to
match. This is a breaking change, but I doubt this is used enough to justify
any deprecation / backwards compatibility effort, and any usage is almost
certainly manual, and with PR writing it manually becomes easier as one
can do
wasm-opt --extract-function=FUNCTION_NAME
The existing test for that is kept (&renamed), and a new test added to test the
new notation.
This is a step towards unifying the symbol map functionality between
wasm-as and wasm-opt (later PRs will turn the symbol mapping pass into
a pass that receives an argument).
|
|
|
|
|
| |
Without this fix we can segfault, as it has no body.
Fixes #3879
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
If we branch to a block, and there are no other branches or a final
value on the block either, then there is no mixing, and we may be able
to optimize the allocation. Before this PR, all branches stopped us.
To do this, add some helpers in BranchUtils.
The main flow logic in Heap2Local used to stop when we reached a
child for the second time. With branches, however, a child can flow both to
its immediate parent, and to branch targets, and so the proper thing to look
at is when we reach a parent for the second time (which would definitely
indicate mixing).
Tests are added for the new functionality. Note that some existing tests
already covered some things we should not optimize, and so no tests
were needed for them. The existing ones are: $get-through-block,
$branch-to-block.
|