| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
|
|
| |
array.init is like array.new_with_rtt except that it takes
as arguments the values to initialize the array with (as opposed to
a size and an optional initial value).
Spec: https://docs.google.com/document/d/1afthjsL_B9UaMqCA5ekgVmOm75BVFu6duHNsN9-gnXw/edit#
|
|
|
|
| |
interpreter (#4023)
|
|
|
|
| |
(#4027)
|
| |
|
| |
|
| |
|
|
|
|
|
|
|
| |
Like a few other SIMD operations, this i64x2.bitmask had not been implemented in
the interpreter yet. Unlike the others, i64x2.bitmask has type i32 rather than
type v128, so Precompute was not skipping it, leading to a crash, as in
https://github.com/emscripten-core/emscripten/issues/14629. Fix the problem by
implementing i64x2.bitmask in the interpreter.
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
| |
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
|
|
|
|
|
|
|
|
| |
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).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
If we allocate some GC data, and do not let the reference escape, then we can
replace the allocation with locals, one local for each field in the allocation
basically. This avoids the allocation, and also allows us to optimize the locals
further.
On the Dart DeltaBlue benchmark, this is a 24% speedup (making it faster than
the JS version, incidentially), and also a 6% reduction in code size.
The tests are not the best way to show what this does, as the pass assumes
other passes will clean up after. Here is an example to clarify. First, in pseudocode:
ref = new Int(42)
do {
ref.set(ref.get() + 1)
} while (import(ref.get())
That is, we allocate an int on the heap and use it as a counter. Unnecessarily,
as it could be a normal int on the stack.
Wat:
(module
;; A boxed integer: an entire struct just to hold an int.
(type $boxed-int (struct (field (mut i32))))
(import "env" "import" (func $import (param i32) (result i32)))
(func "example"
(local $ref (ref null $boxed-int))
;; Allocate a boxed integer of 42 and save the reference to it.
(local.set $ref
(struct.new_with_rtt $boxed-int
(i32.const 42)
(rtt.canon $boxed-int)
)
)
;; Increment the integer in a loop, looking for some condition.
(loop $loop
(struct.set $boxed-int 0
(local.get $ref)
(i32.add
(struct.get $boxed-int 0
(local.get $ref)
)
(i32.const 1)
)
)
(br_if $loop
(call $import
(struct.get $boxed-int 0
(local.get $ref)
)
)
)
)
)
)
Before this pass, the optimizer could do essentially nothing with this.
Even with this pass, running -O1 has no effect, as the pass is only
used in -O2+. However, running --heap2local -O1 leads to this:
(func $0
(local $0 i32)
(local.set $0
(i32.const 42)
)
(loop $loop
(br_if $loop
(call $import
(local.tee $0
(i32.add
(local.get $0)
(i32.const 1)
)
)
)
)
)
)
All the GC heap operations have been removed, and we just
have a plain int now, allowing a bunch of other opts to run. That
output is basically the optimal code, I think.
|
|
|
|
|
|
|
|
|
|
| |
The logic there would construct the cast value separately for functions and data
(as we must), and then in an attempt to share code, would then check if the
cast succeed or not (and if not, do nothing with the cast value).
But this was wrong, as in some weird casts (like a struct to a function) we
cannot construct a valid cast value, and we error there. Instead, check if the
cast works first, once we know enough to do so, and only then construct the
cast value if so.
|
|
|
|
|
|
| |
We truncated and extended packed values in get and set, but
not during initialization.
Found by the fuzzer.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Binaryen allows optimizing functions in function-parallel passes while the
module is still being built, that is, while not all the other functions have
even been added to the module yet. Since the removal of asm2wasm that
has not been heavily tested, but the fuzzer found a closely related bug:
in passes like inlining-optimizing, that inline and then optimize the
functions we inlined into, the mechanism for optimizing only the relevant
functions is to create a module with only some of them. (We only want to
optimize the relevant ones, that we inlined into, because this happens
after the main optimization pipeline - we don't want to re-optimize all the
functions if we just inlined into one of them.)
The specific bug here is that ref.cast of a funcref looked up the target
function on the module (in order to get its signature, to see if the cast
has the right RTT for it). The fix is to return a nonconstant flow in that
case, as it is something we cannot precompute. (This does mean we
may miss some optimization opportunities, but as in the case of where
we optimize functions before the module is fully built up, we do still
get 99% of function-local optimizations that way, and a subsequent
round of full optimizations can be done later if necessary.)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
#3792 added support for module linking and (register command to
wasm-shell, but forgot about three problems:
- Splitting spec tests prevents linking test modules together.
- Registered modules may still be used in assertions or an invoke
- Modules may re-export imported objects
This PR appends transformed modules after binary checks to a spec.wast
file, plus assertion tests and register commands. Then runs wasm-shell
on the whole file. It also keeps both the module name and its registered
name available in wasm-shell for use in shell commands and linked
modules. Furthermore, it correctly finds the module where an object is
defined even if it is imported and re-exported several times.
The updated version of imports.wast spec test is enabled to verify the
fixes.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This is a rewrite of the wasm-shell tool, with the goal of improved
compatibility with the reference interpreter and the spec test suite.
To facilitate that, module instances are provided with a list of linked
instances, and imported objects are looked up in the correct instance.
The new shell can:
- register and link modules using the (register ...) command.
- parse binary modules with the syntax (module binary ...).
- provide the "spectest" module defined in the reference interpreter
- assert instantiation traps with assert_trap
- better check linkability by looking up the linked instances in
- assert_unlinkable
It cannot call external function references that are not direct imports.
That would require bigger changes.
|
|
|
|
|
|
|
|
|
| |
Host limitations are arbitrary and can be modified by optimizations, so
ignore them. For example, if the optimizer removes allocations then a
host limit on an allocation error may vanish. Or, an optimization that
removes recursion and replaces it with a loop may avoid a host limit
on call depth (that is not done currently, but might some day).
This removes a class of annoying false positives in the fuzzer.
|
|
|
|
|
|
|
|
|
| |
Renames the SIMD instructions
* LoadExtSVec8x8ToVecI16x8 -> Load8x8SVec128
* LoadExtUVec8x8ToVecI16x8 -> Load8x8UVec128
* LoadExtSVec16x4ToVecI32x4 -> Load16x4SVec128
* LoadExtUVec16x4ToVecI32x4 -> Load16x4UVec128
* LoadExtSVec32x2ToVecI64x2 -> Load32x2SVec128
* LoadExtUVec32x2ToVecI64x2 -> Load32x2UVec128
|
|
|
|
|
|
|
|
|
| |
Renames the SIMD instructions
* LoadSplatVec8x16 -> Load8SplatVec128
* LoadSplatVec16x8 -> Load16SplatVec128
* LoadSplatVec32x4 -> Load32SplatVec128
* LoadSplatVec64x2 -> Load64SplatVec128
* Load32Zero -> Load32ZeroVec128
* Load64Zero -> Load64ZeroVec128
|
|
|
|
|
|
|
|
|
|
|
| |
Adds C/JS APIs for the SIMD instructions
* Load8LaneVec128 (was LoadLaneVec8x16)
* Load16LaneVec128 (was LoadLaneVec16x8)
* Load32LaneVec128 (was LoadLaneVec32x4)
* Load64LaneVec128 (was LoadLaneVec64x2)
* Store8LaneVec128 (was StoreLaneVec8x16)
* Store16LaneVec128 (was StoreLaneVec16x8)
* Store32LaneVec128 (was StoreLaneVec32x4)
* Store64LaneVec128 (was StoreLaneVec64x2)
|
|
|
|
|
|
|
|
|
|
| |
(#3559)
The spec does not mention traps here, but this is like a JS VM trapping on
OOM - a runtime limitation is reached.
As these are not specced traps, I did not add them to effects.h. Note how
as a result the optimizer happily optimizes into a nop an unused allocation of an
array of size unsigned(-1), which is the behavior we want.
|
| |
|
|
|
|
| |
Also removes experimental SIMD instructions that were not included in the final
spec proposal.
|
|
|
|
|
|
| |
This PR adds support for `ref.null t` as a valid element segment
item. The abbreviated format of `(elem ... func $f $g...)` is kept in
both printing and binary emitting if all items are `ref.func`s. Public
APIs aren't updated in this PR.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
After this PR we still do not support non-nullable locals. But we no longer
turn all types into nullable upon load. In particular, we support non-nullable
types on function parameters and struct fields, etc. This should be enough to
experiment with optimizations in both binaryen and in VMs regarding non-
nullability (since we expect that optimizing VMs can do well inside functions
anyhow; it's non-nullability across calls and from data that the VM can't be
expected to think about).
Let is handled as before, by lowering it into gets and sets. In addition, we
turn non-nullable locals into nullable ones, and add a ref.as_non_null on
all their gets (to keep the type identical there). This is used not just for
loading code with a let but also is needed after inlining.
Most of the code changes here are removing FIXMEs for allowing
non-nullable types. But there is also code to handle the issues mentioned
above.
Most of the test updates are removing extra nulls that we added before
when we turned all types nullable. A few tests had actual issues, though,
and also some new tests are added to cover the code changes here.
|
|
|
|
|
|
|
|
|
|
|
| |
Passive element segments do not belong to any table, so the link between
Table and elem needs to be weaker; i.e. an elem may have a table in case
of active segments, or simply be a collection of function references in
case of passive/declarative segments.
This PR takes Table::Segment out and turns it into a first class module
element just like tables and functions. It also implements early support
for parsing, printing, encoding and decoding passive/declarative elem
segments.
|
|
|
| |
This as a consequence of https://reviews.llvm.org/D95651
|
|
|
| |
And fix errors from such a build.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
I was previously mistaken about `rethrow`'s argument rule and thought
it only counted `catch`'s depth. But it turns out it follows the same
rule `delegate`'s label: the immediate argument follows the same rule as
when computing branch labels, but it only can target `try` labels
(semantically it targets that `try`'s corresponding `catch`); otherwise
it will be a validation failure. Unlike `delegate`, `rethrow`'s label
denotes not where to rethrow, but which exception to rethrow. For
example,
```wasm
try $l0
catch ($l0)
try $l1
catch ($l1)
rethrow $l0 ;; rethrow the exception caught by 'catch ($l0)'
end
end
```
Refer to this comment for the more detailed informal semantics:
https://github.com/WebAssembly/exception-handling/issues/146#issuecomment-777714491
---
This also reverts some of `delegateTarget` -> `exceptionTarget` changes
done in #3562 in the validator. Label validation rules apply differently
for `delegate` and `rethrow` for try-catch. For example, this is valid:
```wasm
try $l0
try
delegate $l0
catch ($l0)
end
```
But this is NOT valid:
```wasm
try $l0
catch ($l0)
try
delegate $l0
end
```
So `try`'s label should be used within try-catch range (not catch-end
range) for `delegate`s.
But for the `rethrow` the rule is different. For example, this is valid:
```wasm
try $l0
catch ($l0)
rethrow $l0
end
```
But this is NOT valid:
```wasm
try $l0
rethrow $l0
catch ($l0)
end
```
So the `try`'s label should be used within catch-end range instead.
|
| |
|
|
|
| |
Adds support for modules with multiple tables. Adds a field for the table name to `CallIndirect` and updates the C/JS APIs accordingly.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
I had completely missed that the spec allows ref.cast etc. of function types,
and not just data. Function types do not have an RTT, unlike GC data, but we
can still cast them. A function reference has the canonical RTT of the signature
for that type, so it's like a simplified case of the GC world, without a hierarchy
of RTTs.
As it turns out, our validation did not rule out rtt.canon of a function type,
nor ref.cast of one, so we unintentionally already had all the support for this
aside from the actual casting, which this PR adds.
The addition is mostly trivial, except that we now need a Module in the base
ExpressionRunner class, so that we can go from a function name to the actual
function. This PR refactors things to allow that.
|
|
|
|
|
|
|
|
| |
As proposed in https://github.com/WebAssembly/simd/pull/395. Note that the other
instructions in the proposal have not been implemented in LLVM or in V8, so
there is no need to implement them in Binaryen right now either. This PR
introduces a new expression class for the new instructions because they uniquely
take an immediate argument identifying which portion of the input vector to
widen.
|
|
|
|
|
|
|
|
|
| |
We added isGCData() before we had dataref. But now there is a clear
parallel of Function vs Data. This PR makes us more consistent there,
renaming isGCData to isData and using that throughout.
This also fixes a bug where the old isGCData just checked if the input
was an Array or a Struct, and ignored the data heap type itself. It is not
possible to test that, however, due to other bugs, so that is deferred.
|
|
|
|
|
|
|
|
|
|
|
| |
This is only partial support, as br_on_null also has an extra optional
value in the spec. Implementing that is cumbersome in binaryen, and
there is ongoing spec discussions about it (see
https://github.com/WebAssembly/function-references/issues/45 ), so
for now we only support the simple case without the default value.
Also fix prefixed opcodes to be LEBs in RefAs, which was noticed here
as the change here made it noticeable whether the values were int8 or
LEBs.
|
|
|
|
|
|
| |
This is different than the other RefAs variants in that it is part of the
typed functions proposal, and not GC. But it is part of GC prototype 3.
Note: This is not useful to us yet as we don't support non-nullable types.
|
|
|
|
|
|
|
|
| |
This expands the existing BrOnCast into BrOn that can also handle the
func/data/i31 variants. This is not as elegant as RefIs / RefAs in that BrOnCast
has an extra rtt field, but I think it is still the best option. We already have optional
fields on Break (the value and condition), so making rtt optional is not odd. And
it allows us to share all the behavior of br_on_* which aside from the cast or the
check itself, is identical - returning the value if the branch is not taken, etc.
|
|
|
|
|
|
|
|
| |
These are similar to is, but instead of returning an i32 answer, they trap on
an invalid value, and return it otherwise.
These could in theory be in a single RefDoThing, with opcodes for both As
and Is, but as the return values are different, that would be a little odd, and
the name would be less clear.
|
| |
|
|
|
|
|
|
|
|
| |
This internal refactoring prepares us for ref.is_func/data/i31, by renaming
the node and adding an "op" field. For now that field must always be "Null"
which means it is a ref.is_null.
This adjusts the C API to match the new IR shape. The high-level JS API
is unchanged.
|
|
|
|
|
|
|
|
|
|
| |
The binary spec
(https://docs.google.com/document/d/1yAWU3dbs8kUa_wcnnirDxUu9nEBsNfq0Xo90OWx6yuo/edit#)
lists `dataref` after `i31ref`, and `dataref` also comes after `i31ref`
in its binary code in the value-increasing order. This reorders these
two in wasm-type.h and other places, although in most of those places
the order is irrelevant.
This also adds C and JS API for `dataref`.
|
|
|
| |
This removes `exnref` type and `br_on_exn` instruction.
|
|
|
|
|
| |
This is not 100% of everything, but is enough to get tests passing, which
includes full binary and text format support, getting all switches to compile
without error, and some additions to InstrumentLocals.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This updates the interpreter for the EH instructions (modulo `delegate`)
to match the new spec. Before we had an `exnref` type so threw a
`Literal` of `exnref` type which contained `ExceptionPackage`. But now
that we don't have `exnref` anymore, so we add the contents of
`ExceptionPackage` to `WasmException`, which is used only for the
`ExpressionRunner` class hierarchy. `exnref` and `ExceptionPackage` will
be removed in a followup CL.
This allows nonzero depths for `rethrow` for now for testing; we
disallowed that for safety measure, but given that there are no passes
that modifies that field, I think the risk is low.
|
|
|
|
| |
As proposed in https://github.com/WebAssembly/simd/pull/383, with opcodes
coordinated with the WIP V8 prototype.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This updates `try`-`catch`-`catch_all` and `rethrow` instructions to
match the new spec. `delegate` is not included. Now `Try` contains not a
single `catchBody` expression but a vector of catch
bodies and events.
This updates most existing routines, optimizations, and tests modulo the
interpreter and the CFG traversal. Because the interpreter has not been
updated yet, the EH spec test is temporarily disabled in check.py. Also,
because the CFG traversal for EH is not yet updated, several EH tests in
`rse_all-features.wast`, which uses CFG traversal, are temporarily
commented out.
Also added a few more tests in existing EH test functions in
test/passes. In the previous spec, `catch` was catching all exceptions
so it was assumed that anything `try` body throws is caught by its
`catch`, but now we can assume the same only if there is a `catch_all`.
Newly added tests test cases when there is a `catch_all` and cases there
are only `catch`es separately.
|
|
|
|
|
| |
The code previously assumed it could always call getGCData, but
that assumes the input is an array or a struct. It could also be an
anyref etc. that contains something other than GC data.
|
|
|
|
| |
As proposed in https://github.com/WebAssembly/simd/pull/352, using the opcodes
used in the LLVM and V8 implementations.
|