summaryrefslogtreecommitdiff
path: root/src
Commit message (Collapse)AuthorAgeFilesLines
...
* [TypedFunctionReferences] Add Typed Function References feature and use the ↵Alon Zakai2020-11-2318-166/+367
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | types (#3388) This adds the new feature and starts to use the new types where relevant. We use them even without the feature being enabled, as we don't know the features during wasm loading - but the hope is that given the type is a subtype, it should all work out. In practice, if you print out the internal type you may see a typed function reference-specific type for a ref.func for example, instead of a generic funcref, but it should not affect anything else. This PR does not support non-nullable types, that is, everything is nullable for now. As suggested by @tlively this is simpler for now and leaves nullability for later work (which will apparently require let or something else, and many passes may need to be changed). To allow this PR to work, we need to provide a type on creating a RefFunc. The wasm-builder.h internal API is updated for this, as are the C and JS APIs, which are breaking changes. cc @dcodeIO We must also write and read function types properly. This PR improves collectSignatures to find all the types, and also to sort them by the dependencies between them (as we can't emit X in the binary if it depends on Y, and Y has not been emitted - we need to give Y's index). This sorting ends up changing a few test outputs. InstrumentLocals support for printing function types that are not funcref is disabled for now, until we figure out how to make that work and/or decide if it's important enough to work on. The fuzzer has various fixes to emit valid types for things (mostly whitespace there). Also two drive-by fixes to call makeTrivial where it should be (when we fail to create a specific node, we can't just try to make another node, in theory it could infinitely recurse). Binary writing changes here to replace calls to a standalone function to write out a type with one that is called on the binary writer object itself, which maintains a mapping of type indexes (getFunctionSignatureByIndex).
* [wasm-split] Initial instrumentation (#3389)Thomas Lively2020-11-201-2/+197
| | | | | | | | | | | | | Implement an instrumentation pass that records the timestamp at which each defined function is first called. Timestamps are not actual time, but rather snapshots of a monotonically increasing counter. The instrumentation exports a function that the embedder can call to dump the profile data into a memory buffer at a given offset and size. The function returns the total size of the profile data so the embedder can know how much to read out of the buffer or how much it needs to grow the buffer. Parsing and using the profile is left as future work, as is recording a hash of the input file that will be used to guard against accidentally instrumenting one module and trying to use the resulting profile to split a different module.
* Initial wasm-split tool (#3359)Thomas Lively2020-11-192-1/+368
| | | | | | | | | | | | | Implement an initial version of the wasm-split tool, which splits modules into a primary module and a secondary module that can be instantiated after the primary module. Eventually, this tool will be able to not only split modules, but also instrument modules to collect profiles that will be able to guide later splitting. In this initial version, however, wasm-split can neither perform instrumentation nor consume any kind of profile data. Despite those shortcomings, this initial version of the tool is already able to perform module splitting according to function lists manually provided by the user via the command line. Follow-up PRs will implement the stubbed out instrumentation and profile consumption functionality.
* [wasm-builder] Construct module elements as unique_ptrs (#3391)Thomas Lively2020-11-1910-97/+96
| | | | | | | | | When Functions, Globals, Events, and Exports are added to a module, if they are not already in std::unique_ptrs, they are wrapped in a new std::unique_ptr owned by the Module. This adds an extra layer of indirection when accessing those elements that can be avoided by allocating those elements as std::unique_ptrs. This PR updates wasm-builder to allocate module elements via std::make_unique rather than `new`. In the future, we should remove the raw pointer versions of Module::add* to encourage using std::unique_ptrs more broadly.
* [effects.h] Add a trap effect for unreachable (#3387)Alon Zakai2020-11-181-11/+18
| | | | | | | | | | | We did not really model the effects of unreachable properly before. It always traps, so it's not an implicit trap, but we didn't do anything but mark it as "branches out", which is not really enough, as while yes it does branch inside the current function, it also traps which is noticeable outside. To fix that, add a trap effect to track this. implicitTrap will set trap as well, automatically, if we do not ignore implicit traps, so it is enough to check just that (unless one cares about the difference between implicit and explicit ones).
* [DeadArgumentElimination] Don't DAE a ref.func-ed class (#3380)Alon Zakai2020-11-181-7/+34
| | | | | | | | | | | If we take a reference of a function, it is dangerous to change the function's type (which removing dead arguments does), as that would be an observable different from the outside - the type changes, and some params are now ignored, and others are reordered. In theory we could find out if the reference does not escape, but that's not trivial. Related to #3378 but not quite the same.
* [Types] Handle function types fully in more places (#3381)Alon Zakai2020-11-185-101/+120
| | | | | | | | Call isFunction to check for a general function type instead of just a funcref, in places where we care about both, and some other minor miscellaneous typing fixes in preparation for typed function references (this will be tested fully at that time). Change is mostly whitespace.
* Remove unused Pass::prepareToRun (#3386)Thomas Lively2020-11-183-14/+0
|
* [effects.h] Make internals internal, forcing the external API to be safe. ↵Alon Zakai2020-11-183-301/+336
| | | | | | | | | | | | | | | | | (#3385) A user of EffectAnalyzer could call walk or visit, to walk the entire input or just visit the node without chlidren. But this was unsafe - we just exposed the Walker/Visitor API here, and did not ensure that users did the stuff in analyze which does a little stuff before and after. In fact Vacuum got this wrong. To avoid that, move all the internals to an internal class. The external API now only allows the caller to call walk or visit, and both are safe. The change here is mostly whitespace + adding parent. prefixes. This is NFC except for fixing possible Vacuum issues (which I am not sure could happen in practice or not).
* [Reducer] Don't error on compound types, just don't reduce them more for now ↵Alon Zakai2020-11-171-1/+4
| | | | (#3383)
* [effects.h] Refactor hasGlobalSideEffects and throw handling. (#3370)Alon Zakai2020-11-172-19/+29
| | | | | | | | The new writesGlobalState has a name that more clearly indicates what it actually does: affect global state (that is, memory, globals, the table, etc.). This removes throw from there, and handles it directly in the single caller of the method, the licm pass. For simplicity, disallow exceptions in that pass, leaving it for future work.
* [Fuzzer] Don't compare references, just their types (#3384)Alon Zakai2020-11-171-14/+44
| | | | | | | There are several issues here that we can't fully handle, see #3378, but basically we are comparing results between two separate wasm modules (and a separate instance of each) - we can't really identify an identical reference between such things. We can only compare things structurally, for which we compare the types.
* [ReReloop] Pass module when calling ReFinalize (#3382)Alon Zakai2020-11-171-1/+1
| | | | | | I happened to notice that this was the one place that calls ReFinalize without the module. That could error if the module is actually needed, which the pass might use, based on the code (but rare enough that it's never been an issue I guess).
* [cost.h] Define costs for I31New and I31Get which the fuzzer emits (#3373)Alon Zakai2020-11-171-2/+2
| | | | | | | | cost.h now requires costs be defined, or it halts at runtime. But the fuzzer already emits those two, so define them to unbreak the fuzzer. Both access a reference, so they should be at least as costly as a load. I31New also allocates, which is very cheap on a generational GC, so do not add much for that.
* [cost.h] Require all expressions to be define a cost (#3363)Alon Zakai2020-11-151-1/+16
| | | | | | Almost NFC, but adds a cost to DataDrop, 5, which tries to reflect that it is costlier than a call (it calls into VM internals) but also not much more, as it actually helps perf in the long term, so it should be preferred where possible.
* Minor code cleanups. NFC (#3364)Alon Zakai2020-11-152-15/+1
| | | The vacuum code can be deleted as it is handled by the default anyhow.
* [Types] Add type sorting for Signatures (#3366)Alon Zakai2020-11-151-9/+22
|
* [TypedFunctionReferences] Identify subtyping between funcref and all typed ↵Alon Zakai2020-11-141-2/+15
| | | | function references (#3357)
* [TypedFunctionReferences] Allow creation of literals with typed function ↵Alon Zakai2020-11-142-3/+6
| | | | | | | types (#3358) * [TypedFunctionReferences] Allow creation of literals with typed function types * feedback
* [s-parsing] Store full function signatures (#3356)Alon Zakai2020-11-132-5/+5
| | | | | We will need this for typed function references support, as then we need to know full function signatures for all functions when we reach a ref.func, whose type is then that signature and not the generic funcref.
* Rename Indirect to NonDirect in CallGraphPropertyAnalysis in preparation for ↵Alon Zakai2020-11-133-12/+16
| | | | | | | | | | CallRef (#3355) This is in preparation for CallRef, which takes a reference to a function and calls it. CallGraphPropertyAnalysis needs to be aware of anything that is not a direct call, and "NonDirect" is meant to cover both CallIndirect and CallRef.
* Rename atomic.notify and *.atomic.wait (#3353)Heejin Ahn2020-11-135-45/+56
| | | | | | | | | | | | | | - atomic.notify -> memory.atomic.notify - i32.atomic.wait -> memory.atomic.wait32 - i64.atomic.wait -> memory.atomic.wait64 See WebAssembly/threads#149. This renames instruction name printing but not the internal data structure names, such as `AtomicNotify`, which are not always the same as printed instruction names anyway. This also does not modify C API. But this fixes interface functions in binaryen.js because it seems binaryen.js's interface functions all follow the corresponding instruction names.
* [wasm64] fix for Memory64Lowering affecting DWARF data (#3348)Wouter van Oortmerssen2020-11-131-2/+10
| | | | We change the AddrSize which causes all DW_FORM_addr to be written differently. Depends on https://reviews.llvm.org/D91395
* Fix warnings in delegations-fields headerAlon Zakai2020-11-131-63/+63
|
* Quick followup to #3349 - avoid unnecessary allocations (#3354)Alon Zakai2020-11-131-6/+31
|
* Make getExpressionName resemble instruction names (#3352)Heejin Ahn2020-11-131-9/+9
| | | | | | | | | | | | | | | This function does not return exact instruction names but more of category names. But when there is a matching instruction, as in case of `global.get/set` or `local.get/set`, it seems to return instruction names. In that regard, this makes `getExpressionName`'s return values to similar to that of real instruction names when possible, in case of some atomic instructions and `memory.init/copy` and `data.drop`. It is hard to make a test for this because this function is used in a very limited way in the codebase, such as: - When printing error messages - When printing a stack instruction names, but only for control flow instructions - When printing instruction names in Metrics
* Fix a hashing regression from #3332 (#3349)Alon Zakai2020-11-131-28/+6
| | | | | | | | | | | | | | | We used to check if a load's sign matters before hashing it. If the load does not extend, then the sign doesn't matter, and we ignored the value there. It turns out that value could be garbage, as we didn't assign it in the binary reader, if it wasn't relevant. In the rewrite this was missed, and actually it's not really possible to do, since we have just a macro for the field, but not the object it is on - which there may be more than one. To fix this, just always assign the field. This is simpler anyhow, and avoids confusion not just here but probably when debugging. The testcase here is reduced from the fuzzer, and is not a 100% guarantee to catch a read of uninitialized memory, but it can't hurt, and with ASan it may be pretty consistent.
* Remove boilerplate in wasm-stack.h (#3347)Alon Zakai2020-11-121-64/+4
|
* Remove some boilerplate in the C API (#3346)Alon Zakai2020-11-123-212/+16
| | | | Also slightly reorder some code in the binary writer headers, that I noticed while looking for boilerplate.
* Module splitting (#3317)Thomas Lively2020-11-127-9/+566
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Adds the capability to programatically split a module into a primary and secondary module such that the primary module can be compiled and run before the secondary module has been instantiated. All calls to secondary functions (i.e. functions that have been split out into the secondary module) in the primary module are rewritten to be indirect calls through the table. Initially, the table slots of all secondary functions contain references to imported placeholder functions. When the secondary module is instantiated, it will automatically patch the table to insert references to the original functions. The process of module splitting involves these steps: 1. Create the new secondary module. 2. Export globals, events, tables, and memories from the primary module and import them in the secondary module. 3. Move the deferred functions from the primary to the secondary module. 4. For any secondary function exported from the primary module, export in its place a trampoline function that makes an indirect call to its placeholder function (and eventually to the original secondary function), allocating a new table slot for the placeholder if necessary. 5. Rewrite direct calls from primary functions to secondary functions to be indirect calls to their placeholder functions (and eventually to their original secondary functions), allocating new table slots for the placeholders if necessary. 6. For each primary function directly called from a secondary function, export the primary function if it is not already exported and import it into the secondary module. 7. Replace all references to secondary functions in the primary module's table segments with references to imported placeholder functions. 8. Create new active table segments in the secondary module that will replace all the placeholder function references in the table with references to their corresponding secondary functions upon instantiation. Functions can be used or referenced three ways in a WebAssembly module: they can be exported, called, or placed in a table. The above procedure introduces a layer of indirection to each of those mechanisms that removes all references to secondary functions from the primary module but restores the original program's semantics once the secondary module is instantiated. As more mechanisms that reference functions are added in the future, such as ref.func instructions, they will have to be modified to use a similar layer of indirection. The code as currently written makes a few assumptions about the module that is being split: 1. It assumes that mutable-globals is allowed. This could be worked around by introducing wrapper functions for globals and rewriting secondary code that accesses them, but now that mutable-globals is shipped on all browsers, hopefully that extra complexity won't be necessary. 2. It assumes that all table segment offsets are constants. This simplifies the generation of segments to actively patch in the secondary functions without overwriting any other table slots. This assumption could be relaxed by 1) having secondary segments re-write primary function slots as well, 2) allowing addition in segment offsets, or 3) synthesizing a start function to modify the table instead of using segments. 3. It assumes that each function appears in the table at most once. This isn't necessarily true in general or even for LLVM output after function deduplication. Relaxing this assumption would just require slightly more complex code, so it is a good candidate for a follow up PR. Future Binaryen work for this feature includes providing a command line tool exposing this functionality as well as C API, JS API, and fuzzer support. We will also want to provide a simple instrumentation pass for finding dead or late-executing functions that would be good candidates for splitting out. It would also be good to integrate that instrumentation with future function outlining work so that dead or exceptional basic blocks could be split out into a separate module.
* Remove boilerplate in walking logic (#3344)Alon Zakai2020-11-122-348/+29
| | | | | | Also fix the order of walking children, which was wrong in the macro. What's nice is that fixing it there would fix anything else using the macro automatically (however, so far nothing else was affected by it).
* Some refactorings in addition to #3338 (#3336)Max Graey2020-11-121-16/+10
| | | | See discussion in #3303
* Remove boilerplate in utils.h (#3340)Alon Zakai2020-11-123-139/+10
| | | Also avoid needing to #undef DELEGATE all the time.
* OptimizeInstructions: Fix regression from #3303 / #3275 (#3338)Alon Zakai2020-11-121-6/+5
| | | | | | | | | | | | | | | | | X - Y <= 0 => X <= Y That is true mathematically, but not in the case of an overflow, e.g. X=10, Y=0x8000000000000000. X - Y is a negative number, so X - Y <= 0 is true. But it is not true that X <= Y (as Y is negative, but X is not). See discussion in #3303 (comment) The actual regression was in #3275, but the fuzzer had an easier time finding it due to #3303
* Fix BinaryenFunctionOptimize. (#3339)Alon Zakai2020-11-111-1/+1
| | | | | | We mistakenly tried to run all passes there, but should run only the function ones. Fixes #3333
* wasm2js: Declare data segments before calling asmFunc (#3337)Sam Clegg2020-11-111-69/+97
| | | | | | | | | This is because we maybe need to reference the segments during the start function. For example in the case of pthreads we conditionally load passive segments during start. Tested in emscripten with: tests/runner.py wasm2js1
* Avoid boilerplate in ExpressionAnalyzer comparing & hashing (#3332)Alon Zakai2020-11-113-376/+248
| | | | | | | | | | | | | | | | | | | | Expands on #3294: * Scope names must be distinguished as either defs or uses. * Error when a core #define is missing, which is less error-prone, as suggested by @tlively * Add DELEGATE_GET_FIELD which lets one define "get the field" once and then all the loops can use it. This helps avoid boilerplate for loops at least in some cases (when there is a single object on which to get the field). With those, it is possible to replace boilerplate in comparisons and hashing logic. This also fixes a bug where BrOnExn::sent was not scanned there. Add some unit tests for hashing. We didn't have any, and hashing can be subtly wrong without observable external effects (just more collisions).
* wasm2js: Support for exported memory (#3323)Sam Clegg2020-11-101-36/+50
| | | | | The asmFunc now sets the outer scope's `bufferView` variable as well as its own internal views.
* Optimize i32(x) % C_pot in boolean context (#3307)Max Graey2020-11-101-2/+17
| | | | | | bool(i32(x) % C_pot) -> bool(i32(x) & (C_pot - 1)) bool(i32(x) % min_s) -> bool(i32(x) & max_s) For all other situations we already do this for (i32|i64).rem_s
* [wasm2js] Use native JavaScript Math.trunc (#3329)Max Graey2020-11-105-48/+9
|
* Canonicalize subtraction with constant on the right to addition (#3321)Max Graey2020-11-102-60/+80
| | | | | | | Using addition in more places is better for gzip, and helps simplify the optimizer as well. Add a FinalOptimizer phase to do optimizations like our signed LEB tweaks, to reduce binary size in the rare case when we do want a subtraction.
* Avoid boilerplate code with a big universal delegation header (#3294)Alon Zakai2020-11-092-295/+664
| | | | | | | | | | | | | | | | | | | | | | | | | To get an idea, this is a sample from the header: switch (DELEGATE_ID) { [..] case Expression::Id::BlockId: { DELEGATE_START(Block); DELEGATE_FIELD_CHILD_LIST(Block, list); DELEGATE_FIELD_SCOPE_NAME(Block, name); DELEGATE_END(Block); break; } A switch is defined (on some DELEGATE_ID that is provided). There is then a case for each expression type, calling a delegate for each field type. This allows a user to define the delegates it wants, then include this header. This uses the new header in the copying logic, where the rewrite also avoids recursion. This fixes a missing BrOnExn::sent scanning in the existing hashing/comparing code (which is what I used as a basis). When this is used there, it will fix that bug.
* Remove dead code and unused includes. NFC. (#3328)Sam Clegg2020-11-0824-92/+18
| | | Specifically try to cleanup use of asm_v_wasm.h and asmjs constants.
* Remove OptimizeCalls from PostEmscripten. NFC. (#3326)Sam Clegg2020-11-063-38/+0
| | | We no longer build modules that import `global.Math`.
* wasm2js: Remove global dict arguments to asmFunc (#3325)Sam Clegg2020-11-053-65/+16
|
* wasm2js: Remove unused argument. NFC. (#3324)Sam Clegg2020-11-051-4/+1
|
* wasm-reduce: Don't try to replace a non-number (like a reference) with a ↵Alon Zakai2020-11-051-1/+6
| | | | | Const (#3218) Also don't assume numbers are 32-bit.
* Remove remaining bits of C API tracing, which has been removed (#3322)Alon Zakai2020-11-051-1/+1
| | | It was removed in #2841
* Inlining: Slight reordering of options (#3308)Alon Zakai2020-11-042-19/+14
| | | | | | | | | | | | | | | | | This simplifies the three size-related inlining flags, so that their meanings are clearer. Also improve the comments and put them in a consistent order in both files. This should not make any difference in general, except that it is now possible to have oneCallerInlineMaxSize > flexibleInlineMaxSize, and we will inline a function with one caller if flexibleInlineMaxSize < FUNCTION_SIZE <= oneCallerInlineMaxSize which we would not before. As the defaults of the flags didn't fit that case, this should not change anything for anyone not passing in those specific inlining flags. For people that pass in those flags, this PR makes more things possible. Resolves the FIXME in that code, and is a refactoring before some more inlining work I have planned.
* Optimize signed / unsigned relationals when RHS is min or max constant (#3314)Max Graey2020-11-041-7/+89
|