aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Gohman <sunfish@mozilla.com>2016-04-27 18:16:38 -0700
committerDan Gohman <sunfish@mozilla.com>2016-04-27 18:16:38 -0700
commitf850552dd07b940ef45d7eee7d8421bb07dd98ec (patch)
tree573fb54e3908f7cc11e2cc86dac0ae43631ae528
parent477274504ea60c2f06ee195bff36c71d24aefaf8 (diff)
downloadnanowasm-design-f850552dd07b940ef45d7eee7d8421bb07dd98ec.tar.gz
Merge pull request #608 from WebAssembly/rationale-revisions
Revise, update, and expand several Rationale entries.
-rw-r--r--Rationale.md53
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