summaryrefslogtreecommitdiff
path: root/src
Commit message (Collapse)AuthorAgeFilesLines
...
* [Wasm GC] Fix evaluateKindCheck() on new externalize/internalize operations ↵Alon Zakai2022-09-011-2/+6
| | | | | | | | | | (#5000) Also add testing that they pass through the full optimizer. Fixes #4999 Drive-by fixes to the text in the assertions, which was copy-pasted.
* Add remaining GC and string instructions to C API (#4998)dcode2022-08-313-25/+471
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Adds C-API bindings for the following expression classes: RefTest RefCast BrOn with operations BrOnNull, BrOnNonNull, BrOnCast, BrOnCastFail, BrOnFunc, BrOnNonFunc, BrOnData, BrOnNonData, BrOnI31, BrOnNonI31 StructNew with operations StringNewUTF8, StringNewWTF8, StringNewReplace, StringNewWTF16, StringNewUTF8Array, StringNewWTF8Array, StringNewReplaceArray, StringNewWTF16Array StructGet StructSet ArrayNew ArrayInit ArrayGet ArraySet ArrayLen ArrayCopy StringNew StringConst StringMeasure with operations StringMeasureUTF8, StringMeasureWTF8, StringMeasureWTF16, StringMeasureIsUSV, StringMeasureWTF16View StringEncode with operations StringEncodeUTF8, StringEncodeWTF8, StringEncodeWTF16, StringEncodeUTF8Array, StringEncodeWTF8Array, StringEncodeWTF16Array StringConcat StringEq StringAs with operations StringAsWTF8, StringAsWTF16, StringAsIter StringWTF8Advance StringWTF16Get StringIterNext StringIterMove with operations StringIterMoveAdvance, StringIterMoveRewind StringSliceWTF with operations StringSliceWTF8, StringSliceWTF16 StringSliceIter
* Update fuzzer to newer GC spec regarding JS interop (#4965)Alon Zakai2022-08-311-7/+24
| | | | Do not export functions that have types not allowed in the rules for JS interop. Only very few GC types can be on the JS boundary atm.
* [NFC] Simplify binary reading logic for data segments (#4990)Alon Zakai2022-08-312-10/+4
| | | Similar to #4969 but for data segments.
* [Wasm GC] Support non-nullable locals in the "1a" form (#4959)Alon Zakai2022-08-3145-192/+622
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | An overview of this is in the README in the diff here (conveniently, it is near the top of the diff). Basically, we fix up nn locals after each pass, by default. This keeps things easy to reason about - what validates is what is valid wasm - but there are some minor nuances as mentioned there, in particular, we ignore nameless blocks (which are commonly added by various passes; ignoring them means we can keep more locals non-nullable). The key addition here is LocalStructuralDominance which checks which local indexes have the "structural dominance" property of 1a, that is, that each get has a set in its block or an outer block that precedes it. I optimized that function quite a lot to reduce the overhead of running that logic after each pass. The overhead is something like 2% on J2Wasm and 0% on Dart (0%, because in this mode we shrink code size, so there is less work actually, and it balances out). Since we run fixups after each pass, this PR removes logic to manually call the fixup code from various places we used to call it (like eh-utils and various passes). Various passes are now marked as requiresNonNullableLocalFixups => false. That lets us skip running the fixups after them, which we normally do automatically. This helps avoid overhead. Most passes still need the fixups, though - any pass that adds a local, or a named block, or moves code around, likely does. This removes a hack in SimplifyLocals that is no longer needed. Before we worked to avoid moving a set into a try, as it might not validate. Now, we just do it and let fixups happen automatically if they need to: in the common code they probably don't, so the extra complexity seems not worth it. Also removes a hack from StackIR. That hack tried to avoid roundtrip adding a nondefaultable local. But we have the logic to fix that up now, and opts will likely keep it non-nullable as well. Various tests end up updated here because now a local can be non-nullable - previous fixups are no longer needed. Note that this doesn't remove the gc-nn-locals feature. That has been useful for testing, and may still be useful in the future - it basically just allows nn locals in all positions (that can't read the null default value at the entry). We can consider removing it separately. Fixes #4824
* [C/JS API] Avoid erroring in BinaryenSetMemoryImport etc. if the entity ↵Max Graey2022-08-302-30/+70
| | | | | | exists (#4991) If it exists, just turn it into an import. If not, then as before we create it + turn it into an import.
* Fix ModuleUtils::renameFunctions on RefFunc (#4978)Alon Zakai2022-08-291-26/+29
| | | | | It had hardcoded handling of the table, but was missing RefFunc (and maybe more?) Also some cleanups around that code.
* [NFC] Simplify binary reading logic for element segments (#4989)Alon Zakai2022-08-292-11/+4
| | | Similar to #4969 but for element segments.
* Implement `extern.externalize` and `extern.internalize` (#4975)Thomas Lively2022-08-2910-10/+132
| | | | These new GC instructions infallibly convert between `extern` and `any` references now that those types are not in the same hierarchy.
* [NFC] Simplify binary reading logic for memories (#4987)Alon Zakai2022-08-292-29/+7
| | | Similar to #4969 but for memories.
* Remvoe extra space after rec beginning (#4981)Alon Zakai2022-08-291-1/+1
|
* Fix SmallVector's resize() method (#4979)Alon Zakai2022-08-291-0/+2
| | | | A resize from a large amount to a small amount would sometimes not clear the flexible storage, if we used it before but not after.
* [OptimizeInstruction] Reorder rules in optimizeSelect (#4984)Max Graey2022-08-291-32/+32
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | To unblock some optimizations. For example this: ```wat (select (i32.eqz (local.get $x)) (i32.const 0) (i32.eqz (local.get $y)) ) ``` Was previously optimized as: ```wat (i32.eqz (select (i32.const 1) (local.get $x) (local.get $y) ) ) ``` Because `optimizeSelect` applied `!x ? !y : 0 -> x ? 0 : !y` then `!(x ? 1 : y)`, blocking the next rules which could have folded this to `or` or `and`. After this PR the same example optimizes better: ```wat (i32.eqz (i32.or (local.get $x) (local.get $y) ) ) ```
* [NFC] Simplify binary reading logic for globals (#4980)Alon Zakai2022-08-292-36/+11
| | | Similar to #4969 but for globals.
* [OptimizeInstructions] Canonicalize relational ops near min/max values (#4282)Max Graey2022-08-261-0/+61
| | | | | | | | | | | | | A continuation of #4272. ``` (signed)x < s_min + 1 ==> x == s_min (signed)x >= s_min + 1 ==> x != s_min (signed)x > s_max - 1 ==> x == s_max (signed)x <= s_max - 1 ==> x != s_max (unsigned)x <= u_max - 1 ==> x != u_max (unsigned)x > u_max - 1 ==> x == u_max ```
* [NFC] Simplify binary reading logic for tables (#4974)Alon Zakai2022-08-262-32/+11
| | | Similar to #4969 but for tables.
* Emit `i31ref` and `dataref` binary shorthands (#4844)Thomas Lively2022-08-261-6/+4
|
* Make `i31ref` and `dataref` nullable (#4843)Thomas Lively2022-08-265-58/+40
| | | | | | | Match the latest version of the GC spec. This change does not depend on V8 changing its interpretation of the shorthands because we are still temporarily not emitting the binary shorthands, but all Binaryen users will have to update their interpretations along with this change if they use the text or binary shorthands.
* [Parser] Parse functions and implicit types (#4972)Thomas Lively2022-08-262-20/+397
| | | | | | | | | Implement function parsing, including parsing of locals and type uses. Also add a new phase of parsing that iterates through type uses that do not have explicit types to create any implicitly defined types and append them to the type index space. This is important because the implicitly defined types may be referred to by index elsewhere and because the legacy parser does not handle these implicitly defined types correctly. Finally, maintain a map of implicit type use locations to corresponding types for use in later phases of parsing.
* Add support for Tag names in the Names section (#4970)Alon Zakai2022-08-262-4/+61
|
* [NFC] Simplify binary reading logic for functions (#4969)Alon Zakai2022-08-262-23/+9
| | | | | | | We do a call to updateMaps() at the end of processNames anyhow, and so we may as well call addFunction immediately (and the names will get fixed up in that updateMaps later). The old code for some reason did that for function imports, but not normal functions. It also stored them separately in temporary storage for some unclear reason...
* Adding Multi-Memories Wasm Feature (#4968)Ashley Nelson2022-08-256-2/+20
| | | Adding multi-memories to the the list of wasm-features.
* Fix order of local names in Names section (#4964)Congcong Cai2022-08-251-17/+19
| | | | | | The wasm spec requires the order of local names in that section to be in increasing order: https://webassembly.github.io/spec/core/appendix/custom.html#binary-namemap
* [TNH Fuzzing] Fix some equality checks that ignored effects (#4951)Alon Zakai2022-08-241-8/+20
| | | | | | | | | | | | | Fuzzing with TrapsNeverHappen found a bug, and then reading similar code I found another, where we check structural equality but ignored effects. Some things look equal but may have different values at runtime: (foo (call $x) (call $y) ) The arms are identical structurally but due to side effects may not be identical in value.
* Fuzzer simplification: Remove trap-ignoring logic (#4958)Alon Zakai2022-08-242-16/+3
| | | | | | | | | | | | | The "ignore trap" logic there is not close to enough for what we'd need to actually fuzz in a way that ignores traps, so this removes it. Atm that logic just allows a trap to happen without causing an error (that is, when comparing two results, one might trap and the other not, but they'd still be considered "equal"). But due to how we optimize traps in TrapsNeverHappens mode, the optimizer is free to assume the trap never occurs, which might remove side effects that are noticeable later. To actually handle that, we'd need to refactor the code to retain results per function (including the Loggings) and then to ignore everything from the very first trapping function. That is somewhat complicated to do, and a simpler thing is done in #4936, so we won't need it here.
* Only look at the relevant parameter in param-utils:removeParameter (#4937)Alon Zakai2022-08-231-5/+2
| | | Followup to #4910.
* Fix multi-memory + C API for MemoryGrow and MemorySize (#4953)Alon Zakai2022-08-234-19/+44
| | | | | | | | | | | | | | | | Those instructions need to know if the memory is 64-bit or not. We looked that up on the module globally, which is convenient, but in the C API this was actually a breaking change, it turns out. To keep things working, provide that information when creating a MemoryGrow or MemorySize, as another parameter in the C API. In the C++ API (wasm-builder), support both modes, and default to the automatic lookup. We already require a bunch of other explicit info when creating expressions, like making a Call requires the return type (we don't look it up globally), and even a LocalGet requires the local type (we don't look it up on the function), so this is consistent with those. Fixes #4946
* Multi-Memories Validate (#4945)Ashley Nelson2022-08-231-37/+43
| | | This change loops through memories to validate each meets wasm spec. Also factors data segment validation out from memory validation, as it makes more sense for data segments to stand alone like the other module-level elements.
* Separate `func` into a separate type hierarchy (#4955)Thomas Lively2022-08-223-37/+18
| | | | | Just like `extern` is no longer a subtype of `any` in the new GC type system, `func` is no longer a subtype of `any`, either. Make that change in our type system implementation and update tests and fuzzers accordingly.
* RemoveUnusedBrs: Remove final block nops in all cases (#4954)Alon Zakai2022-08-221-5/+8
| | | | | | | | | | | | | | | | | | | | This fixes what looks like it might be a regression in #4943. It's not actually an issue since it just affects wat files, but it did uncover an existing inefficiency. The situation is this: (block .. (br $somewhere) (nop) ) Removing such a nop is always helpful, as the pass might see that that br goes to where control flow is going anyhow, and the nop would confuse it. We used to remove such nops only when the block had a name, which is why wat testcases looks optimal, but we were actually doing the less-efficient thing on real-world code. It was a minor inefficiency, though, as the nop is quickly removed by later passes anyhow. Still, the fix is trivial (to always remove such nops, regardless of a name on the block or not).
* Avoid adding new unneeded names to blocks in text roundtripping (#4943)Alon Zakai2022-08-221-6/+26
| | | | | | | | | | | | | | | | | | | | | | | Previously the wat parser would turn this input: (block (nop) ) into something like this: (block $block17 (nop) ) It just added a name all the time, in case the block is referred to by an index later even though it doesn't have a name. This PR makes us rountrip more precisely by not adding such names: if there was no name before, and there is no break by index, then do not add a name. In addition, this will be useful for non-nullable locals since whether a block has a name or not matters there. Like #4912, this makes us more regular in our usage of block names.
* Materialize non-null externrefs in the fuzzer (#4952)Thomas Lively2022-08-221-2/+7
| | | | | | | Some fuzzer initial contents contain non-nullable externrefs that cause the fuzzer to try to materialize non-nullable externref values. Perviously the fuzzer did not support this and crashed with an assertion failure. Fix the assertion failure by instead returning a null cast to non-null, which will trap at runtime but at least produce a valid module.
* GUFA: Mutable exported globals are roots (#4935)Alon Zakai2022-08-221-0/+7
| | | | | | | Such globals can be written to from the outside, so we cannot infer anything about their contents. Fixes #4932
* Multi-Memories improvements to binaryen-c.cpp (#4940)Ashley Nelson2022-08-192-156/+134
| | | | | | Resolving a couple of issues from the multi-memories PR landing: Use memName as parameter label instead of name #4916 Add helper func for case of a single memory to binaryen-c #4917
* [Directize] Add a flag to consider initial table contents immutable (#4942)Alon Zakai2022-08-191-66/+121
| | | | | | | | In LLVM output and probably others, the initial table contents are never changed. We may append later, but we don't trample the initial table entries. As a result, with this new flag we can turn indirect calls on those offsets into direct ones: --directize-initial-tables-immutable
* [OptimizeInstructions] Simplify rounding or conversions after int to float ↵Max Graey2022-08-181-0/+67
| | | | | | | | | | | | | | | | | | | casts (#4720) i32 -> f64 -> i32 rountripping optimizations: ```rust i32(f64(i32(x))) -> x // i32.trunc(_sat)_f64_s(f64.convert_i32_s(x)) -> x u32(f64(u32(x))) -> x // i32.trunc(_sat)_f64_u(f64.convert_i32_u(x)) -> x // note assymetric signed / unsigned or unsigned / signed cases can't be simplified in similar way ``` and rounding after integer to float casts: ```rust ceil(float(int(x))) -> float(int(x)) floor(float(int(x))) -> float(int(x)) trunc(float(int(x))) -> float(int(x)) nearest(float(int(x))) -> float(int(x)) ``` where `float = f32 | f64`, `int = i32 | i64 | u32 | u64`
* Fix Memory64 binary parsing after #4811 (#4933)Alon Zakai2022-08-183-19/+24
| | | | Due to missing test coverage, we missed in #4811 that some memory operations needed to get make64() called on them.
* [Wasm GC] Fix TypeRefining on fallthrough values via tee (#4900)Alon Zakai2022-08-184-10/+57
| | | | | | | | | | | | | | | | | | | | | | A rather tricky corner case: we normally look at fallthrough values for copies of fields, so when we try to refine a field, we ignore stuff like this: a.x = b.x; That copies the same field on the same type to itself, so refining is not limited by it. But if we have something else in the middle, and that thing cannot change type, then it is a problem, like this: (struct.set (..ref..) (local.tee $temp (struct.get))) tee has the type of the local, which does not change in this pass. So we can't look at just the fallthrough here and skip the tee: after refining the field, the tee's old type might not fit in the field's new type. We could perhaps add casts to fix things up, but those may have too big a cost. For now, just ignore the fallthrough.
* Fix DeadArgumentElimination + TrapsNeverHappen to not leave stale types (#4910)Alon Zakai2022-08-181-5/+25
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | DAE will normally not remove an unreachable parameter, because it checks for effects there. But in TrapsNeverHappen mode, we assume that an unreachable is an effect we can remove, so we are willing to remove it: (func $foo (param $unused i32) ;; never use $unused ) (func $bar (call $foo (unreachable))) ;;=> dae+tnh (func $foo ) (func $bar (call $foo)) But that transformation is invalid: the call's type was unreachable before but no longer is. What went wrong here is that, yes, it is valid to remove an unreachable, but we may need to update types while doing so, which we were not doing. This wasn't noticed before due to a combination of unfortunate factors: The main reason is that this only happens in TrapsNeverHappens mode. We don't fuzz that, because it's difficult: that mode can assume a trap never happens, so a trap is undefined behavior really. On real-world code this is great, but in the fuzzer it means that the output can seem to change after optimizations. The validator happened to be missing an error for a call that has type unreachable but shouldn't: Validator: Validate unreachable calls more carefully #4909 . Without that, we'd only get an error if the bad type influenced a subsequent pass in a confusing way - which is possible, but difficult to achieve (what ended up happening in practice is that SignatureRefining on J2Wasm relied on the unreachable and refined a type too much). Even with that fix, for the problem to be detected we'd need for the validation error to happen in the final output, after running all the passes. In practice, though, that's not likely, since other passes tend to remove unreachables etc. Pass-debug mode is very useful for finding stuff like this, as it validates after every individual pass. Sadly it turns out that global validation was off there: Validator: Validate globally by default #4906 (so it was catching the 99% of validation errors that are local, but this particular error was in the remaining 1%...). As a fix, simply ignore this case. It's not really worth the effort to optimize it, since DCE will just remove unreachables like that anyhow. So if we run again after a DCE we'd get a chance to optimize. This updates some existing tests to avoid (unreachable). That was used as an example of something with effects, but after this change it is treated more carefully. Replace those things with something else that has effects (a call).
* Validator: Validate unreachable calls more carefully (#4909)Alon Zakai2022-08-181-0/+57
| | | | | | | | | | | | | | | | | | Normally the validator will find stale types properly, by just running refinalize and seeing if the type has changed (if so, then some code forgot to refinalize). However, refinalize is a local operation, so it does not apply to calls: a call's proper type is determined by the global information of the function we are calling. As a result, we would not notice errors like this: (call $foo) ;; type: unreachable Refinalizing that would not change the type from unreachable to the proper type, since that is global information. To validate this properly, validate that a call whose type is unreachable actually has an unreachable child. That rules out an invalid unreachable type here, which leaves concrete types, that we already have proper global validation for. The code here is generalized to handle non-call things as well, but it only helps expressions requiring global validation, so it likely only helps global.get and a few others.
* Avoid emitting a block in the binary format when it has no name (#4912)Alon Zakai2022-08-181-1/+32
| | | | | | | | | | We already did this if the block was a child of a control flow structure, which is the common case (see the new added comment around that code, which clarifies why). This does the same for all other blocks. This is simple to do and a minor optimization, but the main benefit from this is just to make our handling of blocks uniform: after this, we never emit a block with no name. This will make 1a non- nullable locals easier to handle (since they will be able to assume that property; and not emitting such blocks avoids some work to handle non-nullable locals in them).
* Restore the `extern` heap type (#4898)Thomas Lively2022-08-1717-98/+206
| | | | | | | The GC proposal has split `any` and `extern` back into two separate types, so reintroduce `HeapType::ext` to represent `extern`. Before it was originally removed in #4633, externref was a subtype of anyref, but now it is not. Now that we have separate heaptype type hierarchies, make `HeapType::getLeastUpperBound` fallible as well.
* Mutli-Memories Support in IR (#4811)Ashley Nelson2022-08-1744-1185/+2287
| | | | | | | This PR removes the single memory restriction in IR, adding support for a single module to reference multiple memories. To support this change, a new memory name field was added to 13 memory instructions in order to identify the memory for the instruction. It is a goal of this PR to maintain backwards compatibility with existing text and binary wasm modules, so memory indexes remain optional for memory instructions. Similarly, the JS API makes assumptions about which memory is intended when only one memory is present in the module. Another goal of this PR is that existing tests behavior be unaffected. That said, tests must now explicitly define a memory before invoking memory instructions or exporting a memory, and memory names are now printed for each memory instruction in the text format. There remain quite a few places where a hardcoded reference to the first memory persist (memory flattening, for example, will return early if more than one memory is present in the module). Many of these call-sites, particularly within passes, will require us to rethink how the optimization works in a multi-memories world. Other call-sites may necessitate more invasive code restructuring to fully convert away from relying on a globally available, single memory pointer.
* Validator: Validate globally by default (#4906)Alon Zakai2022-08-161-1/+1
| | | | | | I'm not sure why this defaulted to non-global. Perhaps because of limitations in the asm.js days. A better default is to validate globally, and this also applies in pass-debug mode (since that just uses the default there), so this will catch more problems there.
* Validator: More carefully check for stale types (#4907)Alon Zakai2022-08-161-4/+8
| | | | | | | The validation logic to check for stale types (code where we forgot to run refinalize) had a workaround for a control flow issue. That workaround meant we didn't catch errors where a type was concrete but it should be unreachable. This PR makes that workaround only apply for control flow structures, so we can catch more errors.
* Revert "[Wasm GC] GC-prefixed opcodes are int8, not LEBs (#4889)" (#4895)Alon Zakai2022-08-162-61/+61
| | | | | | | Reverts #4889 The spec is unclear on this, and that PR moved us to do what V8 does. But it sounds like we should clarify the spec to do things the other way, so this goes back to that.
* Validator: Validate intrinsics (#4880)Alon Zakai2022-08-161-8/+55
| | | | | | | | | | call.without.effects has a specific form, where the last parameter is a function reference, and that function reference must have the right type for the other parameters if called with them: (call $call.without.effects (..i32..) (..f64..) (..function reference, which takes params i32 and f64..)
* LegalizeJSInterface: Look for get/setTempRet0 as exports (#4881)Sam Clegg2022-08-153-11/+55
| | | | | | This allows emscripten to move these helper functions from JS library imports to native wasm exports. See https://github.com/emscripten-core/emscripten/issues/7273
* Function-level pass-debug mode 2 validation (#4897)Alon Zakai2022-08-123-2/+53
| | | | | | In BINARYEN_PASS_DEBUG=2 we save the module before each pass, and if validation fails afterwards, we print the module before. This PR does the same for function-parallel passes - in that case, we can actually show the specific function that broke validation, as opposed to the whole module.
* [EH] Pop should be supertype of tag type (#4901)Heejin Ahn2022-08-111-1/+1
| | | | `pop`s type should be a supertype, not a subtype, of the tag's type within `catch`.