summaryrefslogtreecommitdiff
path: root/src
Commit message (Collapse)AuthorAgeFilesLines
* [threads] Validate shared-polymorphic instructions (#6702)Thomas Lively2024-06-252-72/+68
| | | | Such as `ref.eq`, `i31.get_{s,u}`, and `array.len`. Also validate that struct and array operations work on shared structs and arrays.
* [threads] Validate shared-to-unshared edges in heap types (#6698)Thomas Lively2024-06-252-18/+53
| | | Add spec tests checking validation for structs and arrays.
* Add missing struct/array type checks in binary reader (#6701)Alon Zakai2024-06-251-0/+30
| | | Fixes #6695
* Add a missing binary reading check for BrOn's reference child's type (#6700)Alon Zakai2024-06-251-0/+3
| | | | | | That child must be a reference, as `finalize()` assumes so. To avoid an assertion, error early. Fixes #6696
* [NFC] Remove a minor compile-time optimization in Heap2Local (#6699)Alon Zakai2024-06-251-43/+6
| | | | | | | | We tracked which expressions we saw an allocated struct/array reach, and then quickly exited when another one did (as when two allocations mix, we can optimize neither). It turns out that this helps very little in actual measurements (looks like within noise - likely we are ruling out the un-optimizable cases early otherwise anyhow). Also the complexity it adds is a problem for an improvement I want to make to the pass, so remove it.
* [WasmGC] Add missing ArrayNew variants to Properties::isGenerative (#6691)Alon Zakai2024-06-241-0/+2
| | | Fixes #6690
* Add a proper error for bad select results (#6697)Alon Zakai2024-06-241-1/+5
| | | | | The result cannot be `none` or `unreachable` etc. Fixes #6694
* Add TraceCalls pass (#6619)Marcin Kolny2024-06-214-0/+224
| | | | | | | This pass receives a list of functions to trace, and then wraps them in calls to imports. This can be useful for tracing malloc/free calls, for example, but is generic. Fixes #6548
* wasm2js: Fix the names of temp vars with named reference types (#6689)Alon Zakai2024-06-211-0/+1
| | | | | | We were missing code to mangle such names for JS. Without that, the name of a temp var for the type `(ref $foo)` would end up with `(`, `)` in the name, which is not valid in JS.
* GlobalStructInference: Un-nest struct.news in globals when that is helpful ↵Alon Zakai2024-06-201-62/+220
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | (#6688) If we have (global $g (struct.new $S (i32.const 1) (struct.new $T ..) (ref.func $f) )) then before this PR if we wanted to read the middle field we'd stop, as it is non-constant. However, we can un-nest it, making it constant: (global $g.unnested (struct.new $T ..)) (global $g (struct.new $S (i32.const 1) (global.get $g.unnested) (ref.func $f) )) Now the field is a global.get of an immutable global, which is constant. Using this technique we can handle anything in a struct field, constant or not. The cost of adding a global is likely offset by the benefit of being able to refer to it directly, as that opens up more opportunities later. Concretely, this replaces the constant values we look for in GSI with a variant over constants or expressions (we do still want to group constants, as multiple globals with the same constant field can be treated as a whole). And we note cases where we need to un-nest, and handle those at the end.
* Validate memarg offsets (#6683)Thomas Lively2024-06-201-0/+13
| | | | | For 32-bit memories, the offset value must be in the u32 range. Update the address.wast spec test to assert that a module with an overlarge offset value is invalid rather than malformed.
* [NFC] Add pragma to ignore maybe-uninitialized in strings.cpp (#6686)Thomas Lively2024-06-201-0/+5
| | | This will hopefully fix the build on the coverage builder.
* Validate that names are valid UTF-8 (#6682)Thomas Lively2024-06-195-8/+36
| | | | | | Add an `isUTF8` utility and use it in both the text and binary parsers. Add missing checks for overlong encodings and overlarge code points in our WTF8 reader, which the new utility uses. Re-enable the spec tests that test UTF-8 validation.
* Fix validation of unused LEB128 bits (#6680)Thomas Lively2024-06-191-11/+16
| | | | | The unused bits must be a sign extension of the significant value, but we were previously only validating that unsigned LEBs had their unused bytes set to zero. Re-enable the spec test that checks for proper validation.
* Check malformed mutability on imported globals (#6679)Thomas Lively2024-06-181-0/+3
| | | And re-enable the globals.wast spec test, which checks this.
* Re-enable binary.wast spec test (#6677)Thomas Lively2024-06-183-11/+26
| | | | | | Fix the wast parser to accept IDs on quoted modules, remove tests that are invalidated by the multimemory proposal, and add validation that the total number of variables in a function is less than 2^32 and that the code section is present if there is a non-empty function section.
* [threads] Shared basic heap types (#6667)Thomas Lively2024-06-1913-209/+322
| | | | | | | | | | | Implement binary and text parsing and printing of shared basic heap types and incorporate them into the type hierarchy. To avoid the massive amount of code duplication that would be necessary if we were to add separate enum variants for each of the shared basic heap types, use bit 0 to indicate whether the type is shared and replace `getBasic()` with `getBasic(Unshared)`, which clears that bit. Update all the use sites to record whether the original type was shared and produce shared or unshared output without code duplication.
* [Parser] Fix bug in unreachable fallback logic (#6676)Thomas Lively2024-06-181-13/+18
| | | | | | | | | When popping past an unreachable instruction would lead to popping from an empty stack or popping an incorrect type, we need to avoid popping and produce new Unreachable instructions instead to ensure we parse valid IR. The logic for this was flawed and made the synthetic Unreachable come before the popped unreachable child, which was not correct in the case that that popped unreachable was a branch or other non-trapping instruction. Fix and simplify the logic and re-enable the spec test that uncovered the bug.
* fix(#6671): fix possible stack buffer overflow in gen-s-parser.inc (#6678)mtb2024-06-181-0/+8
| | | | | | The stack buffer overflow is occurring because memcpy(buf, op.data(), op.size()); can write up to op.size() bytes into buf, but buf is only 33 bytes long. If op.size() is greater than 33, this will result in a buffer overflow.
* Reject invalid section IDs (#6675)Thomas Lively2024-06-182-7/+8
| | | | | | Rather than treating them as custom sections. Also fix UB where invalid `Section` enum values could be used as keys in a map. Use the raw `uint8_t` section IDs as keys instead. Re-enable a disabled spec test that was failing because of this bug and UB.
* GlobalStructInference: Optimize globals too (#6674)Alon Zakai2024-06-171-11/+10
| | | | This is achieved by simply replacing the Literal with PossibleConstantValues, which supports both Literals and Globals.
* Fix DataSegment name handling (#6673)Alon Zakai2024-06-171-1/+1
| | | | | | | | | | | | | | | | | | | The code used i instead of index, as in this pseudocode: for i in range(num_names): index = readU32LEB() # index of the data segment to name name = readName() # name to give that segment data[i] = name # XXX 'i' should be 'index' That (funnily enough) happened to always work before since we write names in order. That is, normally given segments A,B,C we'd write then in the names section as A,B,C. Then the reader, which had the bug, would always have i and index identical in value anyhow. But if a wasm producer used different indexes, a problem could happen. To test this, add a binary file that has a reversed name section. Fixes #6672
* wasm2js: Support arbitrary temp variable types (#6661)Alon Zakai2024-06-171-20/+18
| | | | | | | | Previously only basic types were allowed. Generalizing this to arbitrary types means we use a map instead of a vector, which is slower, but I can't measure any noticeable difference. Temp vars are pretty rare, and there are just much slower parts of wasm2js, I think.
* [Parser] Fix error message on required reftype (#6666)Thomas Lively2024-06-141-9/+15
| | | | | | | | | Not all uses of the `reftype` parser handled the fact that it returned a `MaybeResult`. Change its name to `maybeReftype`, add a new `reftype` parser that returns an error if there is no reftype, and update all the use sites. Fixes #6655.
* [Parser] Update requirements for implicit type uses (#6665)Thomas Lively2024-06-141-1/+1
| | | | | | | As an abbreviation, a `typeuse` can be given as just a list of parameters and results, in which case it corresponds to the index of the first function type with the same parameters and results. That function type must also be an MVP function type, i.e. it cannot have a nontrivial rec group, be non-final, or have a declared supertype. The parser did not previously implement all of these rules.
* [threads] Binary reading and writing of shared composite types (#6664)Thomas Lively2024-06-143-1/+10
| | | | Also update the parser so that implicit type uses are not matched with shared function types.
* [Parser][NFC] Make typeidx and maybeTypeidx return consistent types (#6663)Thomas Lively2024-06-142-13/+12
| | | | | | | Since the BasicHeapTypes are in an enum, calling HeapType methods on them requires something like `HeapType(HeapType::func).someMethod()`. This is unnecessarily verbose, so add a new `HeapTypes` namespace that contains constexpr HeapType globals that can be used instead, shorting this to `HeapTypes::func.someMethod()`.
* [NFC] Add constexpr HeapTypes for basic heap types (#6662)Thomas Lively2024-06-141-0/+20
| | | | | | | Since the BasicHeapTypes are in an enum, calling HeapType methods on them requires something like `HeapType(HeapType::func).someMethod()`. This is unnecessarily verbose, so add a new `HeapTypes` namespace that contains constexpr HeapType globals that can be used instead, shorting this to `HeapTypes::func.someMethod()`.
* [threads] Add a "shared-everything" feature (#6658)Thomas Lively2024-06-147-6/+53
| | | | | Add the feature and flags to enable and disable it. Require the new feature to be enabled for shared heap types to validate. To make the test work, update the validator to actually check features for global types.
* wasm2js: Generalize global initializer code to use the main codegen logic ↵Alon Zakai2024-06-131-48/+19
| | | | | | | (#6659) This avoids special-casing particular global init forms. After this we should support everything in global inits that we support anywhere else.
* Add local.set/tee local type annotations to BINARYEN_PRINT_FULL (#6657)Alon Zakai2024-06-131-12/+25
| | | | | | | | | | | | | With this we now print e.g. (local.set $temp (; local type: i32 ;) ... This can be nice in large functions to avoid needing to scroll up to see the local type, e.g. when debugging why unsubtyping doesn't work somewhere. Also avoid [ ] in this mode, in favor of the standard (; ;), and put those at the end rather than at the start.
* wasm2js: Fix null handling and RefAsNonNull (#6656)Alon Zakai2024-06-122-27/+31
|
* [threads] Parse, build, and print shared composite types (#6654)Thomas Lively2024-06-126-13/+70
| | | | | | | | | | | | | | Parse the text format for shared composite types as described in the shared-everything thread proposal. Update the parser to use 'comptype' instead of 'strtype' to match the final GC spec and add the new syntactic class 'sharecomptype'. Update the type canonicalization logic to take sharedness into account to avoid merging shared and unshared types. Make the same change in the TypeMerging pass. Ensure that shared and unshared types cannot be in a subtype relationship with each other. Follow-up PRs will add shared abstract heap types, binary parsing and emitting for shared types, and fuzzer support for shared types.
* [DebugInfo] Copy debug info in call-utils.h (#6652)Alon Zakai2024-06-127-52/+97
| | | | | | | | | | | | | | | | | | | | | | | We automatically copy debuginfo in replaceCurrent(), but there are a few places that do other operations than simple replacements. call-utils.h will turn a call_ref with a select target into two direct calls, and we were missing the logic to copy debuginfo from the call_ref to the calls. To make this work, refactor out the copying logic from wasm-traversal, into debuginfo.h, and use it in call-utils.h. debuginfo.h itself is renamed from debug.h (as now this needs to be included from wasm-traversal, which nearly everything does, and it turns out some files have internal stuff like a debug() helper that ends up conflicing with the old debug namespace). Also rename the old copyDebugInfo function to copyDebugInfoBetweenFunctions which is more explicit. That is also moved from the header to a cpp file because it depends on wasm-traversal (so we'd end up with recursive headers otherwise). That is fine, as that method is called after copying a function, which is not that frequent. The new copyDebugInfoToReplacement (which was refactored out of wasm-traversal) is in the header because it can be called very frequently (every single instruction we optimize) and we want it to get inlined.
* [Parser][NFC] Split parser into multiple compilation units (#6653)Thomas Lively2024-06-129-167/+369
| | | | | | | | | | | | Because the parser has five stages, it requires instantiating all of the templates in parsers.h with up to five different contexts. Instantiating all those templates in a single compilation unit takes a long time. On my machine, a release build of wat-parser.cpp.o took 32 seconds. To reduce the time of incremental rebuilds on machines with many cores, split the code across several compilation units so that the templates need to be instantiated for just a single context in each unit. On my machine the longest compilation time after this splitting is 17 seconds. The time for a full release build also drops from 42 seconds to 33 seconds. On machines with fewer cores, the benefit may be smaller or even negative, though.
* Fix wasm-split bug in absence of active element segments (#6651)Thomas Lively2024-06-111-7/+13
| | | | | | | | The module splitting code incorrectly assumed that there would be at least one active element segment and failed to initialize the table slot manager with a function table if that was not the case. Fix the bug by setting the table even when there are no active segments and add a test. Fixes #6572 and #6637.
* wasm2js: Add Table operations (#6650)Alon Zakai2024-06-114-17/+74
| | | | | | | TableGet, Set, Size, Grow, Fill, Copy. Also move "null" into shared-constants, to make the code more consistent overall.
* Fix scratch local optimizations when emitting string slice (#6649)Thomas Lively2024-06-111-31/+22
| | | | | | | | | | | | | | | | The binary writing of `stringview_wtf16.slice` requires scratch locals to store the `start` and `end` operands while the string operand is converted to a stringview. To avoid unbounded binary bloat when round-tripping, we detect the case that `start` and `end` are already `local.get`s and avoid using scratch locals by deferring the binary writing of the `local.get` operands until after the stringview conversoins is emitted. We previously optimized the scratch locals for `start` and `end` independently, but this could produce incorrect code in the case where the `local.get` for `start` is deferred but its value is changed by a `local.set` in the code for `end`. Fix the problem by only optimizing to avoid scratch locals in the case where both `start` and `end` are already `local.get`s, so they will still be emitted in the original relative order and they cannot interfere with each other anyway.
* [Strings] Keep public and private types separate in StringLowering (#6642)Alon Zakai2024-06-101-13/+39
| | | | | | | | | | | | | | | | We need StringLowering to modify even public types, as it must replace every single stringref with externref, even if that modifies the ABI. To achieve that we told it that all string-using types were private, which let TypeUpdater update them, but the problem is that it moves all private types to a new single rec group, which meant public and private types ended up in the same group. As a result, a single public type would make it all public, preventing optimizations and breaking things as in #6630 #6640. Ideally TypeUpdater would modify public types while keeping them in the same rec groups, but this may be a very specific issue for StringLowering, and that might be a lot of work. Instead, just make StringLowering handle public types of functions in a manual way, which is simple and should handle all cases that matter in practice, at least in J2Wasm.
* wasm2js: Add basic reference operations (#6648)Alon Zakai2024-06-104-17/+29
| | | This adds ref.eq, ref.null, ref.is_null, ref.func.
* Fix stack-use-after-scope on Windows in Precompute (#6643)mtb2024-06-051-1/+2
| | | | | Create a temp var to store the ChildIterator. Fixes #6639
* Effects: Add missing combining logic for MayNotReturn (#6635)Alon Zakai2024-06-031-0/+1
| | | | | | | | | | Without that logic we could end up dropping that particular effect. This actually made a test pass when it should not: the modified test here has a function with effects that are ok to remove, but it had a loop which adds MayNotReturn which we should actually not remove, so it was removed erroneously. To fix the test, add other effects there (local ones) that we can see are removable. Also add a function with a loop to test that we do not remove an infinite loop, which adds coverage for the fix here.
* Fix binary parser of declarative element segments (#6618)Rikito Taniguchi2024-06-031-1/+5
| | | | | | | | | | | | | | | The parser was incorrectly handling the parsing of declarative element segments whose `init` is a `vec(expr)`. https://webassembly.github.io/spec/core/binary/modules.html#element-section Binry parser was simply reading a single `u32LEB` value for `init` instead of parsing a expression regardless `usesExpressions = true`. This commit updates the `WasmBinaryReader::readElementSegments` function to correctly parse the expressions for declarative element segments by calling `readExpression` instead of `getU32LEB` when `usesExpressions = true`. Resolves the parsing exception: "[parse exception: bad section size, started at ... not being equal to new position ...]" Related discussion: https://github.com/tanishiking/scala-wasm/issues/136
* Optimize ReorderGlobals ordering with a new algorithm (#6625)Alon Zakai2024-05-311-71/+326
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The old ordering in that pass did a topological sort while sorting by uses both within topological groups and between them. That could be unoptimal in some cases, however, and actually on J2CL output this pass made the binary larger, which is how we noticed this. The problem is that such a toplogical sort keeps topological groups in place, but it can be useful to interleave them sometimes. Imagine this: $c - $a / $e \ $d - $b Here $e depends on $c, etc. The optimal order may interleave the two arms here, e.g. $a, $b, $d, $c, $e. That is because the dependencies define a partial order, and so the arms here are actually independent. Sorting by toplogical depth first might help in some cases, but also is not optimal in general, as we may want to mix toplogical depths: $a, $c, $b, $d, $e does so, and it may be the best ordering. This PR implements a natural greedy algorithm that picks the global with the highest use count at each step, out of the set of possible globals, which is the set of globals that have no unresolved dependencies. So we start by picking the first global with no dependencies and add at at the front; then that unlocks anything that depended on it and we pick from that set, and so forth. This may also not be optimal, but it is easy to make it more flexible by customizing the counts, and we consider 4 sorts here: * Set all counts to 0. This means we only take into account dependencies, and we break ties by the original order, so this is as close to the original order as we can be. * Use the actual use counts. This is the simple greedy algorithm. * Set the count of each global to also contain the counts of its children, so the count is the total that might be unlocked. This gives more weight to globals that can unlock more later, so it is less greedy. * As last, but weight children's counts lower in an exponential way, which makes sense as they may depend on other globals too. In practice it is simple to generate cases where 1, 2, or 3 is optimal (see new tests), but on real-world J2CL I see that 4 (with a particular exponential coefficient) is best, so the pass computes all 4 and picks the best. As a result it will never worsen the size and it has a good chance of improving. The differences between these are small, so in theory we could pick any of them, but given they are all modifications of a single algorithm it is very easy to compute them all with little code complexity. The benefits are rather small here, but this can save a few hundred bytes on a multi-MB Java file. This comes at a tiny compile time cost, but seems worth it for the new guarantee to never regress size.
* LogExecution: Optionally take a module name for the logger function (#6629)YAMAMOTO Takashi2024-05-311-12/+30
| | | | | | | | | --log-execution=NAME will use NAME as the module for the logger function import, rather than infer it. If the name is not provided (--log-execution as before this PR) then we will try to automatically decide which to use ("env", unless we see another module name is used, which can be the case in optimized modules).
* Avoid duplicate type names (#6633)Alon Zakai2024-05-302-4/+21
| | | | | If we replace a type with another, use the original name for the new type, and give the old a unique name (for the rare cases in which it has uses).
* Fix Vacuuming of code leading up to an infinite loop (#6632)Alon Zakai2024-05-291-4/+5
| | | | | We had that logic right in other places, but the specific part of Vacuum that looks at code that leads up to an unreachable did not check for infinite loops, so it could remove them.
* SignaturePruning: Properly handle public types (#6630)Alon Zakai2024-05-293-18/+46
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The SignaturePruning pass optimizes away parameters that it proves are safe to remove. It turns out that that does not always match the definition of private types, which is more restrictive. Specifically, if say all the types are in one big rec group and one of them is used on an exported function then all of them are considered public (as the rec group is). However, in closed world, it would be ok to leave that rec group unchanged but to create a pruned version of that type and use it, in cases where we see it is safe to remove a parameter. (See the testcase for a concrete example.) To put it another way, SignaturePruning already proves that a parameter is safe to remove in all the ways that matter. Before this PR, however, the testcase in this PR would error - so this PR is not an optimization but a bugfix, really - because SignaturePruning would see that a parameter is safe to remove but then TypeUpdating would see the type is public and so it would leave it alone, leading to a broken module. This situation is in fact not that rare, and happens on real-world Java code. The reason we did not notice it before is that typically there are no remaining SignaturePruning opportunities late in the process (when other closed world optimizations have typically led to a single big rec group). The concrete fix here is to add additionalPrivateTypes to a few more places in TypeUpdating. We already supported that for cases where a pass knew better than the general logic what can be modified, and this adds that ability to the signature-rewriting logic there. Then SignaturePruning can send in all the types it has proven are safe to modify. * Also necessary here is to only add from additionalPrivateTypes if the type is not already in our list (or we'd end up with duplicates in the final rec group). * Also move newSignatures in SignaturePruning out of the top level, which was confusing (the pass has multiple iterations, and we want each to have a fresh instance).
* [NFC] Save a line in wasm-shell.cpp (#6631)Thomas Lively2024-05-291-2/+1
|
* Remove obsolete parser code (#6607)Thomas Lively2024-05-2913-8992/+3
| | | | | Remove `SExpressionParser`, `SExpressionWasmBuilder`, and `cashew::Parser`. Simplify gen-s-parser.py. Remove the --new-wat-parser and --deprecated-wat-parser flags.