| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
|
|
|
|
|
|
|
| |
Grouping all references together makes it easier for baseline compilers to
zero out memory (as the zeroing out may be different for MVP types vs.
references).
This puts all references together, either at the start or the end. As a
heuristic for that we see if the first local is a reference. As the optimizer
will sort locals by frequency, this ensures that the most-frequent local
stays in index 0.
Fixes #4773. See more details there
|
| |
|
|
|
|
|
| |
This is more work than a typical instruction because it also adds a new section:
all the (string.const "foo") strings are put in a new "strings" section in the binary, and
the instructions refer to them by index.
|
| |
|
| |
|
| |
|
| |
|
|
|
|
|
|
| |
This is the first instruction from the Strings proposal.
This includes everything but interpreter support.
|
|
|
| |
This just moves code around and adds comments.
|
|
|
|
|
|
|
|
| |
This starts to implement the Wasm Strings proposal
https://github.com/WebAssembly/stringref/blob/main/proposals/stringref/Overview.md
This just adds the types.
|
|
|
|
|
|
|
|
|
|
|
| |
Nominal types don't make much sense without GC, and in particular trying to emit
them with typed function references but not GC enabled can result in invalid
binaries because nominal types do not respect the type ordering constraints
required by the typed function references proposal. Making this change was
mostly straightforward, but required fixing the fuzzer to use --nominal only
when GC is enabled and required exiting early from nominal-only optimizations
when GC was not enabled.
Fixes #4756.
|
|
|
|
|
|
|
| |
`controlFlowDepth` is a variable used to print `delegate`'s target. When
printing nested blocks, we increase `controlFlowDepth` by the number of
nested blocks at once. But we should decrement it as we finish each
block, rather than decrease by the number of nested blocks at once,
because we need correct `controlFlowDepth` within nested blocks.
|
|
|
| |
This avoids hitting an assertion.
|
|
|
|
|
|
|
|
|
|
|
| |
(#4749)
(ref.eq
(local.tee $x (..))
(local.get $x)
)
That will definitely return 1. Before this PR the side effects of tee stopped us
from optimizing.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
#4748 regressed us in some cases, because it removed casts first:
(ref.is_func
(ref.as_func
(local.get $anyref)))
If the cast is removed first, and the local has no useful type info, then
we'd have removed the cast but could not remove the ref.is. But
the ref.is could be optimized to 1, as it must be a func - the type
info proves it thanks to the cast. To avoid this, remove casts after
everything else.
|
| |
|
|
|
|
|
|
| |
(#4748)
Comparing references does not depend on the cast, so if we are ignoring
traps in traps-never-happen mode then we can remove them.
|
|
|
|
|
|
|
|
|
| |
Parse struct and array type definitions along with field names. Only the most
basic definitions are parsed for now; subtype definitions (both nominal
prototype and standard formats) and recursion groups are left to follow-on PRs.
Since there is no official standard for the text format for GC type definitions,
attempt to define a grammar that allows abbreviations that we already use
widely, such as making `(field ... )` optional except for named fields.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* Updating wasm.h/cpp for DataSegments
* Updating wasm-binary.h/cpp for DataSegments
* Removed link from Memory to DataSegments and updated module-utils, Metrics and wasm-traversal
* checking isPassive when copying data segments to know whether to construct the data segment with an offset or not
* Removing memory member var from DataSegment class as there is only one memory rn. Updated wasm-validator.cpp
* Updated wasm-interpreter
* First look at updating Passes
* Updated wasm-s-parser
* Updated files in src/ir
* Updating tools files
* Last pass on src files before building
* added visitDataSegment
* Fixing build errors
* Data segments need a name
* fixing var name
* ran clang-format
* Ensuring a name on DataSegment
* Ensuring more datasegments have names
* Adding explicit name support
* Fix fuzzing name
* Outputting data name in wasm binary only if explicit
* Checking temp dataSegments vector to validateBinary because it's the one with the segments before we processNames
* Pass on when data segment names are explicitly set
* Ran auto_update_tests.py and check.py, success all around
* Removed an errant semi-colon and corrected a counter. Everything still passes
* Linting
* Fixing processing memory names after parsed from binary
* Updating the test from the last fix
* Correcting error comment
* Impl kripken@ comments
* Impl tlively@ comments
* Updated tests that remove data print when == 0
* Ran clang format
* Impl tlively@ comments
* Ran clang-format
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This pulls out the core PossibleContents and ContentOracle classes from the
very large #4598, making a smaller PR that can be reviewed first. This includes
unit tests for the code, but comprehensive testing will only appear in the later
PR, when a new pass is added that uses all this.
PossibleContents tracks the possible contents at particular locations in the
program. It can track constant values as well as "this must contain this
exact type", which is more than wasm itself can indicate.
*Location structs are provided to declare locations in the wasm, like the
location of a local or of a function argument.
ContentOracle analyzes the entire program, and can then map a Location
to the PossibleContents there, which a later pass will use to optimize.
|
|
|
|
|
|
|
|
| |
We emit nominal types as a single large recursion group, but this produces
invalid modules when --nominal or --hybrid was used without GC enabled. Fix the
bug by always emitting types as though they were structural (i.e. without
recursion groups) when GC is not enabled.
Fixes #4723.
|
|
|
|
|
|
|
| |
This code was apparently not updated when we added multi-table support,
and still had the old hardcoded index 0.
Fixes #4711
|
|
|
|
|
|
|
|
|
| |
This pass helps on at least one Java microbenchmark in a clear way. Real-world data
is mixed, with no obvious benefit. But it does optimize 819 callsites on the real-world
14 MB J2Wasm binary, so we may find it helps if/when we run into those code paths.
On that binary (the biggest we have for GC) this pass runs in 0.12 seconds, so there
is very little downside to enabling it. It is a fast linear-time operation.
|
|
|
|
| |
Apply cleanups suggested by aheejin in post-merge code review of previous
parser PRs.
|
| |
|
| |
|
|
|
|
| |
Spec and VM support for that is not yet stable (atm VMs do not allow complex user-
defined types to be passed around).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Equirecursive LUB calculations potentially require building new recursive heap
types that did not already exist in the system, so they have a complicated code
path that uses a TypeBuilder to construct a LUB from the ground up. In contrast,
nominal and isorecursive LUB calculations never introduce new heap types, so
computing their LUBs is much simpler. Previously we were using the same code
path with the TypeBuilder for all type systems out of convenience, but this
commit factors out the LUB calculations for nominal and isorecursive types into
a separate code path that does not use a TypeBuilder.
Not only should this make LUB calculations faster for GC workloads, it also
avoids a mysterious race condition during parallel LUB calculations with
isorecursive types that resulted in a temporary type escaping from one thread
and being used-after-free from another thread. It would be good to fix that bug
properly, but it is very difficult to investigate. Sweeping it under the rug
instead is the best trade off for now.
Fixes #4719.
|
|
|
|
|
|
| |
Begin implementing the second phase of parsing, parsing of type definitions.
Extend `valtype` to parse both user-defined and built in ref types, add `type`
as a top-level module field, and implement parsers for params, results, and
functype definitions.
|
|
|
|
|
|
|
|
|
|
|
| |
Implement the basic infrastructure for the full WAT parser with just enough
detail to parse basic modules that contain only imported globals. Parsing
functions correspond to elements of the grammar in the text specification and
are templatized over context types that correspond to each phase of parsing.
Errors are explicitly propagated via `Result<T>` and `MaybeResult<T>` types.
Follow-on PRs will implement additional phases of parsing and parsing for new
elements in the grammar.
|
|
|
|
| |
Otherwise when a type is only used on a global, it will be incorrectly omitted
from the output.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
In GSI we look for a read of a global in a situation like this:
$global1: value1
$global2: value2
(struct.get $Type (ref))
If global inference shows this get must be of either $global1 or $global2, then we
can optimize to this:
(ref) == $global1 ? value1 : value2
We focus on the case of two values because 1 is handled by other passes, and >2
makes the tradeoffs less clear.
However, a simple extension is the case where there are more than 2 globals, but
there are only two values, and one value is unique to one global:
$global1: valueA
$global2: valueB
$global3: valueA
=>
(ref) == $global2 ? valueB : valueA
We can still use a single comparison here, on the global that has the
unique value. Then the else will handle all the other globals.
This increases the cases that GSI can optimize J2Wasm output by over 50%.
|
|
|
|
|
| |
Update the opcodes for all relaxed SIMD instructions and remove the unsigned dot
product instructions that are no longer in the proposal.
|
|
|
|
|
|
| |
Similar to #4004 but for 32-bit integers
i32(x) << 24 >> 24 ==> i32.extend8_s(x)
i32(x) << 16 >> 16 ==> i32.extend16_s(x)
|
|
|
|
|
|
|
|
| |
We have some possible use cases for this pass, and so are restoring
it.
This reverts the removal in #3261, fixes compile errors in internal API
changes since then, and flips the direction of the stack for the
wasm backend.
|
|
|
|
|
|
|
|
| |
BinaryenModulePrintStackIR: similar to BinaryenModulePrint
BinaryenModuleWriteStackIR: similar to BinaryenModuleWriteText
BinaryenModuleAllocateAndWriteStackIR: similar to BinaryenModuleAllocateAndWriteText
|
|
|
|
|
|
|
|
| |
#4659 adds a testcase with an import of (ref $struct). This could cause an error in
the fuzzer, since it wants to remove imports (because the various fuzzers cannot pass
in custom imports - they want to just run the wasm). When it tries to remove that
import it tries to create a constant for a struct reference, and fails. To fix that, add
enough support to create structs and arrays at least in the simple case where all their
fields are defaultable.
|
|
|
| |
This just moves code around + adds assertions.
|
|
|
|
|
|
|
|
|
|
|
|
| |
Add methods to `Token` for determining whether the token can be interpreted as a
particular token type, returning the interpreted value as appropriate. These
methods perform additional bounds checks for integers and NaN payloads that
could not be done during the initial lexing because the lexer did not know what
the intended token type was. The float methods also reinterpret integer tokens
as floating point tokens since the float grammar is a superset of the integer
grammar and inject the NaN payloads into parsed NaN values.
Move all bounds checking to these new classifier functions to have it in one
place.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This optimizes constants in the megamorphic case of two: when we
know two function references are possible, we could in theory emit this:
(select
(ref.func A)
(ref.func B)
(ref.eq
(..ref value..) ;; globally, only 2 things are possible here, and one has
;; ref.func A as its value, and the other ref.func B
(ref.func A))
That is, compare to one of the values, and emit the two possible values there.
Other optimizations can then turn a call_ref on this select into an if over
two direct calls, leading to devirtualization.
We cannot compare a ref.func directly (since function references are not
comparable), and so instead we look at immutable global structs. If we
find a struct type that has only two possible values in some field, and
the structs are in immutable globals (which happens in the vtable case
in j2wasm for example), then we can compare the references of the struct
to decide between the two values in the field.
|
|
|
|
| |
This moves it out of the validator so it can be used elsewhere. It will be
used in #4685
|
|
|
|
|
|
|
|
|
| |
SimplifyLocals (#4705)
Followup to #4703, this also handles the case where there is a non-
nullable local.set in the value of a nullable one, which we also cannot
optimize.
Fixes #4702
|
|
|
|
|
|
|
| |
Binaryen will not change dominance in SimplifyLocals, however, the current spec's
notion of dominance is simpler than ours, and we must not optimize certain cases in
order to still validate. See details in the comment and test.
Helps #4702
|
|
|
|
|
|
| |
The first way to should detect this is if the main function actually
doesn't take any params. They we fallback to looking deeper.
In preparation for https://reviews.llvm.org/D75277
|
|
|
|
|
|
|
|
|
| |
This part to finalize is currently not used and was added in preparation
for https://reviews.llvm.org/D75277.
However, the better solution to dealing with this alternative name for
main is on the emscripten side. The main reason for this is that
doing the rename here in binaryen would require finalize to always
re-write the binary, which is expensive.
|
|
|
|
|
|
|
|
| |
Previously we were tracking whether integer tokens were signed but we did not
differentiate between positive and negative signs. Unfortunately, without
differentiating them, there's no way to tell the difference between an in-bounds
negative integer and a wildly out-of-bounds positive integer when trying to
perform bounds checks for s32 tokens. Fix the problem by tracking not only
whether there is a sign on an integer token, but also what the sign is.
|
| |
|
| |
|
|
|
|
|
|
| |
wat-parser-internal.h was already quite large after implementing just the lexer,
so it made sense to rename it to be lexer-specific and start a new file for the
higher-level parser. Also make it a proper .cpp file and split the testable
interface out into wat-lexer.h.
|
|
|
|
|
|
| |
calls (#4660)
This extends the existing call_indirect code to do the same for call_ref,
basically. The shared code is added to a new helper utility.
|