summaryrefslogtreecommitdiff
path: root/src/wasm
Commit message (Collapse)AuthorAgeFilesLines
...
* [Wasm GC] Optimize struct stores like stores to memory, ignore unneeded bits ↵Alon Zakai2021-03-121-0/+15
| | | | | | | (#3680) When storing to an i8, we can ignore any higher bits, etc. Adds a getByteSize utility to Field to make this convenient.
* Remove LUB calculation (#3669)Thomas Lively2021-03-113-151/+53
| | | | | | | | Since correct LUB calculation for recursive types is complicated, stop depending on LUBs throughout the code base. This also fixes a validation bug in which the validator required blocks to be typed with the LUB of all the branch types, when in fact any upper bound should have been valid. In addition to fixing that bug, this PR simplifies the code for break handling by not storing redundant information about the arity of types.
* Make unreachable a subtype of everything (#3673)Thomas Lively2021-03-112-87/+59
| | | | | | | Since in principle an unreachable expression can be used in any position. An exception to this rule is in OptimizeInstructions, which avoids replacing concrete expressions with unreachable expressions so that it doesn't need to refinalize any expressions. Notably, Type::getLeastUpperBound was already treating unreachable as the bottom type.
* [Wasm GC] Fix RTT type parsing (#3672)Alon Zakai2021-03-101-2/+2
| | | | | | This was missing from #3663 Fixes #3656
* [Wasm GC] Properly handle "typeindex" in the binary format (#3663)Alon Zakai2021-03-092-24/+32
| | | | | | | | | We handled them as S63 instead of U32. That should be fine, as all U32 values fit in S63. But it is not strictly correct. The signed encoding may use an additional byte which is unnecessary, and there is an actual correctness issue where a U32 may be interpreted as a large negative S63 (because it sign extends a final bit that happens to be 1). May help #3656 but that testcase still does not pass even with this.
* [Wasm GC] Allow set values to be subtypes (#3665)Alon Zakai2021-03-091-8/+8
|
* [reference-types] Support passive elem segments (#3572)Abbas Mashayekh2021-03-055-151/+271
| | | | | | | | | | | 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.
* Fix binary writing of local name indexes (#3649)Alon Zakai2021-03-042-22/+45
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | When writing a binary, we take the local indexes in the IR and turn them into the format in the binary, which clumps them by type. When writing the names section we should be aware of that ordering, but we never were, as noticed in #3499 This fixes that by saving the mapping of locals when we are emitting the name section, then using it when emitting the local names. This also fixes the order of the types themselves as part of the refactoring. We used to depend on the ordering of types to decide which to emit first, but that isn't good for at least two reasons. First, it hits #3648 - that order is not fully defined for recursive types. Also, it's not good for code size - we've ordered the locals in a way we think is best already (ReorderLocals pass). This PR makes us pick an order of types based on that, as much as possible, that is, when we see a type for the first time we append it to a list whose order we use. Test changes: Some are just because we use a different order than before, as in atomics64. But some are actual fixes, e.g. in heap-types where we now have (local $tv (ref null $vector)) which is indeed right - v there is for vector, and likewise m for matrix etc. - we just had wrong names before. Another example, we now have (local $local_externref externref) whereas before the name was funcref, and which was wrong... seems like the incorrectness was more common on reference types and GC types, which is why this was not noticed before. Fixes #3499 Makes part of #3648 moot.
* Emit "elem declare" for functions that need it (#3653)Alon Zakai2021-03-042-1/+35
| | | | | | | This adds support for reading (elem declare func $foo .. in the text and binary formats. We can simply ignore it: we don't need to represent it in IR, rather we find what needs to be declared when writing. That part takes a little more work, for which this adds a shared helper function.
* Fix TypeComparator to satisfy C++'s Compare requirement (#3650)Thomas Lively2021-03-041-7/+7
| | | | | | | | | | | | | | The comparison implemented by TypeComparator was not previously antisymmetric because it held that both A < B and B < A when A and B were structurally identical but nominally distinct recursive types. This meant that it did not satisfy the conditions of C++'s "Compare" requirement, which meant that std::set did not operate correctly, as discovered in #3648. The PR fixes the problem by having making A < B be false (and vice versa), making type comparisons properly antisymmetric. As a drive by, also switches to using std::stable_sort in collectHeapTypes to make the order of the type section completely deterministic accross platforms. Fixes #3648.
* [Wasm GC] Parse text field names even of types that end up canonicalized ↵Alon Zakai2021-03-031-15/+12
| | | | | | | together (#3647) Names of structurally identical types end up "collapsed" together after the types are canonicalized, but with this PR we can properly read content that has structurally identical types with different names.
* [Wasm GC] ref.cast and ref.test should have zero immediates (#3641)Alon Zakai2021-03-021-8/+4
| | | This updates them to be correct in the current spec and prototype v3.
* [Wasm GC] Allow subtyping in arguments to struct.get etc. Fixes #3636 (#3644)Alon Zakai2021-03-022-2/+2
| | | | | | | | | Note that Binaryen "canonicalizes" the type, so in the test output here we end up with $grandchild twice. This is a consequence of us not storing the heap type as an extra field. I can't think of a downside to this canonicalization, aside from losing perfect roundtripping, but I think that's a worthwhile tradeoff for efficiency as we've been thinking so far. Fixes #3636
* Remove duplicate assertion (#3638)Alon Zakai2021-03-021-1/+0
|
* [Wasm GC] Add Names section support for field names (#3589)Alon Zakai2021-03-012-1/+54
| | | | | | | | | | Adds support for GC struct fields in the binary format, implementing WebAssembly/gc#193 No extra tests needed, see the .fromBinary output which shows this working. This also has a minor fix in the s-parser, we should not always add a name to the map of index=>name - only if it exists. Without that fix, the binary emitter would write out null strings.
* [Wasm GC] Add test/spec/br_on_null.wast and validation fixes for it (#3623)Alon Zakai2021-03-012-24/+8
| | | | | | This adds ValidationBuilder which can allow sharing of builder code that also validates, between the text and binary parsers. In general we share that code in the validator, but the validator can only run once IR exists, and in some cases we can't even emit valid IR structure at all.
* Refactor code out of parsing.h NFC. (#3635)Alon Zakai2021-03-013-0/+347
| | | | Most of it goes in a new parsing.cpp. One method was only used in the s-expression's parser, and has been moved there.
* [Wasm Exceptions] Properly ensure unique Try labels after an inlining (#3632)Alon Zakai2021-03-011-0/+3
| | | | | | | | | The old code here just referred to Block and Loop. Refactor it to use the generic helper code that also handles Try. Also add validation of Try names in the validator. The testcase here would have $label appear twice before this fix. After the fix there is $label0 for one of them.
* Allow empty body within catch block (#3630)Heejin Ahn2021-03-011-1/+1
| | | | | | | | Previously we assumed catch body's size should be at least 3: `catch` keyword, event name, and body. But catch's body can be empty when the event's type is none. This PR fixes the bug and allows empty catch bodies to be parsed correctly. Fixes #3629.
* Consider self-referential HeapTypes to be canonical (#3626)Thomas Lively2021-02-281-13/+13
| | | | | | | | | | | | | | This PR makes the TypeBuilder move self-referential HeapTypes to global HeapType store so that they are considered canonical. This means that when a HeapType is constructed with an identical definition, it will be equivalent to the original HeapType constructed by the TypeBuilder, but it does _not_ mean that self-referential HeapTypes are deduplicated. This fixes a bug in which two versions of each self-referential function signature were emitted. Before this PR, the global HeapType store was not aware of the original self-referential HeapTypes. When the function signatures were used to construct HeapTypes during type collection, new HeapTypes were allocated and emitted in addition to the original HeapTypes. Now the global HeapType store returns the original HeapTypes, so the extra HeapType is never allocated.
* Use enum instead of bool for StackSignature kind (#3625)Thomas Lively2021-02-261-5/+9
| | | | | As a readability improvement, use an enum with `Polymorphic` and `Fixed` variants to represent the polymorphic behavior of StackSignatures rather than a `bool uneachable`.
* Support printing recursive types (#3624)Thomas Lively2021-02-261-177/+212
| | | | | Also fixes a few locations in Print.cpp where types were being printed directly rather than going through the s-expression type printer and removes vestigial wrapper types that were no longer used.
* [Wasm GC] Add array.wast and validator fixes for it (#3622)Alon Zakai2021-02-262-1/+6
|
* Use Tarjan's SCC alg. to find self-referential types (#3621)Thomas Lively2021-02-261-30/+90
| | | | | | | | | | | | | | | | | Previously we computed the fixed point of the parent-child relation to identify self-referential HeapTypes in the TypeBuilder canonicalizer. That algorithm was O(|V|^3) in the worst case and took over five seconds to find the self-referential HeapTypes in an example program with just 1134 HeapTypes, probably due to high allocation traffic from the std::unordered_map and std::unordered_sets used to implement the parent-child graph's adjacency list. This PR replaces that algorithm with Tarjan's strongly connected component algorithm, which runs in O(|V|+|E|) and finds the self-referential HeapTypes in the mentioned example program in under 30 ms. All strongly connected components of more than one element in the HeapType parent-child graph correspond to sets of mutually recursive HeapTypes that are therefore self-referential. The only other self-referential HeapTypes are those that are not mutually recursive with any other HeapTypes, but these are trivial to find because they must be their own direct children.
* Support comparing, subtyping, and naming recursive types (#3610)Thomas Lively2021-02-251-170/+281
| | | | | | | | | | | | | | | | | | | | | When the type section is emitted, types with an equal amount of references are ordered by an arbitrary measure of simplicity, which previously would infinitely recurse on structurally equivalent recursive types. Similarly, calculating whether an recursive type was a subtype of another recursive type could have infinitely recursed. This PR avoids infinite recursions in both cases by switching the algorithms from using normal inductive recursion to using coinductive recursion. The difference is that while the inductive algorithms assume the relations do not hold for a pair of HeapTypes until they have been exhaustively shown to hold, the coinductive algorithms assume the relations hold unless a counterexample can be found. In addition to those two algorithms, this PR also implement name generation for recursive types, using de Bruijn indices to stand in for inner uses of the recursive types. There are additional algorithms that will need to be switched from inductive to coinductive recursion, such as least upper bound generation, but these presented a good starting point and are sufficient to get some interesting programs working end-to-end.
* [Wasm GC] Fix the order of operands in array.new and struct.new (#3617)Alon Zakai2021-02-251-7/+8
| | | Also add a missing source file for a GC test, let.wasm.
* Support 64-bit data segment init-exps in Memory64 (#3593)Wouter van Oortmerssen2021-02-254-18/+37
| | | This as a consequence of https://reviews.llvm.org/D95651
* Support Type names in the Names section (#3615)Alon Zakai2021-02-251-0/+37
|
* Support building recursive types (#3602)Thomas Lively2021-02-241-71/+112
| | | | | | | | | | | | | | | | | | | Updates TypeBuilder to support recursive types. Recursive types are particularly problematic because under the current scheme it is necessary to canonicalize the uses of a type's immediate children before canonicalizing the type itself to avoid leaking non-canonical, temporary types out of the TypeBuilder and into the global type stores. In the case of recursive types, it is not possible to do this because of their cyclic nature. In principle this could be overcome by hashing recursive types based on their structure rather than their contents, but that would be complicated. Instead, this PR takes the shortcut of not canonicalizing self-referential HeapTypes at all, but rather moving them out of the TypeBuilder and into the global type store without changing their addresses or needing to update any of their use sites. This breaks all cycles and makes it possible to canonicalize the other types correctly. Note that this PR only adds support for building recursive types. Doing almost anything with the types, such as printing, comparing, or emitting them will certainly lead to infinite recursions. A follow up PR will update all these operations to work correctly with recursive types.
* Refactor name processing (escaping/deduplication) to a shared place. NFC (#3609)Alon Zakai2021-02-241-29/+29
| | | | (not 100% NFC since it also fixes a bug by moving a line out of a loop)
* [Wasm GC] Move struct field names to their proper place (#3600)Alon Zakai2021-02-241-16/+29
| | | | | | | | #3591 adds type and field names to the Module object, and used that for the type but not the fields. This uses it for the fields as well, and removes the "name" field from the Field objects itself, completing the refactoring. After this, binary format support can be added as a proper replacement for #3589
* [Wasm Exceptions] Fix StackIR writing of nested delegates (#3599)Alon Zakai2021-02-231-0/+5
| | | | | | We were missing a pop of catchIndexStack at a Delegate. It ends the scope, so it should do that, like TryEnd does. Found by emscripten-core/emscripten#13485 on -O2.
* Properly use text format type names in printing (#3591)Alon Zakai2021-02-231-0/+12
| | | | | | | | | | | | | | | | | | | This adds a TypeNames entry to modules, which can store names for types. So far this PR uses that to store type names from text format. Future PRs will add support for field names and for the binary format. (Field names are added to wasm.h here to see if we agree on this direction.) Most of the work here is threading a module through the various functions in Print.cpp. This keeps the module optional, so that we can still print an expression independently of a module, which has always been the case, and which I think we should keep (but, if a module was mandatory perhaps this would be a little simpler, and could be refactored into a form that depends on that). 99% of this diff are test updates, since almost all our tests use the text format, and many of them specify a type name but we used to ignore it. This is a step towards a proper solution for #3589
* [GC] Add subtyping support for HeapTypes (#3597)Alon Zakai2021-02-231-22/+61
|
* Support type use before definition in binaries (#3588)Thomas Lively2021-02-192-91/+181
| | | | | | Update parsing of binary type sections to use TypeBuilder to support uses before definitions. Now that both the binary and text parsers support out-of-order type uses, this PR also relaxes the logic for emitting types to allow uses to be emitted before definitions.
* [Wasm Exceptions] Fix binary parsing of a normal break to a try in a ↵Alon Zakai2021-02-191-4/+0
| | | | | | | | | | | | | | | | | | singleton (#3581) The fix here is to remove the code with // maybe we don't need a block here? That would remove a try's block if we thought it wasn't needed. However, it just checked for exception branches, but not normal branches, which are also possible. At that location, we don't have a good way to find out if the block has other branches to it aside from scanning its contents. So this PR just gives up on doing so, which means we add an unnecessary block if the optimizer is not run. If this matters we could make the binary parser more complicated by remembering whether a block had branches in the past, but I'm not sure if it's worth it.
* Support type uses before definitions in text parser (#3584)Thomas Lively2021-02-181-75/+188
| | | | | | | | | | | | | | | | | | | | | | Traverses the module to find type definitions and uses a TypeBuilder to construct the corresponding HeapTypes rather than constructing them directly. This allows types to be used in the definitions of other types before they themselves are defined, which is an important step toward supporting recursive types. After this PR, no further text parsing changes will be necessary to support recursive types. Beyond allowing types to be used before their definitions, this PR also makes a couple incidental changes to the parser's behavior. First, compound heaptypes can now only be declared in `(type ...)` elements and cannot be declared inline at their site of use. This reduces the flexibility of the parser, but is in line with what the text format spec will probably look like eventually (see https://github.com/WebAssembly/function-references/issues/42). The second change is that `(type ...)` elements are now all parsed before `(func ...)` elements rather than in text order with them, so the type indices will be different and wasts using numeric type indices will be broken. Note however, that we were already not completely spec compliant in this regard because we parsed types defined by `(type...)` and `(func...)` elements before types defined by the type uses of `call_indirect` instructions.
* Fix TypeBuilder canonicalization (#3578)Thomas Lively2021-02-181-27/+96
| | | | | | | | | | | | | | | | | | | | | | When types or heap types were used multiple times in a TypeBuilder instance, it was possible for the canonicalization algorithm to canonicalize a parent type before canonicalizing all of its component child types, leaking the temporary types into globally interned types. This bug led to incorrect canonicalization results and use-after free bugs. The cause of the bug was that types were canonicalized in the reverse of the order that they were visited in, but children were visited after the first occurrence of their parents, not necessarily after the last occurrence of their parents. One fix could have been to remove the logic that prevented types from being visited multiple times so that children would always be visited after their parents. That simple fix, however, would not scale gracefully to handle recursive types because it would require some way to detect recursions without accidentally reintroducing these bugs. This PR implements a more robust solution: topologically sorting the traversed types to ensure that children are canonicalized before their parents. This solution will be trivial to adapt for recursive types because recursive types are trivial to detect from the reachability graph used to perform the topological sort.
* [EH] Change catch_all's opcode (#3574)Heejin Ahn2021-02-191-5/+2
| | | | | | | | | | We decided to change `catch_all`'s opcode from 0x05, which is the same as `else`, to 0x19, to avoid some complicated handling in the tools. See: https://github.com/WebAssembly/exception-handling/issues/147 lso this contains the original cpp file used to generate dwarf_with_exceptions.wasm; instructions to generate the wasm from that cpp file are in the comments.
* Allow em_js strings to be exported as globals (#3577)Sam Clegg2021-02-181-14/+27
|
* [EH] Make rethrow's target a try label (#3568)Heejin Ahn2021-02-184-51/+39
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* cleanup to allow binaryen to be built in more strict environments (#3566)walkingeyerobot2021-02-161-2/+2
|
* Fix removal of em_js strings (#3570)Sam Clegg2021-02-161-1/+1
|
* [EH] Rename delegateTarget to exceptionTarget (NFC) (#3562)Heejin Ahn2021-02-133-22/+23
| | | | | | | | | | | | | So far `Try`'s label is only targetted by `delegate`s, but it turns out `rethrow` also has to follow the same rule as `delegate` so it needs to target a `Try` label. So this renames variables like `delegateTargetNames` to `exceptionTargetNames` and methods like `replaceDelegateTargets` to `replaceExceptionTargets`. I considered `tryTarget`, but the branch/block counterpart name we use is not `blockTarget` but `branchTarget`, so I chose `exceptionTarget`. The patch that fixes `rethrow`'s target will follow; this is the preparation for that.
* [EH] Support reading/writing of delegate (#3561)Heejin Ahn2021-02-125-69/+245
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This adds support for reading/writing of the new `delegate` instruction in the folded wast format, the stack IR format, the poppy IR format, and the binary format in Binaryen. We don't have a formal spec written down yet, but please refer to WebAssembly/exception-handling#137 and WebAssembly/exception-handling#146 for the informal semantics. In the current version of spec `delegate` is basically a rethrow, but with branch-like immediate argument so that it can bypass other catches/delegates in between. `delegate` is not represented as a new `Expression`, but it is rather an option within a `Try` class, like `catch`/`catch_all`. One special thing about `delegate` is, even though it is written _within_ a `try` in the folded wat format, like ```wasm (try (do ... ) (delegate $l) ) ``` In the unfolded wat format or in the binary format, `delegate` serves as a scope end instruction so there is no separate `end`: ```wasm try ... delegate $l ``` `delegate` semantically targets an outer `catch` or `delegate`, but we write `delegate` target as a `try` label because we only give labels to block-like scoping expressions. So far we have not given `Try` a label and used inner blocks or a wrapping block in case a branch targets the `try`. But in case of `delegate`, it can syntactically only target `try` and if it targets blocks or loops it is a validation failure. So after discussions in #3497, we give `Try` a label but this label can only be targeted by `delegate`s. Unfortunately this makes parsing and writing of `Try` expression somewhat complicated. Also there is one special case; if the immediate argument of `try` is the same as the depth of control flow stack, this means the 'delegate' delegates to the caller. To handle this case this adds a fake label `DELEGATE_CALLER_TARGET`, and when writing it back to the wast format writes it as an immediate value, unlike other cases in which we write labels. This uses `DELEGATE_FIELD_SCOPE_NAME_DEF/USE` to represent `try`'s label and `delegate`'s target. There are many cases that `try` and `delegate`'s labels need to be treated in the same way as block and branch labels, such as for hashing or comparing. But there are routines in which we automatically assume all label uses are branches. I thought about adding a new kind of defines such as `DELEGATE_FIELD_TRY_NAME_DEF/USE`, but I think it will also involve some duplication of existing routines or classes. So at the moment this PR chooses to use the existing `DELEGATE_FIELD_SCOPE_NAME_DEF/USE` for `try` and `delegate` labels and makes only necessary amount of changes in branch-utils. We can revisit this decision later if necessary. Many of changes to the existing test cases are because now all `try`s are automatically assigned a label. They will be removed in `RemoveUnusedNames` pass in the same way as block labels if not targeted by any delegates. This only supports reading and writing and has not been tested against any optimization passes yet. --- Original unfolded wat file to generate test/try-delegate.wasm: ```wasm (module (event $e) (func try try delegate 0 catch $e end) (func try try catch $e i32.const 0 drop try delegate 1 end catch $e end ) ) ```
* finalize: strip segments that contain only EM_ASM/EM_JS data (#3557)Sam Clegg2021-02-121-47/+142
| | | | | | | If we find a data segment whose entire contents is EM_JS or EM_ASM strings then strip it from the binary. See: https://github.com/emscripten-core/emscripten/pull/13443
* StackSignature subtypes and LUBs (#3543)Thomas Lively2021-02-111-3/+5
| | | | | | | | Add a utility for calculating the least upper bounds of two StackSignatures, taking into account polymorphic unreachable behavior. This will important in the finalization and validation of Poppy IR blocks, where a block is allowed to directly produce fewer values than the branches that target it carry if the difference can be made up for by polymorphism due to an unreachable instruction in the block.
* Simplify asmConst handling. NFC. (#3558)Sam Clegg2021-02-091-76/+9
| | | | | | | | Support for multiple signatures per JS code string was removed in #2422. emscripten now only needs to know that address and the body of the JS function. See https://github.com/emscripten-core/emscripten/pull/13452.
* [reference-types] remove single table restriction in IR (#3517)Abbas Mashayekh2021-02-096-145/+380
| | | Adds support for modules with multiple tables. Adds a field for the table name to `CallIndirect` and updates the C/JS APIs accordingly.
* finalize: Refactor C string extraction code. NFC. (#3555)Sam Clegg2021-02-081-82/+84
| | | | | This is a pure refactor in preparation for change that will enable stripping or at least zeroing segments that only contain EM_JS/EM_ASM strings.