summaryrefslogtreecommitdiff
path: root/scripts
Commit message (Collapse)AuthorAgeFilesLines
* Fix OOB string_view read in generated parser code (#5349)Thomas Lively2022-12-141-7/+5
| | | | | | | | | The `op` string_view was intentionally created to point into the `buf` buffer so that reading past its end would still be safe, but some C++ standard library implementations assert when reading past the end of a string_view. Change the generated code to read out of `buf` instead to avoid those assertions. Fixes #5322. Fixes #5342.
* Add standard versions of WasmGC casts (#5331)Thomas Lively2022-12-071-9/+12
| | | | | | | We previously supported only the non-standard cast instructions introduced when we were experimenting with nominal types. Parse the names and opcodes of their standard counterparts and switch to emitting the standard names and opcodes. Port all of the tests to use the standard instructions, but add additional tests showing that the non-standard versions are still parsed correctly.
* [Wasm GC] Add TypeMerging pass (#5321)Alon Zakai2022-12-071-0/+1
| | | | | | | | This finds types that can be merged into their super: types that add no fields, and are not used in casts, etc. - so we might as well use the super. This complements TypeSSA, in that it can merge back the new types that TypeSSA created, if we never found a use for them. Without this, TypeSSA can bloat binary size quite a lot (I see 10-20%).
* [Wasm GC] Add TypeSSA pass (#5299)Alon Zakai2022-12-021-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This creates new nominal types for each (interesting) struct.new. That then allows type-based optimizations to be more precise, as those optimizations will track separate info for each struct.new, in effect. That is kind of like SSA, however, we do not handle merges. For example: x = struct.new $A (5); print(x.value); y = struct.new $A (11); print(y.value); // => // x = struct.new $A.x (5); print(x.value); y = struct.new $A.y (11); print(y.value); After the pass runs each of those struct.new creates a unique type, and type-based analysis can see that 5 or 11 are the only values written in that type (if nothing else writes there). This bloats the type section with the new subtypes, so it is best used with a pass to merge unneeded duplicate types, which a later PR will add. That later PR will exactly merge back in the types created here, which are nominally different but indistinguishable otherwise. This pass is not enabled by default. It's not clear yet where is the best place to do it, as it must be balanced by type merging, but it might be better to do multiple rounds of optimization between the two. Needs more investigation.
* [Wasm GC] Implement closed-world flag (#5303)Alon Zakai2022-11-301-0/+3
| | | | | | | | | | | | | With this change we default to an open world, that is, we do the safe thing by default: we no longer assume a closed world. Users that want a closed world must pass --closed-world. Atm we just do not run passes that assume a closed world. (We might later refine them to find which types don't escape and only optimize those.) The RemoveUnusedModuleElements is an exception in that the closed-world flag influences one part of its operation, but not the rest. Fixes #5292
* Unpin V8 (#5277)Thomas Lively2022-11-171-3/+1
| | | | | | | | | | | | | | * Do not compare reference values across executions Since we optimize assuming a closed world, optimizations can change the types and structure of GC data even in externally-visible ways. Because differences are expected, the fuzzer already did not compare reference-typed values from before and after optimizations when running with nominal typing. Update it to not compare these values under any type system. * Unpin V8 Our WasmGC output is no longer compatible with the previously pinned version and the issue that caused us to pin it in the first place has been resolved.
* [Wasm GC] Start an OptimizeCasts pass and reuse cast values there (#5263)Alon Zakai2022-11-171-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | (some.operation (ref.cast .. (local.get $ref)) (local.get $ref) ) => (some.operation (local.tee $temp (ref.cast .. (local.get $ref)) ) (local.get $temp) ) This can help cases where we cast for some reason but happen to not use the cast value in all places. This occurs in j2wasm in itable calls sometimes: The this pointer is is refined, but the itable may be done with an unrefined pointer, which is less optimizable. So far this is just inside basic blocks, but that is enough for the cast of itable calls and other common patterns I see.
* [Wasm GC] Add Monomorphize pass (#5238)Alon Zakai2022-11-111-0/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | Monomorphization finds cases where we send more refined types to a function than it declares. In such cases we can copy the function and refine the parameters: // B is a subtype of A foo(new B()); function foo(x : A) { ..} => foo_B(new B()); // call redirected to refined copy function foo(x : A) { ..} // unchanged function foo_B(x : B) { ..} // refined copy This increases code size so it may not be worth it in all cases. This initial PR is hopefully enough to start experimenting with this on performance, and so it does not enable the pass by default. This adds two variations of monomorphization, one that always does it, and the default which is "careful": it sees whether monomorphizing lets the refined function actually be better than the original (say, by removing a cast). If there is no improvement then we do not make any changes. This saves a significant amount of code size - on j2wasm the careful version increases by 13% instead of 20% - but it does run more slowly obviously.
* Implement `array.new_data` and `array.new_elem` (#5214)Thomas Lively2022-11-071-0/+2
| | | | | | | | | In order to test them, fix the binary and text parsers to accept passive data segments even if a module has no memory. In addition to parsing and emitting the new instructions, also implement their validation and interpretation. Test the interpretation directly with wasm-shell tests adapted from the upstream spec tests. Running the upstream spec tests directly would require fixing too many bugs in the legacy text parser, so it will have to wait for the new text parser to be ready.
* Fix fuzzer default contents after #5212 (#5223)Thomas Lively2022-11-071-1/+1
| | | | | | | That PR renamed test/lit/optimize-instructions.wast to test/lit/optimize-instructions-mvp.wast. However, the fuzzer was explicitly adding the testto the list of important initial contents under the old name, so it was failing an assertion that the initial contents existed. Update the fuzzer to use the new test name.
* [Wasm GC] Fix GUFA on externalize/internalize (#5220)Alon Zakai2022-11-041-0/+1
| | | | | | | These operations emit a completely different type than their input, so they must be marked as roots, and not as things that flow values through them (because then we filter everything out as the types are not compatible). Fixes #5219
* Fuzzer: Skip fuzzing VMs when multi-memories are enabled (#5207)Alon Zakai2022-11-031-3/+3
|
* Fix fuzzer to ignore externalize/internalize (#5176)Alon Zakai2022-10-211-0/+2
| | | | | The fuzzer started to fail on the recent externalize/internalize test that was added in #5175 as we lack interpreter support. Move that to a separate file and ignore it in the fuzzer for now.
* [Parser] Parse loads and stores (#5174)Thomas Lively2022-10-211-24/+28
| | | | | | | | | | Add parsing functions for `memarg`s, the offset and align fields of load and store instructions. These fields are interesting because they are lexically reserved words that need to be further parsed to extract their actual values. On top of that, add support for parsing all of the load and store instructions. This required fixing a buffer overflow problem in the generated parser code and adding more information to the signatures of the SIMD load and store instructions. `SIMDLoadStoreLane` instructions are particularly interesting because they may require backtracking to parse correctly.
* [NFC] Avoid re-parsing instruction names (#5171)Thomas Lively2022-10-201-88/+88
| | | | | | | | | Since gen-s-parser.py is essentially a giant table mapping instruction names to the information necessary to construct the corresponding IR nodes, there should be no need to further parse instruction names after the code generated by gen-s-parser.py runs. However, memory instruction parsing still parsed instruction names to get information such as size and default alignment. The new parser does not have the ability to parse that information out of instruction names, so put it in the gen-s-parser.py table instead.
* [Parser][NFC] Pass instruction locations to `makeXXX` functions (#5133)Thomas Lively2022-10-121-2/+2
| | | | | | | | The `makeXXX` functions that are responsible for individual instructions will generally need the locations of those functions to emit useful errors. However, since the instruction names are parsed before the `makeXXX` functions are called, the functions have no good way of getting the location of the beginning of the instruction. Fix this by explicitly passing them the location of the beginning of the instruction.
* [Parser][NFC] Move `ParseInput` into the parser context (#5132)Thomas Lively2022-10-121-2/+2
| | | | | | | | | | | | | Rather than passing both a `Ctx` and a `ParseInput` to every parsing function, pass only a `Ctx` with a `ParseInput` inside of it. This significantly reduces verbosity in the parser. To handle cases where parsing needs to happen at specific locations, which used to be handled by constructing a new `ParseInput` independent from the ctx, introduce a new RAII utility for temporarily changing the location of the `ParseInput` inside a context. Also add a utility for generating an error at a particular location to avoid having to construct new `ParseInput` objects just for that purpose. This resolves a few TODOs about correcting error locations, but since we don't test those yet, I still consider this NFC.
* Make `Name` a pointer, length pair (#5122)Thomas Lively2022-10-111-3/+6
| | | | | | | | | | | | | | | | | | | | | | | With the goal of supporting null characters (i.e. zero bytes) in strings. Rewrite the underlying interned `IString` to store a `std::string_view` rather than a `const char*`, reduce the number of map lookups necessary to intern a string, and present a more immutable interface. Most importantly, replace the `c_str()` method that returned a `const char*` with a `toString()` method that returns a `std::string`. This new method can correctly handle strings containing null characters. A `const char*` can still be had by calling `data()` on the `std::string_view`, although this usage should be discouraged. This change is NFC in spirit, although not in practice. It does not intend to support any particular new functionality, but it is probably now possible to use strings containing null characters in at least some cases. At least one parser bug is also incidentally fixed. Follow-on PRs will explicitly support and test strings containing nulls for particular use cases. The C API still uses `const char*` to represent strings. As strings containing nulls become better supported by the rest of Binaryen, this will no longer be sufficient. Updating the C and JS APIs to use pointer, length pairs is left as future work.
* Fix fuzzer after #5114 (#5117)Sam Clegg2022-10-061-7/+7
| | | Fixes ./scripts/fuzz_opt.py --auto-initial-contents 7044408155933374954
* Pin v8 10.8.104 (#5112)Thomas Lively2022-10-051-1/+4
| | | | | | More recent version of V8 include a change from `dataref` to `structref` that prevent WasmGC modules produced by the fuzzer from validating. Use the last compatible v8 version if it is in the path until we can update Binaryen to be compatible with newer v8.
* [Strings] Add missing String effects + tests (#5057)Alon Zakai2022-09-191-0/+1
| | | Also fix some formatting issue in the file.
* Allow optimizing with global function effects (#5040)Alon Zakai2022-09-161-0/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This adds a map of function name => the effects of that function to the PassOptions structure. That lets us compute those effects once and then use them in multiple passes afterwards. For example, that lets us optimize away a call to a function that has no effects: (drop (call $nothing)) [..] (func $nothing ;; .. lots of stuff but no effects, only a returned value .. ) Vacuum will remove that dropped call if we tell it that the called function has no effects. Note that a nice result of adding this to the PassOptions struct is that all passes will use the extra info automatically. This is not enabled by default as the benefits seem rather minor, though it does help in a small but noticeable way on J2Wasm code, where we use call.without.effects and have situations like this: (func $foo (call $bar) ) (func $bar (call.without.effects ..) ) The call to bar looks like it has effects, normally, but with global effect info we know it actually doesn't. To use this, one would do --generate-global-effects [.. some passes that use the effects ..] --discard-global-effects Discarding is not necessary, but if there is a pass later that adds effects, then not discarding could lead to bugs, since we'd think there are fewer effects than there are. (However, normal optimization passes never add effects, only remove them.) It's also possible to call this multiple times: --generate-global-effects -O3 --generate-global-effects -O3 That computes affects after the first -O3, and may find fewer effects than earlier. This doesn't compute the full transitive closure of the effects across functions. That is, when computing a function's effects, we don't look into its own calls. The simple case so far is enough to handle the call.without.effects example from before (though it may take multiple optimization cycles).
* Remove typed-function-references feature (#5030)Thomas Lively2022-09-091-1/+0
| | | | | | | | | | | | | | | | In practice typed function references will not ship before GC and is not independently useful, so it's not necessary to have a separate feature for it. Roll the functionality previously enabled by --enable-typed-function-references into --enable-gc instead. This also avoids a problem with the ongoing implementation of the new GC bottom heap types. That change will make all ref.null instructions in Binaryen IR refer to one of the bottom heap types. But since those bottom types are introduced in GC, it's not valid to emit them in binaries unless unless GC is enabled. The fix if only reference types is enabled is to emit (ref.null func) instead of (ref.null nofunc), but that doesn't always work if typed function references are enabled because a function type more specific than func may be required. Getting rid of typed function references as a separate feature makes this a nonissue.
* [Wasm GC] Support non-nullable locals in the "1a" form (#4959)Alon Zakai2022-08-311-1/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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
* Implement `extern.externalize` and `extern.internalize` (#4975)Thomas Lively2022-08-292-1/+5
| | | | These new GC instructions infallibly convert between `extern` and `any` references now that those types are not in the same hierarchy.
* Simplify TrapsNeverHappen fuzzing (#4957)Alon Zakai2022-08-241-4/+5
| | | | Also fix a small logic error - call lines can be prefixes of each other, so use the full line (including newline) to differentiate.
* [Fuzzer] Fuzz TrapsNeverHappen mode (#4936)Alon Zakai2022-08-221-2/+85
| | | | | | | | | | | | | | | | This mode is tricky to fuzz because the mode is basically "assume traps never happen; if a trap does happen, that is undefined behavior". So if any trap occurs in the random fuzz testcase, we can't optimize with -tnh and assume the results stay to same. To avoid that, we ignore all functions from the first one that traps, that is, we only compare the code that ran without trapping. That often is a small subset of the total functions, sadly, but I do see that this ends up with some useful coverage despite the drawback. This also requires some fixes to comparing of references, specifically, funcrefs are printed with the function name/index, but that can change during opts, so ignore that. This wasn't noticed before because this new fuzzer mode does comparisons of --fuzz-exec-before output, instead of doing --fuzz-exec which runs it before and after and compares it internally in wasm-opt. Here we are comparing the output externally, which we didn't do before.
* Mutli-Memories Support in IR (#4811)Ashley Nelson2022-08-171-0/+8
| | | | | | | 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.
* Fix require() in wasm2js test suite for newer Node.js (#4913)Alon Zakai2022-08-171-0/+2
| | | | | | | Without this fix, newer node errors on: "node-esm-loader.mjs 'resolve'" did not call the next hook in its chain and did not explicitly signal a short circuit. If this is intentional, include `shortCircuit: true` in the hook's return. This adds that shortCircuit property.
* Fuzzer: When typed-function-references is disabled, disable GC too (#4908)Alon Zakai2022-08-161-1/+2
|
* Fix name of port_passes_tests_to_lit.py script. NFC (#4902)Sam Clegg2022-08-121-2/+2
| | | I was reading these tests and failing to find the names script.
* Port test/passes/legalize-js-interface* to lit (#4903)Sam Clegg2022-08-121-3/+12
| | | | | Also, add support for the `--binaryen-bin` flag to `scripts/port_passes_tests_to_lit.py`. This is needed for folks who don't do in-tree builds.
* Move `auto_update_tests.py` into scripts directory. NFC (#4879)Sam Clegg2022-08-112-2/+202
| | | | So it lives alongside `update_lit_checks.py` and `update_help_checks.py`
* Fuzzer: Emit absolute paths in commands (#4890)Alon Zakai2022-08-101-28/+31
| | | | | | | * better * fix * undo
* Fuzzer: Add some docs and error handling" (#4887)Alon Zakai2022-08-091-4/+19
|
* Remove metadata generation from wasm-emscripten-finalize (#4863)Sam Clegg2022-08-071-10/+0
| | | | This is no longer needed by emscripten as of: https://github.com/emscripten-core/emscripten/pull/16529
* Remove RTTs (#4848)Thomas Lively2022-08-052-18/+9
| | | | | | | RTTs were removed from the GC spec and if they are added back in in the future, they will be heap types rather than value types as in our implementation. Updating our implementation to have RTTs be heap types would have been more work than deleting them for questionable benefit since we don't know how long it will be before they are specced again.
* Bail out of fuzz_shell.js if instantiation fails (#4873)Thomas Lively2022-08-041-2/+9
| | | | | | | | | Sometimes the fuzzer produces valid modules that trap during instantiation. When that happens, the JS harness used to run the fuzzer output in d8 would previously throw an error, creating spurious fuzzer failures on valid modules. Update fuzz_shell.js to catch and supress errors during instantiation (but not validation) to avoid these spurious failures. Fixes #4865.
* Re-run scripts/test/generate_lld_tests.py. NFC (#4861)Sam Clegg2022-08-021-4/+6
|
* Grand Unified Flow Analysis (GUFA) (#4598)Alon Zakai2022-07-221-0/+2
| | | | | | | | | | | | | This tracks the possible contents in the entire program all at once using a single IR. That is in contrast to say DeadArgumentElimination of LocalRefining etc., all of whom look at one particular aspect of the program (function params and returns in DAE, locals in LocalRefining). The cost is to build up an entire new IR, which takes a lot of new code (mostly in the already-landed PossibleContents). Another cost is this new IR is very big and requires a lot of time and memory to process. The benefit is that this can find opportunities that are only obvious when looking at the entire program, and also it can track information that is more specialized than the normal type system in the IR - in particular, this can track an ExactType, which is the case where we know the value is of a particular type exactly and not a subtype.
* [Strings] GC variants for string.encode (#4817)Alon Zakai2022-07-211-0/+2
|
* [Strings] Add string.new GC variants (#4813)Alon Zakai2022-07-191-0/+2
|
* [Strings] stringview_wtf16.length (#4809)Alon Zakai2022-07-181-0/+1
| | | | This measures the length of a view, so it seems simplest to make it a sub-operation of the existing measure instruction.
* [Strings] stringview_*.slice (#4805)Alon Zakai2022-07-151-0/+3
| | | | | | | Unfortunately one slice is the same as python [start:end], using 2 params, and the other slice is one param, [CURR:CURR+num] (where CURR is implied by the current state in the iter). So we can't use a single class here. Perhaps a different name would be good, like slice vs substring (like JS does), but I picked names to match the current spec.
* [Strings] stringview access operations (#4798)Alon Zakai2022-07-131-0/+5
|
* [Strings] string.as (#4797)Alon Zakai2022-07-121-0/+3
|
* [Parser] Start to parse instructions (#4789)Thomas Lively2022-07-111-6/+22
| | | | | | | | | | | | | | | | | | | | | Update gen-s-parser.py to produce a second version of its parsing code that works with the new wat parser. The new version automatically replaces the `s` element argument in the existing parser with the `ctx` and `in` arguments used by the new parser, so adding new instructions will not require any additional work in gen-s-parser.py after this change. Also add stub `make***` functions to the new wat parser, with a few filled out, namely `makeNop`, `makeUnreachable`, `makeConst`, and `makeRefNull`. Update the `global` parser to parse global initializer instructions and update wat-kitchen-sink.wast to demonstrate that the instructions are parsed correctly. Adding new instruction classes will require adding a new `make***` function to wat-parser.cpp in additional to wasm-s-parser.{h,cpp} after this change, but adding a trivial failing implementation is good enough for the time being, so I don't expect this to appreciably increase our maintenance burden in the near term. The infrastructure for parsing folded instructions, instructions with operands, and control flow instructions will be implemented in future PRs.
* Parse `rec` in update_lit_checks.py (#4784)Thomas Lively2022-07-081-1/+1
|
* [Strings] string.is_usv_sequence (#4783)Alon Zakai2022-07-081-0/+1
| | | | | | | This implements it as a StringMeasure opcode. They do have the same number of operands, same trapping behavior, and same return type. They both get a string and do some inspection of it to return an i32. Perhaps the name could be StringInspect or something like that, rather than StringMeasure..? But I think for now this might be good enough, and the spec may change anyhow later.
* [Strings] string.eq (#4781)Alon Zakai2022-07-081-0/+1
|