diff options
| author | Dan Gohman <sunfish@mozilla.com> | 2016-04-27 18:16:38 -0700 |
|---|---|---|
| committer | Dan Gohman <sunfish@mozilla.com> | 2016-04-27 18:16:38 -0700 |
| commit | f850552dd07b940ef45d7eee7d8421bb07dd98ec (patch) | |
| tree | 573fb54e3908f7cc11e2cc86dac0ae43631ae528 | |
| parent | 477274504ea60c2f06ee195bff36c71d24aefaf8 (diff) | |
| download | nanowasm-design-f850552dd07b940ef45d7eee7d8421bb07dd98ec.tar.gz | |
Merge pull request #608 from WebAssembly/rationale-revisions
Revise, update, and expand several Rationale entries.
| -rw-r--r-- | Rationale.md | 53 |
1 files changed, 41 insertions, 12 deletions
diff --git a/Rationale.md b/Rationale.md index c225d3a..aa9bb5b 100644 --- a/Rationale.md +++ b/Rationale.md @@ -15,7 +15,7 @@ and update the [design](AstSemantics.md) before the MVP is finalized. ## Why AST? -Why not a stack-, register- or SSA-based bytecode? +Why not a register- or SSA-based bytecode? * Trees allow a smaller binary encoding: [JSZap][], [Slim Binaries][]. * [Polyfill prototype][] shows simple and efficient translation to asm.js. @@ -24,6 +24,18 @@ Why not a stack-, register- or SSA-based bytecode? [Polyfill prototype]: https://github.com/WebAssembly/polyfill-prototype-1 +## Why not a fully-general stack machine? + +Stack machines have all the code size advantages as expression trees represented +in post-order. However, we wish to avoid requiring an explicit expression stack at +runtime, because many implementations will want to use registers rather than an +actual stack for evaluation. Consequently, while it's possible to think about +wasm expression evaluation in terms of a conceptual stack machine, the stack +machine would be constrained such that one can always statically know the types, +definitions, and uses of all operands on the stack, so that an implementation can +connect definitions with their uses through whatever mechanism they see fit. + + ## Basic Types Only WebAssembly only represents [a few types](AstSemantics.md#Types). @@ -32,7 +44,7 @@ WebAssembly only represents [a few types](AstSemantics.md#Types). language compiler to express its own types in terms of the basic machine types. This allows WebAssembly to present itself as a virtual ISA, and lets compilers target it as they would any other ISA. -* These types are efficiently executed by all modern architectures. +* These types are efficiently executed by all modern CPU architectures. * Smaller types (such as `i8` and `i16`) are usually no more efficient and in languages like C/C++ are only semantically meaningful for memory accesses since arithmetic get widened to `i32` or `i64`. Avoiding them at least for MVP @@ -104,7 +116,7 @@ tradeoffs. [ArrayBuffer]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer -## Resizing +## Linear Memory Resizing To allow efficient engines to employ virtual-memory based techniques for bounds checking, memory sizes are required to be page-aligned. @@ -183,7 +195,6 @@ may be added in the future. The nop operator does not produce a value or cause side effects. It is nevertheless useful for compilers and tools, which sometimes need to replace instructions with a ```nop```. Without a ```nop``` instruction, code generators would use alternative *does-nothing* opcode patterns that consume space in a module and may have a runtime cost. Finding an appropriate opcode that does nothing but has the appropriate type for the node's location is nontrivial. The existence of many different ways to encode ```nop``` - often mixed in the same module - would reduce the efficiency of compression algorithms. -The history of ```nop``` instructions is long and there are numerous examples of their use in production software. ## Locals @@ -194,12 +205,13 @@ variables by creating a separate stack data structure within linear memory. This stack is sometimes called the "aliased" stack, since it is used for variables which may be pointed to by pointers. -This prevents WebAssembly from performing clever optimizations on the stack and -liveness of such variables, but this loss isn't expected to be -consequential. Common C compiler optimizations such as LLVM's global value -numbering effectively split address-taken variables into parts, shrinking the -range where they actually need to have their address taken, and creating new -ranges where they can be allocated as local variables. +Since the aliased stack appears to the WebAssembly engine as normal memory, +WebAssembly optimizations that would target the aliased stack need to be more +general, and thus more complicated. We observe that common compiler +optimizations done before the WebAssembly code is produced, such as LLVM's +global value numbering, effectively split address-taken variables into many +small ranges that can often be allocated as local variables. Thus our +expectation that any loss of optimization potential here is minimal. Conversely, non-address taken values which are usually on the stack are instead represented as locals inside functions. This effectively means that WebAssembly @@ -220,7 +232,7 @@ register allocation algorithms, offloading some of the optimization work from the WebAssembly VM. -## Variable-Length Argument Lists +## Variable-Length Argument Lists ("varargs") C and C++ compilers are expected to implement variable-length argument lists by storing arguments in a buffer in linear memory and passing a pointer to the @@ -231,7 +243,11 @@ performance, but variable-length calls are already somewhat slow. ## Multiple Return Values -TODO +WebAssembly's MVP does not support multiple return values from functions because +they aren't strictly necessary for the earliest anticipated use cases (and it's +a *minimum* viable product), and they would introduce some complexity for some +implementations. However, multiple return values are a very useful feature, and +are relevant to ABIs, so it's likely to be added soon after the MVP. ## Indirect Calls @@ -362,6 +378,19 @@ emulate it with a single extra mask instruction, and because several popular source languages, including JavaScript and C#, have come to specify this behavior too, we reluctantly adopt this behavior as well. +WebAssembly has three classes of integer operations: signed, unsigned, and +sign-agnostic. The signed and unsigned instructions have the property that +whenever they can't return their mathematically expected value (such as when +an overflow occurs, or when their operand is outside their domain), they +trap, in order to avoid silently returning an incorrect value. + +Note that the `add`, `sub`, and `mul` operators are categorized as +sign-agnostic. Because of the magic of two's complement representation, they +may be used for both signed and unsigned purposes. Note that this (very +conveniently!) means that engines don't need to add extra overflow-checking +code for these most common of arithmetic operators on the most popular +hardware platforms. + ## Motivating Scenarios for Feature Testing |
