From 84acb88180c10a877554f5f9554c595a3ee1702d Mon Sep 17 00:00:00 2001 From: Karl Schimpf Date: Fri, 21 Apr 2017 11:18:09 -0700 Subject: [PATCH 001/302] Add placeholder for proposal for exception handling. --- proposals/Exceptions.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 proposals/Exceptions.md diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md new file mode 100644 index 0000000000..0bd21785bf --- /dev/null +++ b/proposals/Exceptions.md @@ -0,0 +1,3 @@ +# Exception handling + +This document describes how to extend the WASM specification to handle exceptions. From e06bb1840cdbba418637e995420294b7b19299f5 Mon Sep 17 00:00:00 2001 From: KarlSchimpf Date: Wed, 26 Apr 2017 15:18:11 -0700 Subject: [PATCH 002/302] Initial proposal for exception handling. (#2) * Save initial desription. * Save state. * Initial proposal for exception handling. --- proposals/Exceptions.md | 293 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 292 insertions(+), 1 deletion(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index 0bd21785bf..0f05472f15 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -1,3 +1,294 @@ # Exception handling -This document describes how to extend the WASM specification to handle exceptions. +There are three sections to this proposal + +1. A overview of the proposed extension to WebAssembly + +2. Changes of the WebAssembly Binary Design document needed to include this + proposal. + +The proposal here is also meant to be a minimal proposal that may be further +extended sometime in the future. + +## Overview + +Exception handling allows code to break control flow when an exception is +thrown. The exception can be an exception known by the WebAssembly module, or it +may be an unknown exception thrown by an imported call. + +Thrown exceptions are handled as follows: + +a) They can be caught by a catch in an enclosing try block of a function body. + +b) Throws not caught within a function body continue up the call chain until an + enclosing try block is found. + +c) If the call stack is exhausted without any enclosing try blocks, it terminates + the application. + +This proposal looks at the changes needed to incorporate these concepts into the +portable binary encoding of WebAssembly modules. + +At the specification level, these changes do not infer whether an implementation +must implement lightweight or heavyweight exceptions. Rather, it defers that +choice to the runtime implementation. + +Exception handling is defined using *exceptions*, *try blocks*, *catch blocks*, +and the instructions *throw* and *rethrow*. + +### Exceptions + +An _exception_ is an internal construct in WebAssembly. Exceptions are +categorized into _exception types_. Each _exception type_ defines a unique kind +of exception. An exception is defined by its _exception type_, and a sequence of +values (i.e. integers and floats) that define the data fields of the exception. +The exception _type signature_ of an exception defines the value types of the +exception's data fields. + +Exception types are defined in a new _exception type_ section of a WebAssembly +module. The _exception type_ section is a table of exception _type +signatures_. Each element in the table defines a different exception type, and +the corresponding exception type signature defines the corresponding data that +can be thrown for that exception type. + +Exception types, in the exception type section, are referenced by both catch blocks +and throw instructions. The reference is an exception type _index_ that refers to +the corresponding exception type in the exception type section. + +Note that multiple exception types can have the same exception _type +signature_. However, because they are separate entries in the exception type +section, they none the less represent different exception types. + +Like functions, exception types can be imported and exported. In such cases, the +exceptions must be named, and also appear in the corresponding import/export +sections of the WebAssembly module. The runtime is responsible for connecting +exception types between WebAssembly modules, and the external environment (i.e. +Javascript). + +Exceptions can also be thrown by called, imported functions. If it corresponds +to an imported exception, it can be caught in try blocks, as well as access the +data of the thrown exception. If the exception is not imported, it still can be +caught to allow code clean-up, but the data of the exception can't be accessed. + +### Try and catch blocks. + +A _try_ block defines a block of code that may need to catch exceptions and/or +clean up state when an exception is thrown. Each try block must end with one or +more _catch_ blocks. No instructions (in the try block) can appear between catch +blocks, or after the last catch block. + +A try block may define more than one catch block, and all but the last catch block +must define an *exception type*. The exception type defines the type of +exception it catches. Catch blocks with an *exception type* are _typed_ catch +blocks. Each typed catch block, within a try block, must reference a different +exception type. The last catch block can either be typed, or it can be a +_default_ catch block. The default catch block has no exception type, and is +used to catch all exceptions not defined by any of the other catch blocks. + +Try blocks, like a control-flow blocks, have a *block type*. The block type of a +try block defines the value yielded by the evaluation the try block when +either no exception is thrown, or the exception is successfully caught and the +code can recover and continue. The catch blocks, within a try block also have a +block type, and must be the same as the enclosing try block. + +In the initial implementation, try and catch blocks may only yield 0 or 1 +values. + +Instruction validation checks that each catch block within a try block refer to +a different exception type (they must have different exception type indices), and +the exception types are defined in the exception type section of the module. It +also checks that the block type of the catch blocks is the same as the enclosing +try block. Further, it verifies that there aren't any instructions between the +catch blocks of the try block, and the last catch block is at the end of the try +block. + +### Throws + +The _throw_ instruction has a single immediate argument containing an +exception type index. This index defines the type of exception to throw. The +arguments to the thrown exception must be on top of the value stack, and must +correspond to the exception type signature of the exception. + +**TODO** Define the order that the data fields of the exception should appear on +the value stack. + +When an exception is thrown, the corresponding values are popped off the value +stack, and stored internally for access when the exception is caught. + +If the throw appears within a try block, the value stack is popped back to +the size the value stack had when the try block was initially entered. + +If a throw occurs within a function body, and it doesn't have an enclosing try +block, the throw continues up the call stack until either an enclosing try block +is found, or the call stack is flushed. If the call stack is flushed, execution +is terminated. + +Otherwise, the call stack is wound back to the function with the nearest +enclosing try block. The value stack is then popped back to the size the value +stack had when that try block was initially entered. + +If the throw appears within a catch block, it is treated as being outside the +corresponding try block of the catch (i.e. just after the end of corresponding +try block). Therefore, throws within the catch block can't be caught by their +enclosing try block. Rather, execution is thrown to the next enclosing try +block. + +Once the value stack has been popped back to the size of the enclosing try block +(whether local or across function calls), control is then passed to the +appropriate catch block. + +If there is a typed catch block with the same exception type _index_ as the +throw, the thrown values (stored internally at the throw) are copied back on the +value stack. Then, the corresponding typed catch block is entered. This allows +the values of the exception to be accessed by the catch block. + +On the other hand, if there isn't a corresponding typed catch block, and there +is a default catch block, the default catch block is entered without pushing the +values of the exception onto the value stack. This allows the default catch +block to clean up state, but it can't look at the thrown value. + +Finally, if there isn't a corresponding typed catch block, and there isn't a +default catch block, the except is automatically rethrown to the next enclosing +try block. + +Also note that when the thrown exception is caught by a catch block, it is not +destroyed until the catch block is exited. This is done so that the catch block +can rethrow the exception. + +If the selected catch block does not rethrow an exception, it must yield the +value(s) expected by the enclosing try block. For typed catch blocks, they must +also be sure to also pop off the caught exception values. + +### Rethrows + +The _rethrow_ instruction has no arguments, and can only appear in catch +blocks. It always re-throws the exception caught by the catch block. This allows +the catch block to clean up state before the exception is passed back to the +next enclosing try block. + +### Debugging + +Earlier discussion implied that when an exception is thrown, the runtime will +pop the value stack across function calls until a corresponding, enclosing try +block is found. The implementation may actually not do this. Rather, it may +first search up the call stack to see if there is an enclosing try. If none are +found, it could terminate the thread at that point of the throw. This would +allow better debugging capability, since the corresponding call stack is still +there to query. + +## Changes to the binary model + +This section describes changes in the binary encoding design document (ref?). + +### Language types + +A new type constructor '0x50' for exception types will be added. + +All types are distinguished by a negative `varint7` values that is the first +byte of their encoding (representing a type constructor): + +| Opcode | Type constructor | +|--------|------------------| +| `-0x01` (i.e., the byte `0x7f`) | `i32` | +| `-0x02` (i.e., the byte `0x7e`) | `i64` | +| `-0x03` (i.e., the byte `0x7d`) | `f32` | +| `-0x04` (i.e., the byte `0x7c`) | `f64` | +| `-0x10` (i.e., the byte `0x70`) | `anyfunc` | +| `-0x20` (i.e., the byte `0x60`) | `func` | +| `-0x30` (i.e., the byte `0x50`) | `except` | +| `-0x40` (i.e., the byte `0x40`) | pseudo type for representing an empty `block_type` | + +### Exception type signatures + +An exception type is described by its exception type signature as follows: + +`except_type` + +| Field | Type | Description | +|-------|------|-------------| +| count | `varuint32` | The number of arguments to the exception | +| value_types | `value_type*` | The type of each argument to the exception | + +### External kind + +`external_kind` + +A single-byte unsigned integer indicating the kind of definition being imported or defined: + +* `0` indicating a `Function` [import](Modules.md#imports) or [definition](Modules.md#function-and-code-sections) +* `1` indicating a `Table` [import](Modules.md#imports) or [definition](Modules.md#table-section) +* `2` indicating a `Memory` [import](Modules.md#imports) or [definition](Modules.md#linear-memory-section) +* `3` indicating a `Global` [import](Modules.md#imports) or [definition](Modules.md#global-section) +* `4` indicating an `Exception` *import* or *definition* + +### Exception type section + +The exception type section is the named section 'exception'. The exception type +section declares exception types using exception type signatures. + +| Field | Type | Description | +|-------|------|-------------| +| count | `varuint32` | Count of the number of exception types to follow | +| entries | `except_type` | Repeated exception type signatures as described *above* | + +### Import section + +The import section is extended to include exception types by extending an +`import_entry` as follows: + +If the `kind` is `Exception`: + +| Field | Type | Description | +|-------|------|-------------| +| type | `varuint32` | exception index to table in the *exception type section* | + +### Export section + +The export section is extended to include exception types by extending an +`export_entry` as follows: + +* If the `kind` is `Exception`, then the `index` is into the corresponding + exception type in the *exception type section*. + +### Name section + +The set of known values for `name_type` of a name section is extended as follows: + + +| Name Type | Code | Description | +| --------- | ---- | ----------- | +| [Function](#function-names) | `1` | Assigns names to functions | +| [Local](#local-names) | `2` | Assigns names to locals in functions | +| [Exception](#(exception-names) | `3` | Assigns names to exception types | + +### Exception names + +The exception names subsection is a `name_map` which assigns names to a subset +of the *exception type index* (both imports and module-defined). + +### Control flow operators + +The control flow operators are extended to define try blocks, catch blocks, +throws, and rethrows as follows: + +| Name | Opcode | Immediates | Description | +| ---- | ---- | ---- | ---- | +| `unreachable` | `0x00` | | trap immediately | +| `nop` | `0x01` | | no operation | +| `block` | `0x02` | sig : `block_type` | begin a sequence of expressions, yielding 0 or 1 values | +| `loop` | `0x03` | sig : `block_type` | begin a block which can also form control flow loops | +| `if` | `0x04` | sig : `block_type` | begin if expression | +| `else` | `0x05` | | begin else expression of if | +| `end` | `0x0b` | | end a block, loop, if, try, catch, and catch_default | +| `br` | `0x0c` | relative_depth : `varuint32` | break that targets an outer nested block | +| `br_if` | `0x0d` | relative_depth : `varuint32` | conditional break that targets an outer nested block | +| `br_table` | `0x0e` | see below | branch table control flow construct | +| `return` | `0x0f` | | return zero or one value from this function | +| `try` | 0x?? | sig : `block_type` | begins a block which can handle thrown exceptions | +| `catch` | 0x?? | sig : `block_type` , index : `varuint32` | begins a block when the exception type `index` is thrown | +| `catch_default` | 0x?? | sig : block_type | begins a block when an unknown exception is thrown | +| `throw` | 0x?? | index : `varuint32` | Throws an exception defined by the exception type `index` | +| `rethrow` | 0x?? | | re-throws the exception caught by the enclosing catch block | + +The *sig* fields of `block', 'if`, `try`, `catch`, and `catch_default` operators +are block signatures which describe their use of the operand stack. From 70ef9746436d6a2eb9059190123e83aa5bd99a07 Mon Sep 17 00:00:00 2001 From: kschimpf Date: Fri, 28 Apr 2017 13:19:39 -0700 Subject: [PATCH 003/302] Use a cleaner syntax for try blocks. --- proposals/Exceptions.md | 256 +++++++++++++++++++--------------------- 1 file changed, 122 insertions(+), 134 deletions(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index 0f05472f15..2ac0971a88 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -1,6 +1,6 @@ # Exception handling -There are three sections to this proposal +There are two sections to this proposal 1. A overview of the proposed extension to WebAssembly @@ -18,13 +18,14 @@ may be an unknown exception thrown by an imported call. Thrown exceptions are handled as follows: -a) They can be caught by a catch in an enclosing try block of a function body. +a) They can be caught by a catch block in an enclosing try block of a function + body. b) Throws not caught within a function body continue up the call chain until an enclosing try block is found. -c) If the call stack is exhausted without any enclosing try blocks, it terminates - the application. +c) If the call stack is exhausted without any enclosing try blocks, it + terminates the application. This proposal looks at the changes needed to incorporate these concepts into the portable binary encoding of WebAssembly modules. @@ -38,118 +39,125 @@ and the instructions *throw* and *rethrow*. ### Exceptions -An _exception_ is an internal construct in WebAssembly. Exceptions are -categorized into _exception types_. Each _exception type_ defines a unique kind -of exception. An exception is defined by its _exception type_, and a sequence of -values (i.e. integers and floats) that define the data fields of the exception. -The exception _type signature_ of an exception defines the value types of the -exception's data fields. - -Exception types are defined in a new _exception type_ section of a WebAssembly -module. The _exception type_ section is a table of exception _type -signatures_. Each element in the table defines a different exception type, and -the corresponding exception type signature defines the corresponding data that -can be thrown for that exception type. - -Exception types, in the exception type section, are referenced by both catch blocks -and throw instructions. The reference is an exception type _index_ that refers to -the corresponding exception type in the exception type section. - -Note that multiple exception types can have the same exception _type -signature_. However, because they are separate entries in the exception type -section, they none the less represent different exception types. - -Like functions, exception types can be imported and exported. In such cases, the -exceptions must be named, and also appear in the corresponding import/export -sections of the WebAssembly module. The runtime is responsible for connecting -exception types between WebAssembly modules, and the external environment (i.e. -Javascript). +An _exception_ is an internal construct in WebAssembly. Exceptions are defined +by a new _exception_ section of a WebAssembly module. The exception section is a +list of _type signatures_. Each entry in this list defines an exception +constructor, and the type signature is the list of arguments passed to the +exception constructor. -Exceptions can also be thrown by called, imported functions. If it corresponds -to an imported exception, it can be caught in try blocks, as well as access the -data of the thrown exception. If the exception is not imported, it still can be -caught to allow code clean-up, but the data of the exception can't be accessed. - -### Try and catch blocks. +Within the module, exceptions are always identified by the construtor that +created it. That is, an index in the exception section. This index is referred +to as the _exception tag_. -A _try_ block defines a block of code that may need to catch exceptions and/or -clean up state when an exception is thrown. Each try block must end with one or -more _catch_ blocks. No instructions (in the try block) can appear between catch -blocks, or after the last catch block. +Exception constructors can be imported and exported by adding the appropriate +entry to the import and export sections. All imported/exporteds exception +(constructors) must be named to reconcile exception tag values between modules. -A try block may define more than one catch block, and all but the last catch block -must define an *exception type*. The exception type defines the type of -exception it catches. Catch blocks with an *exception type* are _typed_ catch -blocks. Each typed catch block, within a try block, must reference a different -exception type. The last catch block can either be typed, or it can be a -_default_ catch block. The default catch block has no exception type, and is -used to catch all exceptions not defined by any of the other catch blocks. +Exception tags are used by throw and catch instructions. The throw instruction +uses the tag to call the apropriate exception constuctor. The catch instruction +uses the tag to identify if the thrown exception is one it can catch. It is the +responsability of the implementation to keep track of the constructor used to +create exceptions, so that it can determine if a catch block can be applied. -Try blocks, like a control-flow blocks, have a *block type*. The block type of a -try block defines the value yielded by the evaluation the try block when -either no exception is thrown, or the exception is successfully caught and the -code can recover and continue. The catch blocks, within a try block also have a -block type, and must be the same as the enclosing try block. - -In the initial implementation, try and catch blocks may only yield 0 or 1 -values. - -Instruction validation checks that each catch block within a try block refer to -a different exception type (they must have different exception type indices), and -the exception types are defined in the exception type section of the module. It -also checks that the block type of the catch blocks is the same as the enclosing -try block. Further, it verifies that there aren't any instructions between the -catch blocks of the try block, and the last catch block is at the end of the try -block. +Exceptions can also be thrown by called, imported functions. If it corresponds +to an imported exception, it can be caught by an appropriate catch instruction. +If the exception is not imported, it still can be caught to allow code clean-up, +but the data of the exception can't be accessed. -### Throws +### Try and catch blocks. -The _throw_ instruction has a single immediate argument containing an -exception type index. This index defines the type of exception to throw. The -arguments to the thrown exception must be on top of the value stack, and must -correspond to the exception type signature of the exception. +A _try_ block defines a list of instruction that may need to catch exceptions +and/or clean up state when an exception is thrown. Like other higher-level constucts, a try block begins with a `try` instruction terminates with an `end` instruction. That is, a try block is sequence of instructions having the following form: + +``` +try + instruction* +catch i + instruction+ +catch j + instruction+ +... +catch n + instruction+ +else + instruction+ +end + +``` + +A try block may contain one or more catch blocks, and all but the last catch +block must begin with a`catch` instruction. The last catch block can begin with +either a `catch` or `else` instruction. The `catch`/`else` instructions (within +the try construct) are called the _catching_ instructions. + +The _body_ of the try block is the list of instructions before the first +catching instruction. The _body_ of each catch block is the sequence of +instructions following the corresponding catching instruction, and the next +catching instruction (or the `end` instruction if it is the last catch block). + +The `catch` instruction has an exception tag associated with it. The tag +identifies what exceptions it can catch. That is, any exception created with the +corresponding exception constructor. Blocks that begin with a `catch` +instruction are considered a _tagged_ catch block. + +The last catch block of an exception can be a tagged catch block. Alternatively, +it can begin with the `else` instruction. If it begins with the `else` +instruction, it defines the _default_ catch block. The default catch block has +no exception type, and is used to catch all exceptions not caught by any of the +tagged catch blocks. + +Try blocks, like a control-flow blocks, have a _block type_. The block type of a +try block defines the value yielded by the evaluation the try block when +either no exception is thrown, or the exception is successfully caught by one of its catch blocks, and the instructions within the catch block can recover from the throw. -**TODO** Define the order that the data fields of the exception should appear on -the value stack. +In the initial implementation, try blocks may only yield 0 or 1 values. -When an exception is thrown, the corresponding values are popped off the value -stack, and stored internally for access when the exception is caught. +### Throws -If the throw appears within a try block, the value stack is popped back to -the size the value stack had when the try block was initially entered. +The _throw_ instruction has a single immediate argument, an exception tag. The +exception tag is used to define the exception constructor used create the +exception. The arguments for the constructor must be on top of the value stack, +and must correspond to the exception type signature for the exception. -If a throw occurs within a function body, and it doesn't have an enclosing try -block, the throw continues up the call stack until either an enclosing try block -is found, or the call stack is flushed. If the call stack is flushed, execution -is terminated. +When an exception is thrown, the created exception is stored internally for +access when the exception is caught. The runtime is then searched for nearest +enclosing try block body that execution is in. That try block is called the +catching try block. -Otherwise, the call stack is wound back to the function with the nearest -enclosing try block. The value stack is then popped back to the size the value -stack had when that try block was initially entered. +If the throw appears within the body of a try block, it is the catching +try block. -If the throw appears within a catch block, it is treated as being outside the -corresponding try block of the catch (i.e. just after the end of corresponding -try block). Therefore, throws within the catch block can't be caught by their -enclosing try block. Rather, execution is thrown to the next enclosing try +If a throw occurs within a function body, and it doesn't appear inside the body +try block, the throw continues up the call stack until it is in the body of an +an enclosing try block, or the call stack is flushed. If the call stack is +flushed, execution is terminated. Otherwise, the found enclosing try block is +the catching try block. + +The catching try block thrown in the body of a catch block is never the +corresponding try block of the catch block, since instructions in the body of +the catch block are not in the body of the try block. + +Once a catching try block is found for the throw, the value stack is popped back +to the size the value stack had when the try block was initially entered. Then, +tagged catch blocks are tried in the order they appear in the catching try +block, until one matches. A tagged catch block matches if the corresponding +`catch` instruction is applicable, i.e. the corresponding exception was +generated using the constructor defined by the tag of the `catch` instruction. + +If a matched tagged catch block is found, control is transferred to +the body of the catch block, and the constructor arguments (when the exception +was created) are pushed back onto the stack. + +Otherwise, control is transferred to the body of the default catch +block. However, unlike tagged catch blocks, the constructor arguments are not +copied back onto the value stack. + +If no tagged catch blocks were matched, and the catching try block doesn't have +a default catch block, the exception is re-thrown to the next enclosing try block. -Once the value stack has been popped back to the size of the enclosing try block -(whether local or across function calls), control is then passed to the -appropriate catch block. - -If there is a typed catch block with the same exception type _index_ as the -throw, the thrown values (stored internally at the throw) are copied back on the -value stack. Then, the corresponding typed catch block is entered. This allows -the values of the exception to be accessed by the catch block. - -On the other hand, if there isn't a corresponding typed catch block, and there -is a default catch block, the default catch block is entered without pushing the -values of the exception onto the value stack. This allows the default catch -block to clean up state, but it can't look at the thrown value. - -Finally, if there isn't a corresponding typed catch block, and there isn't a -default catch block, the except is automatically rethrown to the next enclosing -try block. +If control is transferred to the body of a catch block, and the last instruction +in the body is executed, control then exits the try block. Also note that when the thrown exception is caught by a catch block, it is not destroyed until the catch block is exited. This is done so that the catch block @@ -178,36 +186,15 @@ there to query. ## Changes to the binary model -This section describes changes in the binary encoding design document (ref?). - -### Language types - -A new type constructor '0x50' for exception types will be added. - -All types are distinguished by a negative `varint7` values that is the first -byte of their encoding (representing a type constructor): - -| Opcode | Type constructor | -|--------|------------------| -| `-0x01` (i.e., the byte `0x7f`) | `i32` | -| `-0x02` (i.e., the byte `0x7e`) | `i64` | -| `-0x03` (i.e., the byte `0x7d`) | `f32` | -| `-0x04` (i.e., the byte `0x7c`) | `f64` | -| `-0x10` (i.e., the byte `0x70`) | `anyfunc` | -| `-0x20` (i.e., the byte `0x60`) | `func` | -| `-0x30` (i.e., the byte `0x50`) | `except` | -| `-0x40` (i.e., the byte `0x40`) | pseudo type for representing an empty `block_type` | +This section describes changes in +the +[binary encoding design document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md). ### Exception type signatures -An exception type is described by its exception type signature as follows: - -`except_type` - -| Field | Type | Description | -|-------|------|-------------| -| count | `varuint32` | The number of arguments to the exception | -| value_types | `value_type*` | The type of each argument to the exception | +An exception is described by its exception type signature, which corresponds to +the function signature of the exception constructor. Hence, an exception _type +signature_ is a `func_type`. ### External kind @@ -221,15 +208,15 @@ A single-byte unsigned integer indicating the kind of definition being imported * `3` indicating a `Global` [import](Modules.md#imports) or [definition](Modules.md#global-section) * `4` indicating an `Exception` *import* or *definition* -### Exception type section +### Exception section -The exception type section is the named section 'exception'. The exception type -section declares exception types using exception type signatures. +The `exception` section is the named section 'exception'. The exception section +declares exception types using exception type signatures. | Field | Type | Description | |-------|------|-------------| | count | `varuint32` | Count of the number of exception types to follow | -| entries | `except_type` | Repeated exception type signatures as described *above* | +| entries | `func_type` | Repeated exception type signatures as described *above* | ### Import section @@ -240,7 +227,8 @@ If the `kind` is `Exception`: | Field | Type | Description | |-------|------|-------------| -| type | `varuint32` | exception index to table in the *exception type section* | +| tag | varuint32 | Index into exception secion | +| type | `varuint32` | type index of the function signature | ### Export section From 25ed050b3ebfb4ae1a82b5932eac200a3dec3346 Mon Sep 17 00:00:00 2001 From: Karl Schimpf Date: Mon, 1 May 2017 11:17:43 -0700 Subject: [PATCH 004/302] Rewrite to match suggestions from issues. --- proposals/Exceptions.md | 135 +++++++++++++++++++++------------------- 1 file changed, 72 insertions(+), 63 deletions(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index 2ac0971a88..fda3566bbf 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -21,7 +21,7 @@ Thrown exceptions are handled as follows: a) They can be caught by a catch block in an enclosing try block of a function body. -b) Throws not caught within a function body continue up the call chain until an +b) Throws not caught within a function body continue up the call stack until an enclosing try block is found. c) If the call stack is exhausted without any enclosing try blocks, it @@ -41,23 +41,21 @@ and the instructions *throw* and *rethrow*. An _exception_ is an internal construct in WebAssembly. Exceptions are defined by a new _exception_ section of a WebAssembly module. The exception section is a -list of _type signatures_. Each entry in this list defines an exception -constructor, and the type signature is the list of arguments passed to the -exception constructor. +list of exceptions. Each exception has a _type signature_. The type signature +defines the list of values associated with an exception. -Within the module, exceptions are always identified by the construtor that -created it. That is, an index in the exception section. This index is referred -to as the _exception tag_. +Within the module, exceptions are identified by an index into the exception +section. This index is referred to as the _exception tag_. -Exception constructors can be imported and exported by adding the appropriate -entry to the import and export sections. All imported/exporteds exception -(constructors) must be named to reconcile exception tag values between modules. +Exceptions can be imported and exported by adding the appropriate entries to the +import and export sections of the module. All imported/exported exceptions must +be named to reconcile exception tags between modules. Exception tags are used by throw and catch instructions. The throw instruction -uses the tag to call the apropriate exception constuctor. The catch instruction -uses the tag to identify if the thrown exception is one it can catch. It is the -responsability of the implementation to keep track of the constructor used to -create exceptions, so that it can determine if a catch block can be applied. +uses the tag to call the appropriate exception constructor, which gets values +defined by the corresponding type signature of the exception. The catch +instruction uses the tag to identify if the thrown exception is one it can +catch. Exceptions can also be thrown by called, imported functions. If it corresponds to an imported exception, it can be caught by an appropriate catch instruction. @@ -67,22 +65,24 @@ but the data of the exception can't be accessed. ### Try and catch blocks. A _try_ block defines a list of instruction that may need to catch exceptions -and/or clean up state when an exception is thrown. Like other higher-level constucts, a try block begins with a `try` instruction terminates with an `end` instruction. That is, a try block is sequence of instructions having the following form: +and/or clean up state when an exception is thrown. Like other higher-level +constructs, a try block begins with a `try` instruction, and ends with an `end` +instruction. That is, a try block is sequence of instructions having the +following form: ``` try instruction* catch i - instruction+ + instruction* catch j - instruction+ + instruction* ... catch n - instruction+ + instruction* else - instruction+ + instruction* end - ``` A try block may contain one or more catch blocks, and all but the last catch @@ -93,12 +93,13 @@ the try construct) are called the _catching_ instructions. The _body_ of the try block is the list of instructions before the first catching instruction. The _body_ of each catch block is the sequence of instructions following the corresponding catching instruction, and the next -catching instruction (or the `end` instruction if it is the last catch block). +catching instruction (or the `end` instruction if it is the last catching +block). The `catch` instruction has an exception tag associated with it. The tag identifies what exceptions it can catch. That is, any exception created with the -corresponding exception constructor. Blocks that begin with a `catch` -instruction are considered a _tagged_ catch block. +corresponding exception tag. Catch blocks that begin with a `catch` instruction +are considered a _tagged_ catch block. The last catch block of an exception can be a tagged catch block. Alternatively, it can begin with the `else` instruction. If it begins with the `else` @@ -107,46 +108,49 @@ no exception type, and is used to catch all exceptions not caught by any of the tagged catch blocks. Try blocks, like a control-flow blocks, have a _block type_. The block type of a -try block defines the value yielded by the evaluation the try block when -either no exception is thrown, or the exception is successfully caught by one of its catch blocks, and the instructions within the catch block can recover from the throw. +try block defines the values yielded by the evaluation the try block when either +no exception is thrown, or the exception is successfully caught by one of its +catch blocks, and the instructions within the catch block can recover from the +throw. In the initial implementation, try blocks may only yield 0 or 1 values. ### Throws The _throw_ instruction has a single immediate argument, an exception tag. The -exception tag is used to define the exception constructor used create the -exception. The arguments for the constructor must be on top of the value stack, -and must correspond to the exception type signature for the exception. +exception tag is used to define the constructed exception. The arguments for the +constructor must be on top of the value stack, and must correspond to the +exception type signature for the exception. -When an exception is thrown, the created exception is stored internally for -access when the exception is caught. The runtime is then searched for nearest -enclosing try block body that execution is in. That try block is called the -catching try block. +When an exception is thrown, the values on the stack (corresponding to the type +signature) are popped off and the corresponding exception is constructed. The +exception is stored internally for access when the exception is caught. The +runtime then searches for nearest enclosing try block body that execution is +in. That try block is called the _catching_ try block. -If the throw appears within the body of a try block, it is the catching -try block. +If the throw appears within the body of a try block, it is the catching try +block. If a throw occurs within a function body, and it doesn't appear inside the body -try block, the throw continues up the call stack until it is in the body of an -an enclosing try block, or the call stack is flushed. If the call stack is +of a try block, the throw continues up the call stack until it is in the body of +an an enclosing try block, or the call stack is flushed. If the call stack is flushed, execution is terminated. Otherwise, the found enclosing try block is the catching try block. -The catching try block thrown in the body of a catch block is never the -corresponding try block of the catch block, since instructions in the body of -the catch block are not in the body of the try block. +A throw inside a the body of a catch block is never caught by the corresponding +try block of the catch block, since instructions in the body of the catch block +are not in the body of the try block. Once a catching try block is found for the throw, the value stack is popped back -to the size the value stack had when the try block was initially entered. Then, -tagged catch blocks are tried in the order they appear in the catching try -block, until one matches. A tagged catch block matches if the corresponding -`catch` instruction is applicable, i.e. the corresponding exception was -generated using the constructor defined by the tag of the `catch` instruction. +to the size the value stack had when the try block was entered. Then, tagged +catch blocks are tried in the order they appear in the catching try block, until +one matches. A tagged catch block matches if the corresponding `catch` +instruction is applicable, i.e. the corresponding exception was generated using +the constructor defined by the tag of the `catch` instruction. -If a matched tagged catch block is found, control is transferred to -the body of the catch block, and the constructor arguments (when the exception -was created) are pushed back onto the stack. +If a matched tagged catch block is found, control is transferred to the body of +the catch block, and the constructor arguments (when the exception was created) +are pushed back onto the stack. Otherwise, control is transferred to the body of the default catch block. However, unlike tagged catch blocks, the constructor arguments are not @@ -164,7 +168,7 @@ destroyed until the catch block is exited. This is done so that the catch block can rethrow the exception. If the selected catch block does not rethrow an exception, it must yield the -value(s) expected by the enclosing try block. For typed catch blocks, they must +value(s) expected by the enclosing try block. For tagged catch blocks, they must also be sure to also pop off the caught exception values. ### Rethrows @@ -194,19 +198,22 @@ the An exception is described by its exception type signature, which corresponds to the function signature of the exception constructor. Hence, an exception _type -signature_ is a `func_type`. +signature_ is a `func_type` that returns zero values. + +Exception type signatures must appear in the type section. ### External kind `external_kind` -A single-byte unsigned integer indicating the kind of definition being imported or defined: +A single-byte unsigned integer indicating the kind of definition being imported +or defined: * `0` indicating a `Function` [import](Modules.md#imports) or [definition](Modules.md#function-and-code-sections) * `1` indicating a `Table` [import](Modules.md#imports) or [definition](Modules.md#table-section) * `2` indicating a `Memory` [import](Modules.md#imports) or [definition](Modules.md#linear-memory-section) * `3` indicating a `Global` [import](Modules.md#imports) or [definition](Modules.md#global-section) -* `4` indicating an `Exception` *import* or *definition* +* `4` indicating an `Exception` [import](#import-section) or [definition](#exception-sectio) ### Exception section @@ -215,8 +222,8 @@ declares exception types using exception type signatures. | Field | Type | Description | |-------|------|-------------| -| count | `varuint32` | Count of the number of exception types to follow | -| entries | `func_type` | Repeated exception type signatures as described *above* | +| count | `varuint32` | count of the number of exception types to follow | +| entries | `func_type` | sequence of indices into the type section | ### Import section @@ -227,7 +234,7 @@ If the `kind` is `Exception`: | Field | Type | Description | |-------|------|-------------| -| tag | varuint32 | Index into exception secion | +| tag | varuint32 | index into exception section | | type | `varuint32` | type index of the function signature | ### Export section @@ -235,12 +242,13 @@ If the `kind` is `Exception`: The export section is extended to include exception types by extending an `export_entry` as follows: -* If the `kind` is `Exception`, then the `index` is into the corresponding - exception type in the *exception type section*. +If the `kind` is `Exception`, then the `index` is into the corresponding +exception in the _exception section_ index space. ### Name section -The set of known values for `name_type` of a name section is extended as follows: +The set of known values for `name_type` of a name section is extended as +follows: | Name Type | Code | Description | @@ -252,7 +260,8 @@ The set of known values for `name_type` of a name section is extended as follows ### Exception names The exception names subsection is a `name_map` which assigns names to a subset -of the *exception type index* (both imports and module-defined). +of the _exception_ indices from the exception section. (Used for both imports +and module-defined). ### Control flow operators @@ -273,10 +282,10 @@ throws, and rethrows as follows: | `br_table` | `0x0e` | see below | branch table control flow construct | | `return` | `0x0f` | | return zero or one value from this function | | `try` | 0x?? | sig : `block_type` | begins a block which can handle thrown exceptions | -| `catch` | 0x?? | sig : `block_type` , index : `varuint32` | begins a block when the exception type `index` is thrown | -| `catch_default` | 0x?? | sig : block_type | begins a block when an unknown exception is thrown | -| `throw` | 0x?? | index : `varuint32` | Throws an exception defined by the exception type `index` | +| `catch` | 0x?? | tag : `varuint32` | begins a block when the exception `tag` is thrown | +| `catch_default` | 0x?? | | begins a block when an unknown exception is thrown | +| `throw` | 0x?? | tag : `varuint32` | Throws an exception defined by the exception `tag` | | `rethrow` | 0x?? | | re-throws the exception caught by the enclosing catch block | -The *sig* fields of `block', 'if`, `try`, `catch`, and `catch_default` operators -are block signatures which describe their use of the operand stack. +The *sig* fields of `block', 'if`, and `try` operators are block signatures +which describe their use of the operand stack. From 45db4205d1966b55caa78ba5a112739b6fadbdd0 Mon Sep 17 00:00:00 2001 From: Karl Schimpf Date: Wed, 3 May 2017 10:12:25 -0700 Subject: [PATCH 005/302] Remove the use of "constructors" when defining exceptions. --- proposals/Exceptions.md | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index fda3566bbf..71308476c0 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -52,10 +52,9 @@ import and export sections of the module. All imported/exported exceptions must be named to reconcile exception tags between modules. Exception tags are used by throw and catch instructions. The throw instruction -uses the tag to call the appropriate exception constructor, which gets values -defined by the corresponding type signature of the exception. The catch -instruction uses the tag to identify if the thrown exception is one it can -catch. +uses the tag to allocate the exception with the corresponding data fields +defined by the exception's type signature. The catch instruction uses the tag to +identify if the thrown exception is one it can catch. Exceptions can also be thrown by called, imported functions. If it corresponds to an imported exception, it can be caught by an appropriate catch instruction. @@ -118,15 +117,15 @@ In the initial implementation, try blocks may only yield 0 or 1 values. ### Throws The _throw_ instruction has a single immediate argument, an exception tag. The -exception tag is used to define the constructed exception. The arguments for the -constructor must be on top of the value stack, and must correspond to the -exception type signature for the exception. +exception tag is used to define the data fields of the allocated exception. The +values for the data fields must be on top of the value stack, and must +correspond to the exception type signature for the exception. -When an exception is thrown, the values on the stack (corresponding to the type -signature) are popped off and the corresponding exception is constructed. The -exception is stored internally for access when the exception is caught. The -runtime then searches for nearest enclosing try block body that execution is -in. That try block is called the _catching_ try block. +When an exception is thrown, the exception is allocated and the values on the +stack (corresponding to the type signature) are popped off and assigned to the +allocated exception. The exception is stored internally for access when the +exception is caught. The runtime then searches for nearest enclosing try block +body that execution is in. That try block is called the _catching_ try block. If the throw appears within the body of a try block, it is the catching try block. @@ -144,13 +143,11 @@ are not in the body of the try block. Once a catching try block is found for the throw, the value stack is popped back to the size the value stack had when the try block was entered. Then, tagged catch blocks are tried in the order they appear in the catching try block, until -one matches. A tagged catch block matches if the corresponding `catch` -instruction is applicable, i.e. the corresponding exception was generated using -the constructor defined by the tag of the `catch` instruction. +one matches. If a matched tagged catch block is found, control is transferred to the body of -the catch block, and the constructor arguments (when the exception was created) -are pushed back onto the stack. +the catch block, and the data fields of the exception are pushed back onto the +stack. Otherwise, control is transferred to the body of the default catch block. However, unlike tagged catch blocks, the constructor arguments are not From 6d17d0e87c68381159c10074236246f5db2d12d5 Mon Sep 17 00:00:00 2001 From: Karl Schimpf Date: Wed, 3 May 2017 10:33:06 -0700 Subject: [PATCH 006/302] Introduce new except_type for exceptions. --- proposals/Exceptions.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index 71308476c0..c65e975454 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -191,13 +191,15 @@ This section describes changes in the [binary encoding design document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md). -### Exception type signatures +### except_type An exception is described by its exception type signature, which corresponds to -the function signature of the exception constructor. Hence, an exception _type -signature_ is a `func_type` that returns zero values. +the data fields of the exception. -Exception type signatures must appear in the type section. +| Field | Type | Description | +|-------|------|-------------| +| `count` | `varuint32` | The number of known exceptions | +| `sig` | `value_type*` | The type signature of each exception | ### External kind @@ -219,8 +221,8 @@ declares exception types using exception type signatures. | Field | Type | Description | |-------|------|-------------| -| count | `varuint32` | count of the number of exception types to follow | -| entries | `func_type` | sequence of indices into the type section | +| count | `varuint32` | count of the number of exceptions to follow | +| sig | `except_type*` | The type signature of the data fields for the exception | ### Import section @@ -231,7 +233,7 @@ If the `kind` is `Exception`: | Field | Type | Description | |-------|------|-------------| -| tag | varuint32 | index into exception section | +| tag | varuint32 | index into the exception section | | type | `varuint32` | type index of the function signature | ### Export section @@ -252,7 +254,7 @@ follows: | --------- | ---- | ----------- | | [Function](#function-names) | `1` | Assigns names to functions | | [Local](#local-names) | `2` | Assigns names to locals in functions | -| [Exception](#(exception-names) | `3` | Assigns names to exception types | +| [Exception](#exception-names) | `3` | Assigns names to exception types | ### Exception names From 037dbf18ad6955d0bf4bbbc85b7bf06ed64fe0d3 Mon Sep 17 00:00:00 2001 From: Karl Schimpf Date: Thu, 4 May 2017 08:31:22 -0700 Subject: [PATCH 007/302] Clean up nits, and define the exception index space. --- proposals/Exceptions.md | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index c65e975454..537757de75 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -84,7 +84,7 @@ else end ``` -A try block may contain one or more catch blocks, and all but the last catch +A try block also contain one or more catch blocks, and all but the last catch block must begin with a`catch` instruction. The last catch block can begin with either a `catch` or `else` instruction. The `catch`/`else` instructions (within the try construct) are called the _catching_ instructions. @@ -98,7 +98,7 @@ block). The `catch` instruction has an exception tag associated with it. The tag identifies what exceptions it can catch. That is, any exception created with the corresponding exception tag. Catch blocks that begin with a `catch` instruction -are considered a _tagged_ catch block. +are considered _tagged_ catch blocks. The last catch block of an exception can be a tagged catch block. Alternatively, it can begin with the `else` instruction. If it begins with the `else` @@ -154,7 +154,7 @@ block. However, unlike tagged catch blocks, the constructor arguments are not copied back onto the value stack. If no tagged catch blocks were matched, and the catching try block doesn't have -a default catch block, the exception is re-thrown to the next enclosing try +a default catch block, the exception is rethrown to the next enclosing try block. If control is transferred to the body of a catch block, and the last instruction @@ -198,8 +198,8 @@ the data fields of the exception. | Field | Type | Description | |-------|------|-------------| -| `count` | `varuint32` | The number of known exceptions | -| `sig` | `value_type*` | The type signature of each exception | +| `count` | `varuint32` | The number of types in the signature | +| `type` | `value_type*` | The type of each element in the signature | ### External kind @@ -222,7 +222,19 @@ declares exception types using exception type signatures. | Field | Type | Description | |-------|------|-------------| | count | `varuint32` | count of the number of exceptions to follow | -| sig | `except_type*` | The type signature of the data fields for the exception | +| sig | `except_type*` | The type signature of the data fields for each exception | + +#### Exception index space + +The _exception index space_ indexes all imported and internally-defined +exceptions, assigning monotonically-increasing indices based on the order +defined in the exception section. Thus, the index space starts at zero with +imported exceptions followed by internally-defined exceptions. + +**Note:** The exception index space is a change to the +[Modules document](https://github.com/WebAssembly/design/blob/master/Modules.md), +rather than the +[binary encoding design document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md). ### Import section @@ -233,8 +245,7 @@ If the `kind` is `Exception`: | Field | Type | Description | |-------|------|-------------| -| tag | varuint32 | index into the exception section | -| type | `varuint32` | type index of the function signature | +| `sig` | `except_type` | the type signature of the exception | ### Export section @@ -242,7 +253,7 @@ The export section is extended to include exception types by extending an `export_entry` as follows: If the `kind` is `Exception`, then the `index` is into the corresponding -exception in the _exception section_ index space. +exception in the [exception index space](#exception-index-space). ### Name section @@ -274,17 +285,16 @@ throws, and rethrows as follows: | `block` | `0x02` | sig : `block_type` | begin a sequence of expressions, yielding 0 or 1 values | | `loop` | `0x03` | sig : `block_type` | begin a block which can also form control flow loops | | `if` | `0x04` | sig : `block_type` | begin if expression | -| `else` | `0x05` | | begin else expression of if | +| `else` | `0x05` | | begin else expression of if or try | +| `try` | `0x06` | sig : `block_type` | begins a block which can handle thrown exceptions | +| `catch` | `0x07` | tag : `varuint32` | begins a block when the exception `tag` is thrown | +| `throw` | `0x08` | tag : `varuint32` | Throws an exception defined by the exception `tag` | +| `rethrow` | `0x09` | | re-throws the exception caught by the enclosing catch block | | `end` | `0x0b` | | end a block, loop, if, try, catch, and catch_default | | `br` | `0x0c` | relative_depth : `varuint32` | break that targets an outer nested block | | `br_if` | `0x0d` | relative_depth : `varuint32` | conditional break that targets an outer nested block | | `br_table` | `0x0e` | see below | branch table control flow construct | | `return` | `0x0f` | | return zero or one value from this function | -| `try` | 0x?? | sig : `block_type` | begins a block which can handle thrown exceptions | -| `catch` | 0x?? | tag : `varuint32` | begins a block when the exception `tag` is thrown | -| `catch_default` | 0x?? | | begins a block when an unknown exception is thrown | -| `throw` | 0x?? | tag : `varuint32` | Throws an exception defined by the exception `tag` | -| `rethrow` | 0x?? | | re-throws the exception caught by the enclosing catch block | The *sig* fields of `block', 'if`, and `try` operators are block signatures which describe their use of the operand stack. From d3d3b6ae48384d9546b61396fe8ea5f0ff5efc99 Mon Sep 17 00:00:00 2001 From: Karl Schimpf Date: Thu, 4 May 2017 10:24:59 -0700 Subject: [PATCH 008/302] Fix nits. --- proposals/Exceptions.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index 537757de75..983c91e045 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -84,7 +84,7 @@ else end ``` -A try block also contain one or more catch blocks, and all but the last catch +A try block also contains one or more catch blocks, and all but the last catch block must begin with a`catch` instruction. The last catch block can begin with either a `catch` or `else` instruction. The `catch`/`else` instructions (within the try construct) are called the _catching_ instructions. @@ -228,8 +228,8 @@ declares exception types using exception type signatures. The _exception index space_ indexes all imported and internally-defined exceptions, assigning monotonically-increasing indices based on the order -defined in the exception section. Thus, the index space starts at zero with -imported exceptions followed by internally-defined exceptions. +defined in the import and exception sections. Thus, the index space starts at +zero with imported exceptions followed by internally-defined exceptions. **Note:** The exception index space is a change to the [Modules document](https://github.com/WebAssembly/design/blob/master/Modules.md), From d9208406f94a8f92b45d0a98120acdfe69691c94 Mon Sep 17 00:00:00 2001 From: Karl Schimpf Date: Thu, 11 May 2017 12:49:00 -0700 Subject: [PATCH 009/302] Handle issues 7, 9, and 10. --- proposals/Exceptions.md | 117 ++++++++++++++++++++++++++++------------ 1 file changed, 82 insertions(+), 35 deletions(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index 983c91e045..e4a4afe484 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -1,11 +1,14 @@ # Exception handling -There are two sections to this proposal +There are four sections to this proposal 1. A overview of the proposed extension to WebAssembly + +2. Changes to the text format document. + +3. Changes to the Modules document. -2. Changes of the WebAssembly Binary Design document needed to include this - proposal. +3. Changes of the WebAssembly Binary Design document. The proposal here is also meant to be a minimal proposal that may be further extended sometime in the future. @@ -44,8 +47,9 @@ by a new _exception_ section of a WebAssembly module. The exception section is a list of exceptions. Each exception has a _type signature_. The type signature defines the list of values associated with an exception. -Within the module, exceptions are identified by an index into the exception -section. This index is referred to as the _exception tag_. +Within the module, exceptions are identified by an index into +the [exception index space](#exception-index-space). This index is referred to +as the _exception tag_. Exceptions can be imported and exported by adding the appropriate entries to the import and export sections of the module. All imported/exported exceptions must @@ -63,7 +67,7 @@ but the data of the exception can't be accessed. ### Try and catch blocks. -A _try_ block defines a list of instruction that may need to catch exceptions +A _try_ block defines a list of instructions that may need to catch exceptions and/or clean up state when an exception is thrown. Like other higher-level constructs, a try block begins with a `try` instruction, and ends with an `end` instruction. That is, a try block is sequence of instructions having the @@ -79,15 +83,15 @@ catch j ... catch n instruction* -else +catch default instruction* end ``` A try block also contains one or more catch blocks, and all but the last catch block must begin with a`catch` instruction. The last catch block can begin with -either a `catch` or `else` instruction. The `catch`/`else` instructions (within -the try construct) are called the _catching_ instructions. +either a `catch` or `catch_deafult` instruction. The `catch`/`catch default` +instructions (within the try construct) are called the _catching_ instructions. The _body_ of the try block is the list of instructions before the first catching instruction. The _body_ of each catch block is the sequence of @@ -101,10 +105,10 @@ corresponding exception tag. Catch blocks that begin with a `catch` instruction are considered _tagged_ catch blocks. The last catch block of an exception can be a tagged catch block. Alternatively, -it can begin with the `else` instruction. If it begins with the `else` -instruction, it defines the _default_ catch block. The default catch block has -no exception type, and is used to catch all exceptions not caught by any of the -tagged catch blocks. +it can begin with the `catch default` instruction. If it begins with the +`catch default` instruction, it defines the _default_ catch block. The default +catch block has no exception type, and is used to catch all exceptions not +caught by any of the tagged catch blocks. Try blocks, like a control-flow blocks, have a _block type_. The block type of a try block defines the values yielded by the evaluation the try block when either @@ -118,7 +122,7 @@ In the initial implementation, try blocks may only yield 0 or 1 values. The _throw_ instruction has a single immediate argument, an exception tag. The exception tag is used to define the data fields of the allocated exception. The -values for the data fields must be on top of the value stack, and must +values for the data fields must be on top of the operand stack, and must correspond to the exception type signature for the exception. When an exception is thrown, the exception is allocated and the values on the @@ -140,8 +144,8 @@ A throw inside a the body of a catch block is never caught by the corresponding try block of the catch block, since instructions in the body of the catch block are not in the body of the try block. -Once a catching try block is found for the throw, the value stack is popped back -to the size the value stack had when the try block was entered. Then, tagged +Once a catching try block is found for the throw, the operand stack is popped back +to the size the operand stack had when the try block was entered. Then, tagged catch blocks are tried in the order they appear in the catching try block, until one matches. @@ -151,7 +155,7 @@ stack. Otherwise, control is transferred to the body of the default catch block. However, unlike tagged catch blocks, the constructor arguments are not -copied back onto the value stack. +copied back onto the operand stack. If no tagged catch blocks were matched, and the catching try block doesn't have a default catch block, the exception is rethrown to the next enclosing try @@ -170,21 +174,70 @@ also be sure to also pop off the caught exception values. ### Rethrows -The _rethrow_ instruction has no arguments, and can only appear in catch -blocks. It always re-throws the exception caught by the catch block. This allows -the catch block to clean up state before the exception is passed back to the -next enclosing try block. +The _rethrow_ instruction can only appear in the body of a catch block. The +_rethrow_ instruction gets a single index argument. It is to disambiguate which +caught exception is to be rethrown, when inside nested catch blocks (of +corresponding nested try blocks). The blocks are numbered monotonically +(inside-out) starting at zero. Sero implies the immediately enclosing catch +block. + +The _rethrow_ isntruction always re-throws the exception caught by the +referenced catch block. This allows the catch block to clean up state before the +exception is passed back to the next enclosing try block. ### Debugging Earlier discussion implied that when an exception is thrown, the runtime will -pop the value stack across function calls until a corresponding, enclosing try +pop the operand stack across function calls until a corresponding, enclosing try block is found. The implementation may actually not do this. Rather, it may first search up the call stack to see if there is an enclosing try. If none are found, it could terminate the thread at that point of the throw. This would allow better debugging capability, since the corresponding call stack is still there to query. +## Changes to the text format. + +This section describes change in the +[instruction syntax document](https://github.com/WebAssembly/spec/blob/master/document/syntax/instructions.rst). + +### Control Instructions + +The following rule is added to *instructions*: + +``` +instructions ::= + ... + try resulttype instr* catch+ end | + throw exceptidex | + rethrow + +catch ::= + catch exceptidx inst* | + catch default inst* +``` + +Like the *block*, *loop*, and *if* instructions, the *try* instruction is a +*structured* instruction, and is implicitly labeled. this allows branch +instructions to exit try blocks. + +The _exceptidx_ of the *catch* instruction is the exception tag for the caught +exception. Similarly, the _exceptidx_ of the *throw* instruction is the tag for +the constructed exception. See [exception index space](#exception-index-space) +for further clarification of exception tags. + +## Changes to Modules document. + +This section describes change in the +[Modules document](https://github.com/WebAssembly/design/blob/master/Modules.md). + +#### Exception index space + +The _exception index space_ indexes all imported and internally-defined +exceptions, assigning monotonically-increasing indices based on the order +defined in the import and exception sections. Thus, the index space starts at +zero with imported exceptions followed by internally-defined exceptions in +the [exception section](#exception-section). + ## Changes to the binary model This section describes changes in @@ -224,18 +277,6 @@ declares exception types using exception type signatures. | count | `varuint32` | count of the number of exceptions to follow | | sig | `except_type*` | The type signature of the data fields for each exception | -#### Exception index space - -The _exception index space_ indexes all imported and internally-defined -exceptions, assigning monotonically-increasing indices based on the order -defined in the import and exception sections. Thus, the index space starts at -zero with imported exceptions followed by internally-defined exceptions. - -**Note:** The exception index space is a change to the -[Modules document](https://github.com/WebAssembly/design/blob/master/Modules.md), -rather than the -[binary encoding design document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md). - ### Import section The import section is extended to include exception types by extending an @@ -289,7 +330,7 @@ throws, and rethrows as follows: | `try` | `0x06` | sig : `block_type` | begins a block which can handle thrown exceptions | | `catch` | `0x07` | tag : `varuint32` | begins a block when the exception `tag` is thrown | | `throw` | `0x08` | tag : `varuint32` | Throws an exception defined by the exception `tag` | -| `rethrow` | `0x09` | | re-throws the exception caught by the enclosing catch block | +| `rethrow` | `0x09` | catch_index : `varuint32` | re-throws the exception caught by the enclosing catch block | | `end` | `0x0b` | | end a block, loop, if, try, catch, and catch_default | | `br` | `0x0c` | relative_depth : `varuint32` | break that targets an outer nested block | | `br_if` | `0x0d` | relative_depth : `varuint32` | conditional break that targets an outer nested block | @@ -298,3 +339,9 @@ throws, and rethrows as follows: The *sig* fields of `block', 'if`, and `try` operators are block signatures which describe their use of the operand stack. + +Note that the textual `catch default` instruction is implemented using the +`else` operator. Since the `else` operator is always unambiguous in the binary +format, there is no need to tie up a separate opcode for the `catch default` +instruction. + From 9e5b9ff954b1f1acb5fb8ac12cb90200ec7555e7 Mon Sep 17 00:00:00 2001 From: Karl Schimpf Date: Thu, 11 May 2017 14:04:37 -0700 Subject: [PATCH 010/302] Fix nits and add example. --- proposals/Exceptions.md | 73 +++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index e4a4afe484..af9e9caa47 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -4,11 +4,11 @@ There are four sections to this proposal 1. A overview of the proposed extension to WebAssembly -2. Changes to the text format document. +1. Changes to the text format document. -3. Changes to the Modules document. +1. Changes to the Modules document. -3. Changes of the WebAssembly Binary Design document. +1. Changes of the WebAssembly Binary Design document. The proposal here is also meant to be a minimal proposal that may be further extended sometime in the future. @@ -21,13 +21,13 @@ may be an unknown exception thrown by an imported call. Thrown exceptions are handled as follows: -a) They can be caught by a catch block in an enclosing try block of a function +1. They can be caught by a catch block in an enclosing try block of a function body. -b) Throws not caught within a function body continue up the call stack until an +1. Throws not caught within a function body continue up the call stack until an enclosing try block is found. -c) If the call stack is exhausted without any enclosing try blocks, it +1. If the call stack is exhausted without any enclosing try blocks, it terminates the application. This proposal looks at the changes needed to incorporate these concepts into the @@ -90,7 +90,7 @@ end A try block also contains one or more catch blocks, and all but the last catch block must begin with a`catch` instruction. The last catch block can begin with -either a `catch` or `catch_deafult` instruction. The `catch`/`catch default` +either a `catch` or `catch default` instruction. The `catch`/`catch default` instructions (within the try construct) are called the _catching_ instructions. The _body_ of the try block is the list of instructions before the first @@ -175,15 +175,43 @@ also be sure to also pop off the caught exception values. ### Rethrows The _rethrow_ instruction can only appear in the body of a catch block. The -_rethrow_ instruction gets a single index argument. It is to disambiguate which -caught exception is to be rethrown, when inside nested catch blocks (of -corresponding nested try blocks). The blocks are numbered monotonically -(inside-out) starting at zero. Sero implies the immediately enclosing catch -block. +_rethrow_ instruction always re-throws the exception caught by the referenced +catch block. This allows the catch block to clean up state before the exception +is passed back to the next enclosing try block. + +The _rethrow_ instruction gets a _catch index_ argument. It is to disambiguate +which caught exception is to be rethrown, when inside nested catch blocks (of +corresponding nested try blocks). + +For example consider the following example: + +``` +try + ... +catch 1 + ... + try + ... + catch 2 + ... + try + ... + catch 3 + ... + rethrow N + end + end +end +``` + +In this example, `N` is used to disambiguate which caught exception is being +rethrown. It could rethrow any of the three caught expceptions. The catch blocks +are numbered monotonically (inside-out) starting at zero. Zero implies the +immediately enclosing catch block. -The _rethrow_ isntruction always re-throws the exception caught by the -referenced catch block. This allows the catch block to clean up state before the -exception is passed back to the next enclosing try block. +So, in the above example, `rethrow 0` corresponds to the exception caught by +`catch 3`, `rethrow 1` corresponds to the exception caught by `catch 2`, and +`rethrow 2` corresponds to the exception caught by `catch 1`. ### Debugging @@ -208,11 +236,11 @@ The following rule is added to *instructions*: instructions ::= ... try resulttype instr* catch+ end | - throw exceptidex | - rethrow + throw except_index | + rethrow catch_index catch ::= - catch exceptidx inst* | + catch except_index inst* | catch default inst* ``` @@ -220,11 +248,14 @@ Like the *block*, *loop*, and *if* instructions, the *try* instruction is a *structured* instruction, and is implicitly labeled. this allows branch instructions to exit try blocks. -The _exceptidx_ of the *catch* instruction is the exception tag for the caught -exception. Similarly, the _exceptidx_ of the *throw* instruction is the tag for +The `except_index` of the `catch` instruction is the exception tag for the caught +exception. Similarly, the `except_index` of the *throw* instruction is the tag for the constructed exception. See [exception index space](#exception-index-space) for further clarification of exception tags. +The `catch_index` of the `rethrow` instruciton is the index to the corresponding +catch that defines the exception to throw. + ## Changes to Modules document. This section describes change in the @@ -331,7 +362,7 @@ throws, and rethrows as follows: | `catch` | `0x07` | tag : `varuint32` | begins a block when the exception `tag` is thrown | | `throw` | `0x08` | tag : `varuint32` | Throws an exception defined by the exception `tag` | | `rethrow` | `0x09` | catch_index : `varuint32` | re-throws the exception caught by the enclosing catch block | -| `end` | `0x0b` | | end a block, loop, if, try, catch, and catch_default | +| `end` | `0x0b` | | end a block, loop, if, try, catch, and catch default | | `br` | `0x0c` | relative_depth : `varuint32` | break that targets an outer nested block | | `br_if` | `0x0d` | relative_depth : `varuint32` | conditional break that targets an outer nested block | | `br_table` | `0x0e` | see below | branch table control flow construct | From b17d8aebfc67d0eedd318a95b5fb70d78adb01be Mon Sep 17 00:00:00 2001 From: Karl Schimpf Date: Thu, 11 May 2017 14:08:31 -0700 Subject: [PATCH 011/302] Fix where end can appear. --- proposals/Exceptions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index af9e9caa47..3d5bd2f7b4 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -362,7 +362,7 @@ throws, and rethrows as follows: | `catch` | `0x07` | tag : `varuint32` | begins a block when the exception `tag` is thrown | | `throw` | `0x08` | tag : `varuint32` | Throws an exception defined by the exception `tag` | | `rethrow` | `0x09` | catch_index : `varuint32` | re-throws the exception caught by the enclosing catch block | -| `end` | `0x0b` | | end a block, loop, if, try, catch, and catch default | +| `end` | `0x0b` | | end a block, loop, if, and try | | `br` | `0x0c` | relative_depth : `varuint32` | break that targets an outer nested block | | `br_if` | `0x0d` | relative_depth : `varuint32` | conditional break that targets an outer nested block | | `br_table` | `0x0e` | see below | branch table control flow construct | From d9d5cace0b7d73b91a27278ddbedab22523234fb Mon Sep 17 00:00:00 2001 From: kschimpf Date: Fri, 12 May 2017 08:55:22 -0700 Subject: [PATCH 012/302] Use catch-all and make rethrows use a label. --- proposals/Exceptions.md | 53 ++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index 3d5bd2f7b4..bd0a38a555 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -83,14 +83,14 @@ catch j ... catch n instruction* -catch default +catch_all instruction* end ``` A try block also contains one or more catch blocks, and all but the last catch block must begin with a`catch` instruction. The last catch block can begin with -either a `catch` or `catch default` instruction. The `catch`/`catch default` +either a `catch` or `catch_all` instruction. The `catch`/`catch_all` instructions (within the try construct) are called the _catching_ instructions. The _body_ of the try block is the list of instructions before the first @@ -105,8 +105,8 @@ corresponding exception tag. Catch blocks that begin with a `catch` instruction are considered _tagged_ catch blocks. The last catch block of an exception can be a tagged catch block. Alternatively, -it can begin with the `catch default` instruction. If it begins with the -`catch default` instruction, it defines the _default_ catch block. The default +it can begin with the `catch_all` instruction. If it begins with the +`catch_all` instruction, it defines the _default_ catch block. The default catch block has no exception type, and is used to catch all exceptions not caught by any of the tagged catch blocks. @@ -179,9 +179,11 @@ _rethrow_ instruction always re-throws the exception caught by the referenced catch block. This allows the catch block to clean up state before the exception is passed back to the next enclosing try block. -The _rethrow_ instruction gets a _catch index_ argument. It is to disambiguate -which caught exception is to be rethrown, when inside nested catch blocks (of -corresponding nested try blocks). +Associated with the _rethrow_ instruction is a _label_. The label is used to +disambiguate which exception is to be rethrown, when inside nested catch blocks. + +The label is the relative block depth to the corresponding try block for which +the catching block appears. For example consider the following example: @@ -190,28 +192,29 @@ try ... catch 1 ... - try - ... - catch 2 + begin ... try ... - catch 3 + catch 2 ... - rethrow N + try + ... + catch 3 + ... + rethrow N + end end end + ... end ``` In this example, `N` is used to disambiguate which caught exception is being -rethrown. It could rethrow any of the three caught expceptions. The catch blocks -are numbered monotonically (inside-out) starting at zero. Zero implies the -immediately enclosing catch block. - -So, in the above example, `rethrow 0` corresponds to the exception caught by -`catch 3`, `rethrow 1` corresponds to the exception caught by `catch 2`, and -`rethrow 2` corresponds to the exception caught by `catch 1`. +rethrown. It could rethrow any of the three caught expceptions. Hence, +`rethrow 0` corresponds to the exception caught by `catch 3`, `rethrow 1` +corresponds to the exception caught by `catch 2`, and `rethrow 4` corresponds +to the exception caught by `catch 1`. ### Debugging @@ -219,14 +222,14 @@ Earlier discussion implied that when an exception is thrown, the runtime will pop the operand stack across function calls until a corresponding, enclosing try block is found. The implementation may actually not do this. Rather, it may first search up the call stack to see if there is an enclosing try. If none are -found, it could terminate the thread at that point of the throw. This would +found, it could terminate the thread at the point of the throw. This would allow better debugging capability, since the corresponding call stack is still there to query. ## Changes to the text format. This section describes change in the -[instruction syntax document](https://github.com/WebAssembly/spec/blob/master/document/syntax/instructions.rst). +[instruction syntax document](https://github.com/WebAssembly/spec/blob/master/document/text/instructions.rst). ### Control Instructions @@ -241,7 +244,7 @@ instructions ::= catch ::= catch except_index inst* | - catch default inst* + catch_all inst* ``` Like the *block*, *loop*, and *if* instructions, the *try* instruction is a @@ -253,7 +256,7 @@ exception. Similarly, the `except_index` of the *throw* instruction is the tag f the constructed exception. See [exception index space](#exception-index-space) for further clarification of exception tags. -The `catch_index` of the `rethrow` instruciton is the index to the corresponding +The `catch_index` of the `rethrow` instruction is the index to the corresponding catch that defines the exception to throw. ## Changes to Modules document. @@ -371,8 +374,8 @@ throws, and rethrows as follows: The *sig* fields of `block', 'if`, and `try` operators are block signatures which describe their use of the operand stack. -Note that the textual `catch default` instruction is implemented using the +Note that the textual `catch_all` instruction is implemented using the `else` operator. Since the `else` operator is always unambiguous in the binary -format, there is no need to tie up a separate opcode for the `catch default` +format, there is no need to tie up a separate opcode for the `catch_all` instruction. From 2eb8c41f6b0e81a17a8f617bef3a19778e820801 Mon Sep 17 00:00:00 2001 From: kschimpf Date: Fri, 12 May 2017 09:18:16 -0700 Subject: [PATCH 013/302] Clean up the control flow operator entry for rethrow. --- proposals/Exceptions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index bd0a38a555..1cd54d0e89 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -364,7 +364,7 @@ throws, and rethrows as follows: | `try` | `0x06` | sig : `block_type` | begins a block which can handle thrown exceptions | | `catch` | `0x07` | tag : `varuint32` | begins a block when the exception `tag` is thrown | | `throw` | `0x08` | tag : `varuint32` | Throws an exception defined by the exception `tag` | -| `rethrow` | `0x09` | catch_index : `varuint32` | re-throws the exception caught by the enclosing catch block | +| `rethrow` | `0x09` | relativew_depth : `varuint32` | re-throws the exception caught by the corresponding try block | | `end` | `0x0b` | | end a block, loop, if, and try | | `br` | `0x0c` | relative_depth : `varuint32` | break that targets an outer nested block | | `br_if` | `0x0d` | relative_depth : `varuint32` | conditional break that targets an outer nested block | From b5157b5749fb35a8b6a0256cf640e81a5bb1f0d5 Mon Sep 17 00:00:00 2001 From: Karl Schimpf Date: Mon, 15 May 2017 08:10:27 -0700 Subject: [PATCH 014/302] Fix nits. --- proposals/Exceptions.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index 1cd54d0e89..8cc36b6994 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -110,7 +110,7 @@ it can begin with the `catch_all` instruction. If it begins with the catch block has no exception type, and is used to catch all exceptions not caught by any of the tagged catch blocks. -Try blocks, like a control-flow blocks, have a _block type_. The block type of a +Try blocks, like control-flow blocks, have a _block type_. The block type of a try block defines the values yielded by the evaluation the try block when either no exception is thrown, or the exception is successfully caught by one of its catch blocks, and the instructions within the catch block can recover from the @@ -192,7 +192,7 @@ try ... catch 1 ... - begin + block ... try ... @@ -213,9 +213,12 @@ end In this example, `N` is used to disambiguate which caught exception is being rethrown. It could rethrow any of the three caught expceptions. Hence, `rethrow 0` corresponds to the exception caught by `catch 3`, `rethrow 1` -corresponds to the exception caught by `catch 2`, and `rethrow 4` corresponds +corresponds to the exception caught by `catch 2`, and `rethrow 3` corresponds to the exception caught by `catch 1`. +Note that `rethrow 2` is not allowed because it does not reference a `try` +instruction. Rather, it references a `block` instruction. + ### Debugging Earlier discussion implied that when an exception is thrown, the runtime will @@ -240,7 +243,7 @@ instructions ::= ... try resulttype instr* catch+ end | throw except_index | - rethrow catch_index + rethrow label catch ::= catch except_index inst* | @@ -256,8 +259,8 @@ exception. Similarly, the `except_index` of the *throw* instruction is the tag f the constructed exception. See [exception index space](#exception-index-space) for further clarification of exception tags. -The `catch_index` of the `rethrow` instruction is the index to the corresponding -catch that defines the exception to throw. +The `label` of the `rethrow` instruction is the label to the corresponding try +block, defining the catch to rethrow. ## Changes to Modules document. From 740894f377f4a71ecbc9e48647a1aa54df28626c Mon Sep 17 00:00:00 2001 From: Karl Schimpf Date: Mon, 15 May 2017 08:34:28 -0700 Subject: [PATCH 015/302] Fix more nits. --- proposals/Exceptions.md | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index 8cc36b6994..60dcf3f933 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -38,7 +38,7 @@ must implement lightweight or heavyweight exceptions. Rather, it defers that choice to the runtime implementation. Exception handling is defined using *exceptions*, *try blocks*, *catch blocks*, -and the instructions *throw* and *rethrow*. +and the instructions `throw` and `rethrow`. ### Exceptions @@ -120,7 +120,7 @@ In the initial implementation, try blocks may only yield 0 or 1 values. ### Throws -The _throw_ instruction has a single immediate argument, an exception tag. The +The `throw` instruction has a single immediate argument, an exception tag. The exception tag is used to define the data fields of the allocated exception. The values for the data fields must be on top of the operand stack, and must correspond to the exception type signature for the exception. @@ -174,18 +174,18 @@ also be sure to also pop off the caught exception values. ### Rethrows -The _rethrow_ instruction can only appear in the body of a catch block. The -_rethrow_ instruction always re-throws the exception caught by the referenced +The `rethrow` instruction can only appear in the body of a catch block. The +`rethrow` instruction always re-throws the exception caught by an enclosing catch block. This allows the catch block to clean up state before the exception is passed back to the next enclosing try block. -Associated with the _rethrow_ instruction is a _label_. The label is used to +Associated with the `rethrow` instruction is a _label_. The label is used to disambiguate which exception is to be rethrown, when inside nested catch blocks. The label is the relative block depth to the corresponding try block for which the catching block appears. -For example consider the following example: +For example consider the following: ``` try @@ -250,12 +250,12 @@ catch ::= catch_all inst* ``` -Like the *block*, *loop*, and *if* instructions, the *try* instruction is a -*structured* instruction, and is implicitly labeled. this allows branch +Like the `block`, `loop`, and `if` instructions, the `try` instruction is a +*structured* instruction, and is implicitly labeled. This allows branch instructions to exit try blocks. The `except_index` of the `catch` instruction is the exception tag for the caught -exception. Similarly, the `except_index` of the *throw* instruction is the tag for +exception. Similarly, the `except_index` of the `throw` instruction is the tag for the constructed exception. See [exception index space](#exception-index-space) for further clarification of exception tags. @@ -367,18 +367,17 @@ throws, and rethrows as follows: | `try` | `0x06` | sig : `block_type` | begins a block which can handle thrown exceptions | | `catch` | `0x07` | tag : `varuint32` | begins a block when the exception `tag` is thrown | | `throw` | `0x08` | tag : `varuint32` | Throws an exception defined by the exception `tag` | -| `rethrow` | `0x09` | relativew_depth : `varuint32` | re-throws the exception caught by the corresponding try block | -| `end` | `0x0b` | | end a block, loop, if, and try | +| `rethrow` | `0x09` | relative_depth : `varuint32` | re-throws the exception caught by the corresponding try block | +| `end` | `0x0b` | | end a block, loop, if, and try | | `br` | `0x0c` | relative_depth : `varuint32` | break that targets an outer nested block | | `br_if` | `0x0d` | relative_depth : `varuint32` | conditional break that targets an outer nested block | | `br_table` | `0x0e` | see below | branch table control flow construct | | `return` | `0x0f` | | return zero or one value from this function | -The *sig* fields of `block', 'if`, and `try` operators are block signatures +The *sig* fields of `block`, `if`, and `try` operators are block signatures which describe their use of the operand stack. Note that the textual `catch_all` instruction is implemented using the `else` operator. Since the `else` operator is always unambiguous in the binary format, there is no need to tie up a separate opcode for the `catch_all` instruction. - From 6ba25ce5478506d5902458eed9c4bdc7ecc46ea6 Mon Sep 17 00:00:00 2001 From: Karl Schimpf Date: Tue, 16 May 2017 09:50:00 -0700 Subject: [PATCH 016/302] Change README.md to reflect that this repository is a proposal. --- README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4092be9ca2..58eb078d21 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,20 @@ [![Build Status](https://travis-ci.org/WebAssembly/spec.svg?branch=master)](https://travis-ci.org/WebAssembly/spec) -# spec +# Exception handling + +This repository +a holds +[propsal](https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md) for +adding exception handling to WebAssembly. + +The repository is a copy +of [WebAssembly/spec](https://github.com/WebAssembly/spec). + +The remainder of the document is contents of the +original [README.md](https://github.com/WebAssembly/spec/blob/master/README.md) +document of that repository. + +## spec This repository holds a prototypical reference implementation for WebAssembly, which is currently serving as the official specification. Eventually, we expect From d02bff64f493cf73c782c00d6d7d34ba70b8086f Mon Sep 17 00:00:00 2001 From: Karl Schimpf Date: Tue, 16 May 2017 09:52:45 -0700 Subject: [PATCH 017/302] Fix sentence structure. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 58eb078d21..cae5105c86 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ # Exception handling This repository -a holds +holds a [propsal](https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md) for adding exception handling to WebAssembly. From d2ff7d8fd35e116ff1e791d0e6c55b5e328456ef Mon Sep 17 00:00:00 2001 From: Karl Schimpf Date: Fri, 9 Feb 2018 10:41:18 -0800 Subject: [PATCH 018/302] Initial draft of the layer 1. --- proposals/Layer-1.md | 390 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 390 insertions(+) create mode 100644 proposals/Layer-1.md diff --git a/proposals/Layer-1.md b/proposals/Layer-1.md new file mode 100644 index 0000000000..e106d02fe8 --- /dev/null +++ b/proposals/Layer-1.md @@ -0,0 +1,390 @@ +# Layer 1 exception handling + +Layer 1 of exception handling is the MVP (minimal viable proposal) for +implementing exceptions in WebAssembly. As such, it doesn't include higher-level +concepts and structures. These concept and structures are introduced in later +layers, and either: + +1. Improves readability by combining concepts in layer 1 into higher-level + constructs, thereby reducing code size. + +2. Allow performance improvements in the VM. + +3. Introduce additional new functionality not available in layer 1. + +## Overview + +Exception handling allows code to break control flow when an exception is +thrown. The exeception can be any exception known by the WebAssembly module, or +it may an unknown exception that was thrown by a called imported function. + +One of the problems with exception handling is that both WebAssembly and the +host VM probably have different notions of what exceptions are, but both must be +aware of the other. + +It is difficult to define exceptions in WebAssembly because (in general) +it doesn't have knowledge of the host VM. Further, adding such knowledge to +WebAssembly would limit the ability for other host VMs to support WebAssembly +exceptions. + +One issue is that both sides need to know if an exception was thrown by the +other, because cleanup may need to be performed. + +Another problem is that WebAssembly doesn't have direct access to the host VM's +memory. As a result, WebAssembly defers the handling of exceptions to the host +VM. + +To access exceptions, WebAssembly provides instructions to check if the +exception is one that WebAssembly understands. If so, the data of the +WebAssembly exceptions's data is extracted and copied onto the stack, allowing +succeeding instructions to process the data. + +Lastly, exception lifetimes must be maintained by the host VM, so that it can +collect and reuse the memory used by exceptions. This implies that the host must +know where exceptions are stored, so that it can determine when an exception can +be garbage collected. + +This also implies that the host VM must provide a garbage collector for +exceptions. For host VMs that have garbage collection (such as JavaScript), +this is not a problem. + +However, not all host VMs may have a garbage collector. For this reason, +WebAssembly exceptions are designed to allow the use of reference counters to +perform the the garbage collection in the host VM. + +To do this, WebAssembly exceptions are immutable once created, to avoid cyclic +data structures that can't be garbage collected. It also means that exceptions +can't be stored into linear memory. The rationale for this is twofold: + +* For security. Loads + and stores do not guarantee that the data read was of the same type as + stored. This allows spoofing of exception references that may allow a + WebAssembly module to access data it should not know in the host VM. + +* The host VM does not know the layout of data in linear memory, so it can't + find places where exception references are stored. + +Hence, while an exception reference is a new first class type, this proposal +disallows their usage in linear memory. + +A WebAssembly exception is created by the `except` instruction. Once an +exception is created, you can throw it with the `throw` instruction. Thrown +exceptions are handled as follows: + +1. They can be caught by a catch block in an enclosing try block of a function + body. The caught exception is pushed onto the stack. + +1. Throws not caught within a function body continue up the call stack, popping + call frames, until an enclosing try block is found. + +1. If the call stack is exhausted without any enclosing try blocks, the host VM + defines how to handle the uncaught exception. + +### Exceptions + +An `exception` is an internal construct in WebAssembly that is maintained by the +host. WebAssembly exceptions (as opposed to host exceptions) are defined by a +new `exception section` of a WebAssembly module. The exception section is a list +of exception types, from which exceptions can be created. + +Each exception type has a `type signature`. The type signature defines the list +of values associated with the exception. + +Within the module, exception types are identified by an index into the +[exception index space](#exception-index-space). This index is referred to as +the `exception tag`. The `tagged exception type` is the corresponding +exception type refered to by the exception tag. + +Exception types can be imported and exported by adding the appropriate entries +to the import and export sections of the module. All imported/exported exception +types must be named to reconcile exception tags between modules. + +Exception tags are used by: + +1. The `except` instruction which creates a WebAssembly instance of the + corresponding tagged exception type, and pushes a reference to it onto the + stack. + +2. The `if_except` instruction that queries an exception to see if it is an + instance of the corresponding tagged exception class, and if true it pushes + the corresponding values of the exception onto the stack. + +### The exception refernce data type + +Data types are extended to have a new `except_ref` type. The representation of +an exception type is left to the host VM, but its size must be fixed. The actual +number of bytes it takes to represent any `except_ref` is left to the host VM. + +### Try and catch blocks + +A _try block_ defines a list of instructions that may need to process exceptions +and/or clean up state when an exception is thrown. Like other higher-level +constructs, a try block begins with a `try` instruction, and ends with an `end` +instruction. That is, a try block is sequence of instructions having the +following form: + +``` +try block_type + instruction* +catch + instruction* +end +``` + +A try block ends with a `catch block` that is defined by the list of +instructions after the `catch` instruction. + +Try blocks, like control-flow blocks, have a _block type_. The block type of a +try block defines the values yielded by the evaluation the try block when either +no exception is thrown, or the exception is successfully caught by the catch +block. + +In the initial implementation, try blocks may only yield 0 or 1 values. + +### Exception creation + +A `except` instruction has a single immediate argument, an exception tag. The +corresponding tagged exception type is used to define the data fields of the +created exception. The values for the data fields must be on top of the operand +stack, and must correspond to the exception's type signature. These values are +popped off the stack and an instance of the exception is then created. A +reference to the created exception is then pushed onto the stack. + +### Throws + +The `throw` throws the exception on top of the stack. The exception is popped +off the top of the stack before throwing. + +When an exception is thrown, the host VM searches for nearest enclosing try +block body that execution is in. That try block is called the _catching_ try +block. + +If the throw appears within the body of a try block, it is the catching try +block. + +If a throw occurs within a function body, and it doesn't appear inside the body +of a try block, the throw continues up the call stack until it is in the body of +an an enclosing try block, or the call stack is flushed. If the call stack is +flushed, the host VM defines how to handle uncaught exceptions. Otherwise, the +found enclosing try block is the catching try block. + +A throw inside the body of a catch block is never caught by the corresponding +try block of the catch block, since instructions in the body of the catch block +are not in the body of the try block. + +Once a catching try block is found for the throw, the operand stack is popped back +to the size the operand stack had when the try block was entered, and then +the caught exception is pushed onto the stack. + +If control is transferred to the body of a catch block, and the last instruction +in the body is executed, control then exits the try block. + +If the selected catch block does not throw an exception, it must yield the +value(s) expected by the corresponding catching try block. This includes popping +the caught exception. + +Note that a caught exception can be rethrown using the `throw` instruction. + +### Exception data extraction + +The `if_except block` defines a conditional query of the exception on top of the +stack. The exception is not popped when queried. The if_except block has two +subblocks, the `then` and `else` subblocks, like that of an `if` block. The then +block is a sequence of instructions following the `if_except` instruction. The +else block is optional, and if it appears, it begins with the `else` +instruction. The scope of the if_except block is from the `if_except` +instruction to the corresponding `end` instruction. + +That is, the forms of an if_except block is: + +``` +if_except block_type except_index + Instruction* +end + +if_except block_type except_index + Instruction* +else + Instructions* +end +``` + +The conditional query of an exception succeeds when the exception on the top of +the stack is an instance of the corresponding tagged exception type (defined by +`except_index`). + +If the query succeeds, the data values (associated with the type signature of +the exception class) are extracted and pushed onto the stack, and control +transfers to the instructions in the then block. + +If the query fails, it either enters the else block, or transfer control to the +end of the if_except block if there is no else block. + +### Debugging + +Earlier discussion implied that when an exception is thrown, the runtime will +pop the operand stack across function calls until a corresponding, enclosing try +block is found. The implementation may actually not do this. Rather, it may +first search up the call stack to see if there is an enclosing try. If none are +found, it could terminate the thread at the point of the throw. This would +allow better debugging capability, since the corresponding call stack is still +there to query. + +## Changes to the text format. + +This section describes change in the +[instruction syntax document](https://github.com/WebAssembly/spec/blob/master/document/core/instructions.rst). + +### New instructions + +The following rules are added to *instructions*: + +``` + try resulttype instructions* catch instructions* end | + except except_index | + throw | + if_except resulttype except_index then Instructions* end | + if_except resulttype except_index then Instructions* else Instructions* end +``` + +Like the `block`, `loop`, and `if` instructions, the `try` and `if_except` +instructions are *structured* control flow instructions, and can be +labeled. This allows branch instructions to exit try and `if_except` blocks. + +The `except_index` of the `except` and `if_except` instructions defines the +exception type to create/extract form. See [exception index +space](#exception-index-space) for further clarification of exception tags. + +## Changes to Modules document. + +This section describes change in the +[Modules document](https://github.com/WebAssembly/design/blob/master/Modules.md). + +### Exception index space + +The _exception index space_ indexes all imported and internally-defined +exceptions, assigning monotonically-increasing indices based on the order +defined in the import and exception sections. Thus, the index space starts at +zero with imported exceptions followed by internally-defined exceptions in +the [exception section](#exception-section). + +## Changes to the binary model + +This section describes changes in +the +[binary encoding design document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md). + + +### Data Types + +#### except_ref + +An exception reference pointing to an instance of an exception. The size +is fixed, but unknown in WebAssembly (the host defines the size in bytes). + +### Language Types + +| Opcode | Type constructor | +|--------|------------------| +| -0x41 | `except_ref` | + +#### value_type + +A `varint7` indicating a a `value type` is extended to include `except_ref` as +encoded above. + +#### Other Types + +##### except_type + +An exception is described by its exception type signature, which corresponds to +the data fields of the exception. + +| Field | Type | Description | +|-------|------|-------------| +| `count` | `varuint32` | The number of types in the signature | +| `type` | `value_type*` | The type of each element in the signature | + + +##### external_kind + +A single-byte unsigned integer indicating the kind of definition being imported +or defined: + +* `0` indicating a `Function` [import](Modules.md#imports) or [definition](Modules.md#function-and-code-sections) +* `1` indicating a `Table` [import](Modules.md#imports) or [definition](Modules.md#table-section) +* `2` indicating a `Memory` [import](Modules.md#imports) or [definition](Modules.md#linear-memory-section) +* `3` indicating a `Global` [import](Modules.md#imports) or [definition](Modules.md#global-section) +* `4` indicating an `Exception` [import](#import-section) or [definition](#exception-sectio) + +### Module structure + +#### High-level structure + +A new `exception` section is introduced and is named `exception`. If included, +it must appear between the `Export` and `Start` sections of the module. + + +##### Exception section + +The `exception` section is the named section 'exception'. The exception section +declares exception types using exception type signatures. + +| Field | Type | Description | +|-------|------|-------------| +| count | `varuint32` | count of the number of exceptions to follow | +| sig | `except_type*` | The type signature of the data fields for each exception | + + +##### Import section + +The import section is extended to include exception types by extending an +`import_entry` as follows: + +If the `kind` is `Exception`: + +| Field | Type | Description | +|-------|------|-------------| +| `sig` | `except_type` | the type signature of the exception | + +##### Export section + +The export section is extended to include exception types by extending an +`export_entry` as follows: + +If the `kind` is `Exception`, then the `index` is into the corresponding +exception in the [exception index space](#exception-index-space). + + +##### Name section + +The set of known values for `name_type` of a name section is extended as +follows: + +| Name Type | Code | Description | +| --------- | ---- | ----------- | +| [Function](#function-names) | `1` | Assigns names to functions | +| [Local](#local-names) | `2` | Assigns names to locals in functions | +| [Exception](#exception-names) | `3` | Assigns names to exception types | + +###### Exception names + +The exception names subsection is a `name_map` which assigns names to a subset +of the _exception_ indices from the exception section. (Used for both imports +and module-defined). + +### Control flow operators + +The control flow operators are extended to define try blocks, catch blocks, +throws, and rethrows as follows: + +| Name | Opcode | Immediates | Description | +| ---- | ---- | ---- | ---- | +| `try` | `0x06` | sig : `block_type` | begins a block which can handle thrown exceptions | +| `catch` | `0x07` | | begins the catch block of the try block | +| `throw` | `0x08` | |Throws the exception on top of the stack | +| `except` | `0x09` | tag : varuint32 | Creates an exception defined by the exception tag and pushes reference on stack | +| `if_except` | `0x0a` | sig : `block_type` , tag : `varuint32` | Begin exception data extraction if exception on stack was created using the corresponding exception tag | + +The *sig* fields of `block`, `if`, `try` and `if_except` operators are block +signatures which describe their use of the operand stack. From 3b7859eebd3ff4c82afbfd2d7c4d4c3380233af1 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Fri, 9 Feb 2018 14:11:40 -0800 Subject: [PATCH 019/302] Fix typos --- proposals/Layer-1.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/Layer-1.md b/proposals/Layer-1.md index e106d02fe8..92077e1ded 100644 --- a/proposals/Layer-1.md +++ b/proposals/Layer-1.md @@ -15,7 +15,7 @@ layers, and either: ## Overview Exception handling allows code to break control flow when an exception is -thrown. The exeception can be any exception known by the WebAssembly module, or +thrown. The execption can be any exception known by the WebAssembly module, or it may an unknown exception that was thrown by a called imported function. One of the problems with exception handling is that both WebAssembly and the @@ -109,7 +109,7 @@ Exception tags are used by: instance of the corresponding tagged exception class, and if true it pushes the corresponding values of the exception onto the stack. -### The exception refernce data type +### The exception reference data type Data types are extended to have a new `except_ref` type. The representation of an exception type is left to the host VM, but its size must be fixed. The actual From 42fd2c8bbf6d65d4ffe3dd21e6c87fade3594f97 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Fri, 9 Feb 2018 15:36:02 -0800 Subject: [PATCH 020/302] How many ways can you mispell exception? --- proposals/Layer-1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/Layer-1.md b/proposals/Layer-1.md index 92077e1ded..9495f7e7b8 100644 --- a/proposals/Layer-1.md +++ b/proposals/Layer-1.md @@ -15,7 +15,7 @@ layers, and either: ## Overview Exception handling allows code to break control flow when an exception is -thrown. The execption can be any exception known by the WebAssembly module, or +thrown. The exception can be any exception known by the WebAssembly module, or it may an unknown exception that was thrown by a called imported function. One of the problems with exception handling is that both WebAssembly and the From 03b95ed11f507559306226c3181f381cb604690d Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Mon, 12 Feb 2018 10:33:21 -0800 Subject: [PATCH 021/302] Fix some more typos (#40) --- proposals/Layer-1.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/proposals/Layer-1.md b/proposals/Layer-1.md index 9495f7e7b8..29c4b74ccf 100644 --- a/proposals/Layer-1.md +++ b/proposals/Layer-1.md @@ -205,7 +205,7 @@ end if_except block_type except_index Instruction* else - Instructions* + Instruction* end ``` @@ -240,11 +240,11 @@ This section describes change in the The following rules are added to *instructions*: ``` - try resulttype instructions* catch instructions* end | + try resulttype instruction* catch instruction* end | except except_index | throw | - if_except resulttype except_index then Instructions* end | - if_except resulttype except_index then Instructions* else Instructions* end + if_except resulttype except_index then instruction* end | + if_except resulttype except_index then instruction* else instruction* end ``` Like the `block`, `loop`, and `if` instructions, the `try` and `if_except` @@ -290,7 +290,7 @@ is fixed, but unknown in WebAssembly (the host defines the size in bytes). #### value_type -A `varint7` indicating a a `value type` is extended to include `except_ref` as +A `varint7` indicating a `value_type` is extended to include `except_ref` as encoded above. #### Other Types @@ -383,7 +383,7 @@ throws, and rethrows as follows: | `try` | `0x06` | sig : `block_type` | begins a block which can handle thrown exceptions | | `catch` | `0x07` | | begins the catch block of the try block | | `throw` | `0x08` | |Throws the exception on top of the stack | -| `except` | `0x09` | tag : varuint32 | Creates an exception defined by the exception tag and pushes reference on stack | +| `except` | `0x09` | tag : `varuint32` | Creates an exception defined by the exception tag and pushes reference on stack | | `if_except` | `0x0a` | sig : `block_type` , tag : `varuint32` | Begin exception data extraction if exception on stack was created using the corresponding exception tag | The *sig* fields of `block`, `if`, `try` and `if_except` operators are block From 9d2be9643c5a8c608f81d1fd19f188a6330abc0f Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Mon, 12 Feb 2018 11:33:54 -0800 Subject: [PATCH 022/302] Clarify the relationship between the original proposal and Layer 1. --- proposals/Exceptions.md | 8 ++++++++ proposals/Layer-1.md | 8 +++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index 60dcf3f933..1ab91ea849 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -1,3 +1,11 @@ +THIS DOCUMENT IS OBSOLETE! + +Please see The new [Layer 1 MVP Proposal] instead. + +[Layer 1 MVP Proposal]: https://github.com/WebAssembly/exception-handling/blob/master/proposals/Layer-1.md + +The original proposal is preserved here for reference. + # Exception handling There are four sections to this proposal diff --git a/proposals/Layer-1.md b/proposals/Layer-1.md index 29c4b74ccf..06af4ebe2f 100644 --- a/proposals/Layer-1.md +++ b/proposals/Layer-1.md @@ -7,11 +7,13 @@ layers, and either: 1. Improves readability by combining concepts in layer 1 into higher-level constructs, thereby reducing code size. - 2. Allow performance improvements in the VM. - 3. Introduce additional new functionality not available in layer 1. - + +This document supersedes the original [Exceptions Proposal]. + +[Exceptions Proposal]: https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md + ## Overview Exception handling allows code to break control flow when an exception is From cd67c6aa81a973fa58c38036b78f228fbc098c96 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Mon, 12 Feb 2018 12:37:15 -0800 Subject: [PATCH 023/302] Rename Layer 1 to Level 1 --- proposals/Exceptions.md | 4 ++-- proposals/{Layer-1.md => Level-1.md} | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) rename proposals/{Layer-1.md => Level-1.md} (98%) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index 1ab91ea849..d234b3cebd 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -1,8 +1,8 @@ THIS DOCUMENT IS OBSOLETE! -Please see The new [Layer 1 MVP Proposal] instead. +Please see The new [Level 1 MVP Proposal] instead. -[Layer 1 MVP Proposal]: https://github.com/WebAssembly/exception-handling/blob/master/proposals/Layer-1.md +[Level 1 MVP Proposal]: https://github.com/WebAssembly/exception-handling/blob/master/proposals/Level-1.md The original proposal is preserved here for reference. diff --git a/proposals/Layer-1.md b/proposals/Level-1.md similarity index 98% rename from proposals/Layer-1.md rename to proposals/Level-1.md index 06af4ebe2f..cc3276b771 100644 --- a/proposals/Layer-1.md +++ b/proposals/Level-1.md @@ -1,14 +1,14 @@ -# Layer 1 exception handling +# Level 1 exception handling -Layer 1 of exception handling is the MVP (minimal viable proposal) for +Level 1 of exception handling is the MVP (minimal viable proposal) for implementing exceptions in WebAssembly. As such, it doesn't include higher-level concepts and structures. These concept and structures are introduced in later -layers, and either: +levels, and either: -1. Improves readability by combining concepts in layer 1 into higher-level +1. Improves readability by combining concepts in Level 1 into higher-level constructs, thereby reducing code size. 2. Allow performance improvements in the VM. -3. Introduce additional new functionality not available in layer 1. +3. Introduce additional new functionality not available in Level 1. This document supersedes the original [Exceptions Proposal]. From 61fa726b222fdd3d9ec8164210ae84783fa29c5d Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Mon, 12 Feb 2018 12:34:20 -0800 Subject: [PATCH 024/302] Describe level approach and start describing Level 2 --- proposals/Level-1+N.md | 69 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 proposals/Level-1+N.md diff --git a/proposals/Level-1+N.md b/proposals/Level-1+N.md new file mode 100644 index 0000000000..fcae817512 --- /dev/null +++ b/proposals/Level-1+N.md @@ -0,0 +1,69 @@ +# Exception Handling Level 1+N Extensions + +While the Level 1 Proposal establishes the minimum viable product (MVP) for +exception handling, there are several extensions that would be nice to have for +various reasons. These include: +* More compact WebAssembly code. Compound instructions can capture common + sequences and save on code size. +* More efficient embedder implementation. Some changes to the baseline spec can + open up opportunities for embedders to generate better code. +* General completeness. The baseline proposal has some arbitrary limitations + that are only there to reduce implementation effort but do not have any + fundamental theoretical reasons. + +Many of these extensions are complementary and build upon each other. Thus a +layered approach works well, where sets of features that are logically related +can be added at once. + +This document captures several feature levels at a high level. The goal is not +to exhaustively specify them but to carve out the design space in sufficient +detail that we can ensure the Level 1 proposal is future proof with respect to +these. Each level will likely become its own WebAssembly proposal after the +initial exception handling support is accepted, but if there are strong use +cases and a low enough specification and implementation burden, these may be +included with the initial exception proposal. The goal is to make sure each set +of features can be discussed in terms of its own merits independent of the other +features. + +# Level 2 + +## Specific Catch + +The Level 1 proposal only supports `catch_all`, meaning a single catch clause +that runs for all exceptions. Some languages may only be interested in catching +certain exceptions. Specific catch allows programs to specify which exceptions +that will handle with a certain `try` block. This improves performance by not +running code that is not needed and, more importantly, opens up for efficient +implementation strategies for the embedder such as being able to go directly to +the catch clause for the given exception. + +This feature extends try blocks as follows: + +``` +try resulttype + instruction* +(catch exception_index + instruction* )* +(catch + instruction* )? +end +``` + +Note that the `catch exteption_index` and `catch` forms of the catch clause should be given different opcodes. + +### Alternate Form: Catch Lists + +In this version, a catch clause lists which exception indices it handles. An +empty list is equivalent to `catch_all`. An example is given below. + +``` +try resulttype + instruction* +catch exception_index* + instrunction* +end +``` + +One downside of this form is that it does not directly support running different +code for different exception types. This can still be accomplished, however, by +dyanmically inspecting the exception inside the catch block. From aa6e87eecd78e62a05c12291789c2acabf9a26b2 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Mon, 12 Feb 2018 13:58:23 -0800 Subject: [PATCH 025/302] Brief description of resumable exceptions --- proposals/Level-1+N.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/proposals/Level-1+N.md b/proposals/Level-1+N.md index fcae817512..7c0e6cab8a 100644 --- a/proposals/Level-1+N.md +++ b/proposals/Level-1+N.md @@ -25,6 +25,9 @@ included with the initial exception proposal. The goal is to make sure each set of features can be discussed in terms of its own merits independent of the other features. +Please note that everything in here should be considered fluid and subject to +change. + # Level 2 ## Specific Catch @@ -67,3 +70,34 @@ end One downside of this form is that it does not directly support running different code for different exception types. This can still be accomplished, however, by dyanmically inspecting the exception inside the catch block. + +# Level 3 + +## Resumable Exceptions + +This proposal allows exception handlers to return a value to the site where the +exception was thrown. Resumable exceptions enable or are equivalent to a number +of advanced control flow features such as generators, coroutines, delimited +continuations and effect handlers. + +In high level code, this would enable programs such as: + +``` +Exception FileNotFound: string -> string + +try { + filename = "foo.txt" + while(!(file = open(filename))) { + filename = throw FileNotFound(filename); + } +} catch (FileNotFound e) { + new_file_name = ask_user_for_filename(); + resume e(new_file_name) +} +``` + +The key changes are that exception types are now allowed to include return +values, `throw` can return a value (we might want to introduce a different +opcode for this version, such as `raise` or `throw_resumable`), and there is a +`resume` instruction that returns values back to where the exception was thrown +from. From 76fef9dbbbee495c840e92d6f66ef16888a0e01f Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Mon, 12 Feb 2018 17:01:02 -0800 Subject: [PATCH 026/302] Add an algebraic effect handler example --- proposals/Level-1+N.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/proposals/Level-1+N.md b/proposals/Level-1+N.md index 7c0e6cab8a..dab7b06bf8 100644 --- a/proposals/Level-1+N.md +++ b/proposals/Level-1+N.md @@ -101,3 +101,40 @@ values, `throw` can return a value (we might want to introduce a different opcode for this version, such as `raise` or `throw_resumable`), and there is a `resume` instruction that returns values back to where the exception was thrown from. + +Below are several examples showing how other control flow patterns can be +expressed in terms of resumable exceptions. + +### Example: Algebraic Effect Handlers + +Consider the following example, taken from http://www.eff-lang.org/try/: + +``` +handle + std#print "A"; + std#print "B"; + std#print "C"; + std#print "D" +with +| std#print msg k -> + std#print ("I see you tried to print " ^ msg ^ ". Okay, you may.\n"); + k () +``` + +This could be lowered to Wasm resumable exception pseudo-code like this: + +``` +Exception StdPrint: string -> () + +import function RealPrint: string -> () + +try: + throw StdPrint("A") + throw StdPrint("B") + throw StdPrint("C") + throw StdPrint("D") +catch e: StdPrint(msg): + RealPrint("I see you tried to print " + msg + ". Okay, you may.\n") + resume e() +end +``` From 7ece355dde7bb0b31489fbc8493a108670c07c49 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Mon, 12 Feb 2018 18:27:19 -0800 Subject: [PATCH 027/302] Add a coroutine example --- proposals/Level-1+N.md | 64 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/proposals/Level-1+N.md b/proposals/Level-1+N.md index dab7b06bf8..330ce41dcd 100644 --- a/proposals/Level-1+N.md +++ b/proposals/Level-1+N.md @@ -138,3 +138,67 @@ catch e: StdPrint(msg): resume e() end ``` + +### Example: Coroutines + +Consider the example below taken from https://en.wikipedia.org/wiki/Coroutine: + +``` +var q := new queue + +coroutine produce + loop + while q is not full + create some new items + add the items to q + yield to consume + +coroutine consume + loop + while q is not empty + remove some items from q + use the items + yield to produce +``` + +Using similar high level pseudo code, we can convert this as follows to use +resumable exceptions: + +``` +Exception yield: () -> () + +function produce(): + loop: + while q is not full: + create some new items + add the items to q + throw yield() + +function consume(): + loop: + while q is not empty: + remove some items from q + use the items + throw yield() + +function run(): + // Start the producer + c1 = try: + produce() + catch e: yield(): + e + end + + // Start the consumer + c2 = try: + consume() + catch e: yeild(): + e + end + + loop: + // Run the producer + c1 = resume c1(); + // Run the consumer + c2 = resume c2(); +``` From afccf3ab428cc40bd78c9487fa2cf53752e28ff4 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Tue, 13 Feb 2018 12:46:40 -0800 Subject: [PATCH 028/302] Feedback from @rossberg --- proposals/Level-1+N.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/proposals/Level-1+N.md b/proposals/Level-1+N.md index 330ce41dcd..335a0825aa 100644 --- a/proposals/Level-1+N.md +++ b/proposals/Level-1+N.md @@ -183,17 +183,17 @@ function consume(): function run(): // Start the producer - c1 = try: + try: produce() catch e: yield(): - e + c1 = e end // Start the consumer - c2 = try: + try: consume() - catch e: yeild(): - e + catch e: yield(): + c2 = e end loop: From 5af8f7fe32adfc73bfa80b7c0465744e0fe33b33 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Tue, 13 Feb 2018 12:56:17 -0800 Subject: [PATCH 029/302] Add a generators example --- proposals/Level-1+N.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/proposals/Level-1+N.md b/proposals/Level-1+N.md index 335a0825aa..1f0fb15b38 100644 --- a/proposals/Level-1+N.md +++ b/proposals/Level-1+N.md @@ -202,3 +202,37 @@ function run(): // Run the consumer c2 = resume c2(); ``` + +### Example: Generators + +Consider the following generator example in JavaScript: + +```javascript +function* simpleIterator() { + yield 1; + yield 2; + yield 3; +} + +for (let i of simpleIterator()) { + print(i); +} +``` + +In our WebAssembly pseudo code, this could become: + +``` +Exception yield: i32 -> () + +function simpleIterator(): + throw yield(1) + throw yield(2) + throw yield(3) + +function main(): + try: + simpleIterator() + catch e: yield(i): + print(i) + resume e() +``` From e92e28081ad2055adb4d9cc5e7a27b4e4bb560b6 Mon Sep 17 00:00:00 2001 From: Karl Schimpf Date: Wed, 14 Feb 2018 08:43:55 -0800 Subject: [PATCH 030/302] Combine throw and create --- proposals/Level-1.md | 56 ++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/proposals/Level-1.md b/proposals/Level-1.md index cc3276b771..9a719bd128 100644 --- a/proposals/Level-1.md +++ b/proposals/Level-1.md @@ -69,9 +69,8 @@ can't be stored into linear memory. The rationale for this is twofold: Hence, while an exception reference is a new first class type, this proposal disallows their usage in linear memory. -A WebAssembly exception is created by the `except` instruction. Once an -exception is created, you can throw it with the `throw` instruction. Thrown -exceptions are handled as follows: +A WebAssembly exception is created when you throw it with the `throw` +instruction. Thrown exceptions are handled as follows: 1. They can be caught by a catch block in an enclosing try block of a function body. The caught exception is pushed onto the stack. @@ -93,19 +92,19 @@ Each exception type has a `type signature`. The type signature defines the list of values associated with the exception. Within the module, exception types are identified by an index into the -[exception index space](#exception-index-space). This index is referred to as -the `exception tag`. The `tagged exception type` is the corresponding +[exception index space](#exception-index-space). This static index refers to the +corresponding runtime index that uniquely identifies the exception type, and is +called the `exception tag`. The `tagged exception type` is the corresponding exception type refered to by the exception tag. Exception types can be imported and exported by adding the appropriate entries to the import and export sections of the module. All imported/exported exception types must be named to reconcile exception tags between modules. -Exception tags are used by: +Exception indices are used by: -1. The `except` instruction which creates a WebAssembly instance of the - corresponding tagged exception type, and pushes a reference to it onto the - stack. +1. The `throw` instruction which creates a WebAssembly instance of the + corresponding tagged exception type, and then throws it. 2. The `if_except` instruction that queries an exception to see if it is an instance of the corresponding tagged exception class, and if true it pushes @@ -114,8 +113,7 @@ Exception tags are used by: ### The exception reference data type Data types are extended to have a new `except_ref` type. The representation of -an exception type is left to the host VM, but its size must be fixed. The actual -number of bytes it takes to represent any `except_ref` is left to the host VM. +an exception type is left to the host VM. ### Try and catch blocks @@ -143,19 +141,13 @@ block. In the initial implementation, try blocks may only yield 0 or 1 values. -### Exception creation +### Throwing an exception -A `except` instruction has a single immediate argument, an exception tag. The -corresponding tagged exception type is used to define the data fields of the -created exception. The values for the data fields must be on top of the operand -stack, and must correspond to the exception's type signature. These values are -popped off the stack and an instance of the exception is then created. A -reference to the created exception is then pushed onto the stack. - -### Throws - -The `throw` throws the exception on top of the stack. The exception is popped -off the top of the stack before throwing. +The `throw` instruction takes an exception index as an immediate argument. That +index is used to identify the tagged exception type to throw. The values to +throw (corresponding to the signature) are popped from the top of the stack, and +an exception is created. This includes attaching a stack track to the exception. +The newly created exception is then thrown. When an exception is thrown, the host VM searches for nearest enclosing try block body that execution is in. That try block is called the _catching_ try @@ -187,6 +179,13 @@ the caught exception. Note that a caught exception can be rethrown using the `throw` instruction. +### Rethrowing an exception + +The `rethrow` instruction takes exception associated with the `except_ref` on +top of the stack, and rethrows the exception. A rethrow has the same effect as a +throw, other than an exception is not created. Rather, the referenced exception +on top of the stack is popped and then thrown. + ### Exception data extraction The `if_except block` defines a conditional query of the exception on top of the @@ -244,7 +243,8 @@ The following rules are added to *instructions*: ``` try resulttype instruction* catch instruction* end | except except_index | - throw | + throw except_index | + rethrow | if_except resulttype except_index then instruction* end | if_except resulttype except_index then instruction* else instruction* end ``` @@ -253,7 +253,7 @@ Like the `block`, `loop`, and `if` instructions, the `try` and `if_except` instructions are *structured* control flow instructions, and can be labeled. This allows branch instructions to exit try and `if_except` blocks. -The `except_index` of the `except` and `if_except` instructions defines the +The `except_index` of the `throw` and `if_except` instructions defines the exception type to create/extract form. See [exception index space](#exception-index-space) for further clarification of exception tags. @@ -384,9 +384,9 @@ throws, and rethrows as follows: | ---- | ---- | ---- | ---- | | `try` | `0x06` | sig : `block_type` | begins a block which can handle thrown exceptions | | `catch` | `0x07` | | begins the catch block of the try block | -| `throw` | `0x08` | |Throws the exception on top of the stack | -| `except` | `0x09` | tag : `varuint32` | Creates an exception defined by the exception tag and pushes reference on stack | -| `if_except` | `0x0a` | sig : `block_type` , tag : `varuint32` | Begin exception data extraction if exception on stack was created using the corresponding exception tag | +| `throw` | `0x08` | index : `varint32` | Creates an exception defined by the exception `index`and then throws it | +| `rethrow` | `0x09` | | Pops the `except_ref` on top of the stack and throws it | +| `if_except` | `0x0a` | sig : `block_type` , index : `varuint32` | Begin exception data extraction if exception on stack was created using the corresponding exception `index` | The *sig* fields of `block`, `if`, `try` and `if_except` operators are block signatures which describe their use of the operand stack. From f19e662ae718db74422767c1ecc6dec3f2a4146e Mon Sep 17 00:00:00 2001 From: Karl Schimpf Date: Wed, 14 Feb 2018 09:46:39 -0800 Subject: [PATCH 031/302] Save state --- proposals/Level-1.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/proposals/Level-1.md b/proposals/Level-1.md index cc3276b771..4368d94408 100644 --- a/proposals/Level-1.md +++ b/proposals/Level-1.md @@ -81,6 +81,49 @@ exceptions are handled as follows: 1. If the call stack is exhausted without any enclosing try blocks, the host VM defines how to handle the uncaught exception. + +### Event handling + +This proposal focusses on adding exception handling, but tries to be more +general in its specification such that more general kinds of event handling can +be added to WebAssembly in the future without having to redo exception handling. + +An event handler allows one to process an event generated by a block of +code. Events yield the current execution and look for an enclosing try block to +handle the event. If found, the corresponding event handler is run. The event +handler can optionally resume by sending values back to the yielded instruction, +allowing the originating code to resume. + +Exceptions are a special case of an event in that they never resume. Similarly, +a throw instruction is the yielding event of an exception. The catch block +associated with a try block defines how to handle the throw. + +An `event` (such as an exception) is an internal construct in WebAssembly that +is maintained by the host. WebAssembly events are defined by a new `handler` +section` of a WebAssembly module. The handler section is a list of event types +that are defined by the module. + +Each `event type` has a `event specifier` and a `type signature`. Depending on +the value of the event specifier, additional values may be specified in the +event type. + +For level 1, the only event specifier is the constant 0 which denotes that the +event is an exception. Future extensions my add additional event specifiers. + +The type signature of an event type is an index to the corresponding function +signature defined in the `type` section. The parameter of the function signature +defines the list of values associated with the thrown exception. The return +value(s) of the signature defines what is passed back to the throw so that +execution may resume. + +Note: Resumable events may not use the `throw` instruction, and may use new (yet +to be defined) `yeild` instructions for which value(s) may be passed back to it +and allow it to resume with the instruction following the yeild instruction. + +Within a module, event types are identified by an `event index` to the [event +index space](#event-index-space). This (module specific) index identifies the +corresponding identify runtime `event tag` that uniquely identifies the +corresponding event type. ### Exceptions From d29e948c00ad13be142ce8fa08d15246d3deb8a9 Mon Sep 17 00:00:00 2001 From: Karl Schimpf Date: Wed, 14 Feb 2018 11:04:19 -0800 Subject: [PATCH 032/302] Clean up nits of rossberg --- proposals/Level-1.md | 135 +++++++++++++++++++++++++------------------ 1 file changed, 79 insertions(+), 56 deletions(-) diff --git a/proposals/Level-1.md b/proposals/Level-1.md index 9a719bd128..d1918775d9 100644 --- a/proposals/Level-1.md +++ b/proposals/Level-1.md @@ -86,34 +86,41 @@ instruction. Thrown exceptions are handled as follows: An `exception` is an internal construct in WebAssembly that is maintained by the host. WebAssembly exceptions (as opposed to host exceptions) are defined by a new `exception section` of a WebAssembly module. The exception section is a list -of exception types, from which exceptions can be created. +of exception definitions, from which exceptions can be created. -Each exception type has a `type signature`. The type signature defines the list -of values associated with the exception. +Each exception definition describe the structure of corresponding exception +values that can be generated from it. Exception definitions may also appear in +the import section of a module. -Within the module, exception types are identified by an index into the +Each exception definition has a `type signature`. The type signature defines the +list of values associated with corresponding thrown exception values. + +Within the module, exception definitions are identified by an index into the [exception index space](#exception-index-space). This static index refers to the -corresponding runtime index that uniquely identifies the exception type, and is -called the `exception tag`. The `tagged exception type` is the corresponding -exception type refered to by the exception tag. +corresponding runtime tag that uniquely identifies exception values created +using the exception definition, and is called the `exception tag`. + +Each exception definition within a module (i.e. in the exception and import +section) are associated with unique exception tags. -Exception types can be imported and exported by adding the appropriate entries -to the import and export sections of the module. All imported/exported exception -types must be named to reconcile exception tags between modules. +Exception tags can also be exported by adding the appropriate descriptors in the +export section of the module. All imported/exported indices must be named to +reconcile the corresponding exception tag referenced by exception indices +between modules. Exception indices are used by: -1. The `throw` instruction which creates a WebAssembly instance of the - corresponding tagged exception type, and then throws it. +1. The `throw` instruction which creates a WebAssembly exception value + with the corresponding exception tag, and then throws it. -2. The `if_except` instruction that queries an exception to see if it is an - instance of the corresponding tagged exception class, and if true it pushes - the corresponding values of the exception onto the stack. +2. The `if_except` instruction that queries an exception value to see if the + exception tag corresponding to the module's exception index. If true it + pushes the corresponding values of the exception onto the stack. ### The exception reference data type Data types are extended to have a new `except_ref` type. The representation of -an exception type is left to the host VM. +an exception value is left to the host VM. ### Try and catch blocks @@ -144,13 +151,16 @@ In the initial implementation, try blocks may only yield 0 or 1 values. ### Throwing an exception The `throw` instruction takes an exception index as an immediate argument. That -index is used to identify the tagged exception type to throw. The values to -throw (corresponding to the signature) are popped from the top of the stack, and -an exception is created. This includes attaching a stack track to the exception. -The newly created exception is then thrown. +index is used to identify the exception tag to use to create and throw the +corresponding exception value. + +The values on top of the stack must correspond to the the type signature +associated with the exception index. These values are popped of the stack and +are used (along with the corresponding exception tag) to create the +corresponding exception value. That exception value is then thrown. -When an exception is thrown, the host VM searches for nearest enclosing try -block body that execution is in. That try block is called the _catching_ try +When an exception value is thrown, the host VM searches for nearest enclosing +try block body that execution is in. That try block is called the _catching_ try block. If the throw appears within the body of a try block, it is the catching try @@ -166,9 +176,10 @@ A throw inside the body of a catch block is never caught by the corresponding try block of the catch block, since instructions in the body of the catch block are not in the body of the try block. -Once a catching try block is found for the throw, the operand stack is popped back -to the size the operand stack had when the try block was entered, and then -the caught exception is pushed onto the stack. +Once a catching try block is found for the thrown exception value, the operand +stack is popped back to the size the operand stack had when the try block was +entered, and then the values of the caught exception value is pushed onto the +stack. If control is transferred to the body of a catch block, and the last instruction in the body is executed, control then exits the try block. @@ -177,23 +188,24 @@ If the selected catch block does not throw an exception, it must yield the value(s) expected by the corresponding catching try block. This includes popping the caught exception. -Note that a caught exception can be rethrown using the `throw` instruction. +Note that a caught exception value can be rethrown using the `throw` +instruction. ### Rethrowing an exception -The `rethrow` instruction takes exception associated with the `except_ref` on -top of the stack, and rethrows the exception. A rethrow has the same effect as a -throw, other than an exception is not created. Rather, the referenced exception -on top of the stack is popped and then thrown. +The `rethrow` instruction takes the exception value associated with the +`except_ref` on top of the stack, and rethrows the exception. A rethrow has the +same effect as a throw, other than an exception is not created. Rather, the +referenced exception value on top of the stack is popped and then thrown. ### Exception data extraction -The `if_except block` defines a conditional query of the exception on top of the -stack. The exception is not popped when queried. The if_except block has two -subblocks, the `then` and `else` subblocks, like that of an `if` block. The then -block is a sequence of instructions following the `if_except` instruction. The -else block is optional, and if it appears, it begins with the `else` -instruction. The scope of the if_except block is from the `if_except` +The `if_except block` defines a conditional query of the exception value on top +of the stack. The exception value is not popped when queried. The if_except +block has two subblocks, the `then` and `else` subblocks, like that of an `if` +block. The then block is a sequence of instructions following the `if_except` +instruction. The else block is optional, and if it appears, it begins with the +`else` instruction. The scope of the if_except block is from the `if_except` instruction to the corresponding `end` instruction. That is, the forms of an if_except block is: @@ -210,13 +222,12 @@ else end ``` -The conditional query of an exception succeeds when the exception on the top of -the stack is an instance of the corresponding tagged exception type (defined by -`except_index`). +The conditional query of an exception succeeds when the exception value on the +top of the stack has the corresponding exception tag (defined by `except_index`). -If the query succeeds, the data values (associated with the type signature of -the exception class) are extracted and pushed onto the stack, and control -transfers to the instructions in the then block. +If the query succeeds, the values (associated with the exception value) are +extracted and pushed onto the stack, and control transfers to the instructions +in the then block. If the query fails, it either enters the else block, or transfer control to the end of the if_except block if there is no else block. @@ -254,8 +265,9 @@ instructions are *structured* control flow instructions, and can be labeled. This allows branch instructions to exit try and `if_except` blocks. The `except_index` of the `throw` and `if_except` instructions defines the -exception type to create/extract form. See [exception index -space](#exception-index-space) for further clarification of exception tags. +exception value (and hence, exception tag) to create/extract form. See +[exception index space](#exception-index-space) for further clarification of +exception tags. ## Changes to Modules document. @@ -270,6 +282,15 @@ defined in the import and exception sections. Thus, the index space starts at zero with imported exceptions followed by internally-defined exceptions in the [exception section](#exception-section). +The exception index space defines the (module) static version of runtine +exception tags. For exception indicies that are not imported/exported, the +corresponding exception tag is guaranteed to be unique over all loaded +modules. + +For exception indices imported/exported, unique exception tags are created for +each unique name imported/exported, and are aliased to the corresponding +exception index defined in each module. + ## Changes to the binary model This section describes changes in @@ -281,7 +302,7 @@ the #### except_ref -An exception reference pointing to an instance of an exception. The size +An exception reference points to an exception value. The size is fixed, but unknown in WebAssembly (the host defines the size in bytes). ### Language Types @@ -299,14 +320,17 @@ encoded above. ##### except_type -An exception is described by its exception type signature, which corresponds to -the data fields of the exception. +Each exception definition (defining an exception tag) has a type signature, +which corresponds to the data fields of the exception. | Field | Type | Description | |-------|------|-------------| | `count` | `varuint32` | The number of types in the signature | | `type` | `value_type*` | The type of each element in the signature | +Note: An `except_type` is not actually a type, just an exception definition that +corresponds to an exception tag. It is listed under `Other types` for +simplicity. ##### external_kind @@ -317,30 +341,29 @@ or defined: * `1` indicating a `Table` [import](Modules.md#imports) or [definition](Modules.md#table-section) * `2` indicating a `Memory` [import](Modules.md#imports) or [definition](Modules.md#linear-memory-section) * `3` indicating a `Global` [import](Modules.md#imports) or [definition](Modules.md#global-section) -* `4` indicating an `Exception` [import](#import-section) or [definition](#exception-sectio) +* `4` indicating an `Exception` [import](#import-section) or [definition](#exception-section) ### Module structure #### High-level structure A new `exception` section is introduced and is named `exception`. If included, -it must appear between the `Export` and `Start` sections of the module. - +it must appear after immediately after the global section. ##### Exception section The `exception` section is the named section 'exception'. The exception section -declares exception types using exception type signatures. +declares a list of exception definitions, defining corresponding exception tags. | Field | Type | Description | |-------|------|-------------| | count | `varuint32` | count of the number of exceptions to follow | -| sig | `except_type*` | The type signature of the data fields for each exception | +| sig | `except_type*` | The type signature of the data fields for the tagged exception value | ##### Import section -The import section is extended to include exception types by extending an +The import section is extended to include exception definitions by extending an `import_entry` as follows: If the `kind` is `Exception`: @@ -351,11 +374,11 @@ If the `kind` is `Exception`: ##### Export section -The export section is extended to include exception types by extending an -`export_entry` as follows: +The export section is extended to reference exception definitions by by +extending an `export_entry` as follows: If the `kind` is `Exception`, then the `index` is into the corresponding -exception in the [exception index space](#exception-index-space). +exception index in the [exception index space](#exception-index-space). ##### Name section From 751ba715f90012617cb1891dfb1ebeaeb94e4329 Mon Sep 17 00:00:00 2001 From: Karl Schimpf Date: Wed, 14 Feb 2018 11:25:57 -0800 Subject: [PATCH 033/302] Fix nits from rossberg --- proposals/Level-1.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/proposals/Level-1.md b/proposals/Level-1.md index d1918775d9..14e947e5d0 100644 --- a/proposals/Level-1.md +++ b/proposals/Level-1.md @@ -188,7 +188,7 @@ If the selected catch block does not throw an exception, it must yield the value(s) expected by the corresponding catching try block. This includes popping the caught exception. -Note that a caught exception value can be rethrown using the `throw` +Note that a caught exception value can be rethrown using the `rethrow` instruction. ### Rethrowing an exception @@ -328,10 +328,6 @@ which corresponds to the data fields of the exception. | `count` | `varuint32` | The number of types in the signature | | `type` | `value_type*` | The type of each element in the signature | -Note: An `except_type` is not actually a type, just an exception definition that -corresponds to an exception tag. It is listed under `Other types` for -simplicity. - ##### external_kind A single-byte unsigned integer indicating the kind of definition being imported From b7fce8e78dfa3601fb726f06b75b5c77c925dd04 Mon Sep 17 00:00:00 2001 From: Karl Schimpf Date: Mon, 26 Feb 2018 11:23:11 -0800 Subject: [PATCH 034/302] Define events --- proposals/Level-1.md | 362 ++++++++++++++++++++++--------------------- 1 file changed, 182 insertions(+), 180 deletions(-) diff --git a/proposals/Level-1.md b/proposals/Level-1.md index 7d6720e692..4ed625b4f2 100644 --- a/proposals/Level-1.md +++ b/proposals/Level-1.md @@ -21,49 +21,49 @@ thrown. The exception can be any exception known by the WebAssembly module, or it may an unknown exception that was thrown by a called imported function. One of the problems with exception handling is that both WebAssembly and the -host VM probably have different notions of what exceptions are, but both must be -aware of the other. +embedder probably have different notions of what exceptions are, but both must +be aware of the other. -It is difficult to define exceptions in WebAssembly because (in general) -it doesn't have knowledge of the host VM. Further, adding such knowledge to -WebAssembly would limit the ability for other host VMs to support WebAssembly +It is difficult to define exceptions in WebAssembly because (in general) it +doesn't have knowledge of the embedder. Further, adding such knowledge to +WebAssembly would limit the ability for other embedders to support WebAssembly exceptions. One issue is that both sides need to know if an exception was thrown by the other, because cleanup may need to be performed. -Another problem is that WebAssembly doesn't have direct access to the host VM's -memory. As a result, WebAssembly defers the handling of exceptions to the host -VM. +Another problem is that WebAssembly doesn't have direct access to the embedder's +memory. As a result, WebAssembly defers the handling of exceptions to the +embedder. To access exceptions, WebAssembly provides instructions to check if the exception is one that WebAssembly understands. If so, the data of the -WebAssembly exceptions's data is extracted and copied onto the stack, allowing +WebAssembly exception data is extracted and copied onto the stack, allowing succeeding instructions to process the data. -Lastly, exception lifetimes must be maintained by the host VM, so that it can -collect and reuse the memory used by exceptions. This implies that the host must -know where exceptions are stored, so that it can determine when an exception can -be garbage collected. +Lastly, exception lifetimes must be maintained by the embedder, so that it can +collect and reuse the memory used by exceptions. This implies that the embedder +must know where exceptions are stored, so that it can determine when an +exception can be garbage collected. -This also implies that the host VM must provide a garbage collector for -exceptions. For host VMs that have garbage collection (such as JavaScript), +This also implies that the embedder must provide a garbage collector for +exceptions. For embedders that have garbage collection (such as JavaScript), this is not a problem. -However, not all host VMs may have a garbage collector. For this reason, -WebAssembly exceptions are designed to allow the use of reference counters to -perform the the garbage collection in the host VM. +However, not all embedders may have a garbage collector. For this reason, +WebAssembly exceptions are designed to allow the use of reference counters (to +exceptions) to perform the the garbage collection in the embedder. -To do this, WebAssembly exceptions are immutable once created, to avoid cyclic -data structures that can't be garbage collected. It also means that exceptions -can't be stored into linear memory. The rationale for this is twofold: +To do this, WebAssembly exceptions are immutable once created. This avoids +cyclic data structures that can't be garbage collected. It also means that +exceptions can't be stored into WebAssembly's linear memory. The rationale for +this is twofold: -* For security. Loads - and stores do not guarantee that the data read was of the same type as - stored. This allows spoofing of exception references that may allow a - WebAssembly module to access data it should not know in the host VM. +* For security. Loads and stores do not guarantee that the data read was of the + same type as stored. This allows spoofing of exception references that may + allow a WebAssembly module to access data it should not know in the embedder. -* The host VM does not know the layout of data in linear memory, so it can't +* The embedder does not know the layout of data in linear memory, so it can't find places where exception references are stored. Hence, while an exception reference is a new first class type, this proposal @@ -78,92 +78,94 @@ instruction. Thrown exceptions are handled as follows: 1. Throws not caught within a function body continue up the call stack, popping call frames, until an enclosing try block is found. -1. If the call stack is exhausted without any enclosing try blocks, the host VM +1. If the call stack is exhausted without any enclosing try blocks, embedder defines how to handle the uncaught exception. ### Event handling This proposal focusses on adding exception handling, but tries to be more -general in its specification such that more general kinds of event handling can -be added to WebAssembly in the future without having to redo exception handling. +general in its specification. This allows future generalizations to WebAssembly +without having to redo exception handling. -An event handler allows one to process an event generated by a block of -code. Events yield the current execution and look for an enclosing try block to -handle the event. If found, the corresponding event handler is run. The event -handler can optionally resume by sending values back to the yielded instruction, -allowing the originating code to resume. +Events are generated by event yielding instructions. They yeild to an +appropriate event handler. The event handler is then run. That event handler +can either resume control at the point of the event handler, or optionally +resume by sending values back to the yielding instruction allow the +originating code to resume. Exceptions are a special case of an event in that they never resume. Similarly, -a throw instruction is the yielding event of an exception. The catch block -associated with a try block defines how to handle the throw. +a throw instruction is the yielding instruction of an exception, and the +corresponding catching block is the event handler of the exception. -An `event` (such as an exception) is an internal construct in WebAssembly that -is maintained by the host. WebAssembly events are defined by a new `handler` -section` of a WebAssembly module. The handler section is a list of event types -that are defined by the module. +An `event` is an internal construct in WebAssembly that is maintained by the +embedder. WebAssembly events are defined by a new `event section` of a +WebAssembly module. -Each `event type` has a `event specifier` and a `type signature`. Depending on +The event section defines a list of event types that may be handled by the +module. Each `event type` has (at a minimum) an `event specifier` and a `type +signature`. The event specifier defines the kind of event while the type +signature defines the list of values associated with the event. Depending on the value of the event specifier, additional values may be specified in the event type. -For level 1, the only event specifier is the constant 0 which denotes that the -event is an exception. Future extensions my add additional event specifiers. +For level 1, the only event specifier is the constant 0, and denotes that the +event is an `exception`. It has no additional values specified (other than the +type signature). Future extensions my add additional event specifiers, such as +resumable events. -The type signature of an event type is an index to the corresponding function -signature defined in the `type` section. The parameter of the function signature -defines the list of values associated with the thrown exception. The return -value(s) of the signature defines what is passed back to the throw so that -execution may resume. +The `type signature` of an event type is an index into the `type` section. The +type signature is defined by a function type. The parameter list of the type +signature defines the list of values returned to the corresponding enclosing +catch. The result type defines the list of values to be used when resuming on an +event. For exceptions, that can't resume, the result type must always be type +'void'. -Note: Resumable events may not use the `throw` instruction, and may use new (yet -to be defined) `yeild` instructions for which value(s) may be passed back to it -and allow it to resume with the instruction following the yeild instruction. +Note: Resumable events may not use the `throw` instruction. Rather, they may use +a new (yet to be defined) `yeild` instruction that passes value(s) to its +enclosing contexts. Such an instruction would allow the calling context to +return values back, and resume with the instruction following the yeild +instruction, based on the values returned. Within a module, event types are identified by an `event index` to the [event -index space](#event-index-space). This (module specific) index identifies the -corresponding identify runtime `event tag` that uniquely identifies the -corresponding event type. +index space](#event-index-space). Each event index refers to a corresponding +runtime tag that uniquely identifies the corresponding event to be handled. The +corresponding runtime tag is called an `event tag`. -### Exceptions - -An `exception` is an internal construct in WebAssembly that is maintained by the -host. WebAssembly exceptions (as opposed to host exceptions) are defined by a -new `exception section` of a WebAssembly module. The exception section is a list -of exception definitions, from which exceptions can be created. +Event types are numbered numerically, starting with the import section, and then +followed by event types in the event section. Each event type within a module +are associated with unique event tags. -Each exception definition describe the structure of corresponding exception -values that can be generated from it. Exception definitions may also appear in -the import section of a module. +Event types can also be exported by adding appropriate descriptors in the export +section of the module. Each imported/exported event index must be named to +reconcile the corresponding (runtime) event tag. -Each exception definition has a `type signature`. The type signature defines the -list of values associated with corresponding thrown exception values. - -Within the module, exception definitions are identified by an index into the -[exception index space](#exception-index-space). This static index refers to the -corresponding runtime tag that uniquely identifies exception values created -using the exception definition, and is called the `exception tag`. +### Exceptions -Each exception definition within a module (i.e. in the exception and import -section) are associated with unique exception tags. +An `exception` is a WebAssembly event that can be thrown and caught. That is, +an `exception type` is an event type whose event specifier is 0. The `type +signature` of the exception is the corresponding type signature of the event +type. That is, the parameter list of the type signature defines the list of +values associated with the exception, and the result type must be type `void`. -Exception tags can also be exported by adding the appropriate descriptors in the -export section of the module. All imported/exported indices must be named to -reconcile the corresponding exception tag referenced by exception indices -between modules. +Exceptions are identified by the by the corresponding event index, and is called +an `exception index`. The corresponding (runtime) event tag is called the +`exception tag`. Like all event types, each exception type within a module +(i.e. in the event and import sections) are associated with unique exception +tags. Exception indices are used by: -1. The `throw` instruction which creates a WebAssembly exception value - with the corresponding exception tag, and then throws it. +1. The `throw` instruction which creates a WebAssembly exception with the + corresponding exception tag, and then throws it. -2. The `if_except` instruction that queries an exception value to see if the - exception tag corresponding to the module's exception index. If true it - pushes the corresponding values of the exception onto the stack. +2. The `if_except` instruction that queries an exception to see if the exception + tag corresponding to the module's exception index. If true it pushes the + corresponding values of the exception onto the stack. ### The exception reference data type -Data types are extended to have a new `except_ref` type. The representation of -an exception value is left to the host VM. +Data types are extended to have a new `except_ref` type. The representation is +left to the embedder. ### Try and catch blocks @@ -182,7 +184,8 @@ end ``` A try block ends with a `catch block` that is defined by the list of -instructions after the `catch` instruction. +instructions after the `catch` instruction. The catch block is the event handler +for all exceptions thrown in the try block. Try blocks, like control-flow blocks, have a _block type_. The block type of a try block defines the values yielded by the evaluation the try block when either @@ -195,15 +198,16 @@ In the initial implementation, try blocks may only yield 0 or 1 values. The `throw` instruction takes an exception index as an immediate argument. That index is used to identify the exception tag to use to create and throw the -corresponding exception value. +corresponding exception. The values on top of the stack must correspond to the the type signature associated with the exception index. These values are popped of the stack and are used (along with the corresponding exception tag) to create the -corresponding exception value. That exception value is then thrown. +corresponding exception value. Along with the values, a stack trace is also +associated with the exception. That exception is then thrown. -When an exception value is thrown, the host VM searches for nearest enclosing -try block body that execution is in. That try block is called the _catching_ try +When an exception is thrown, the embedder searches for nearest enclosing try +block body that execution is in. That try block is called the _catching_ try block. If the throw appears within the body of a try block, it is the catching try @@ -212,52 +216,47 @@ block. If a throw occurs within a function body, and it doesn't appear inside the body of a try block, the throw continues up the call stack until it is in the body of an an enclosing try block, or the call stack is flushed. If the call stack is -flushed, the host VM defines how to handle uncaught exceptions. Otherwise, the +flushed, the embeddder defines how to handle uncaught exceptions. Otherwise, the found enclosing try block is the catching try block. A throw inside the body of a catch block is never caught by the corresponding try block of the catch block, since instructions in the body of the catch block are not in the body of the try block. -Once a catching try block is found for the thrown exception value, the operand -stack is popped back to the size the operand stack had when the try block was -entered, and then the values of the caught exception value is pushed onto the -stack. +Once a catching try block is found for the thrown exception, the operand stack +is popped back to the size the operand stack had when the try block was entered, +and then an except_ref (for the exception) is pushed back onto the stack. If control is transferred to the body of a catch block, and the last instruction in the body is executed, control then exits the try block. If the selected catch block does not throw an exception, it must yield the value(s) expected by the corresponding catching try block. This includes popping -the caught exception. +the caught except_ref. -Note that a caught exception value can be rethrown using the `rethrow` -instruction. +Note that a caught exception except_ref value can be rethrown using the +`rethrow` instruction. ### Rethrowing an exception -The `rethrow` instruction takes the exception value associated with the -`except_ref` on top of the stack, and rethrows the exception. A rethrow has the -same effect as a throw, other than an exception is not created. Rather, the -referenced exception value on top of the stack is popped and then thrown. +The `rethrow` instruction takes the exception associated with the `except_ref` +on top of the stack, and rethrows that exception. A rethrow has the same effect +as a throw, other than an exception is not created. Rather, the referenced +exception on top of the stack is popped and then thrown. ### Exception data extraction -The `if_except block` defines a conditional query of the exception value on top -of the stack. The exception value is not popped when queried. The if_except -block has two subblocks, the `then` and `else` subblocks, like that of an `if` -block. The then block is a sequence of instructions following the `if_except` -instruction. The else block is optional, and if it appears, it begins with the -`else` instruction. The scope of the if_except block is from the `if_except` -instruction to the corresponding `end` instruction. +The `if_except block` defines a conditional query of the exception in the +except_ref on top of the stack. The except_ref is popped when queried. The +if_except block has two subblocks, the `then` and `else` subblocks, like that of +an `if` block. The then block is a sequence of instructions following the +`if_except` instruction. The else block begins with the `else` instruction. The +scope of the if_except block is from the `if_except` instruction to the +corresponding `end` instruction. That is, the forms of an if_except block is: ``` -if_except block_type except_index - Instruction* -end - if_except block_type except_index Instruction* else @@ -265,25 +264,19 @@ else end ``` -The conditional query of an exception succeeds when the exception value on the -top of the stack has the corresponding exception tag (defined by `except_index`). +The conditional query of an exception succeeds when the exception in the +except_ref on the top of the stack has the corresponding exception tag (defined +by `except_index`). After the query, the except_ref is popped from the stack. If the query succeeds, the values (associated with the exception value) are extracted and pushed onto the stack, and control transfers to the instructions -in the then block. +in the then block. If the query fails, control is transfertd to the else block. -If the query fails, it either enters the else block, or transfer control to the -end of the if_except block if there is no else block. +### Stack traces -### Debugging - -Earlier discussion implied that when an exception is thrown, the runtime will -pop the operand stack across function calls until a corresponding, enclosing try -block is found. The implementation may actually not do this. Rather, it may -first search up the call stack to see if there is an enclosing try. If none are -found, it could terminate the thread at the point of the throw. This would -allow better debugging capability, since the corresponding call stack is still -there to query. +When an exception is thrown, conceptually a runtime stack is associated with the +exception. However, WebAssembly does not have (direct) access to the stack +trace. Hence, it is left to the embedder to maintain and use at it sees fit. ## Changes to the text format. @@ -299,7 +292,6 @@ The following rules are added to *instructions*: except except_index | throw except_index | rethrow | - if_except resulttype except_index then instruction* end | if_except resulttype except_index then instruction* else instruction* end ``` @@ -308,51 +300,49 @@ instructions are *structured* control flow instructions, and can be labeled. This allows branch instructions to exit try and `if_except` blocks. The `except_index` of the `throw` and `if_except` instructions defines the -exception value (and hence, exception tag) to create/extract form. See -[exception index space](#exception-index-space) for further clarification of -exception tags. +exception type (and hence, exception tag) to create/extract form. See [event +index space](#event-index-space) for further clarification of exception +tags. ## Changes to Modules document. This section describes change in the [Modules document](https://github.com/WebAssembly/design/blob/master/Modules.md). -### Exception index space +### Event index space -The _exception index space_ indexes all imported and internally-defined -exceptions, assigning monotonically-increasing indices based on the order -defined in the import and exception sections. Thus, the index space starts at -zero with imported exceptions followed by internally-defined exceptions in -the [exception section](#exception-section). +The `event index space` indexes all imported and internally-defined events, +assigning monotonically-increasing indices based on the order defined in the +import and event sections. Thus, the index space starts at zero with imported +events followed by internally-defined events in the [event +section](#event-section). -The exception index space defines the (module) static version of runtine -exception tags. For exception indicies that are not imported/exported, the -corresponding exception tag is guaranteed to be unique over all loaded +The event index space defines the (module) static version of runtine event +tags. These (runtime) event tags are guaranteed to be unique over all loaded modules. -For exception indices imported/exported, unique exception tags are created for +For event indices imported/exported, unique event tags are created for each unique name imported/exported, and are aliased to the corresponding -exception index defined in each module. +event index defined in each module. ## Changes to the binary model -This section describes changes in -the -[binary encoding design document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md). +This section describes changes in the [binary encoding design +document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md). ### Data Types #### except_ref -An exception reference points to an exception value. The size -is fixed, but unknown in WebAssembly (the host defines the size in bytes). +An exception reference points to an exception. The size is fixed, but unknown in +WebAssembly. ### Language Types | Opcode | Type constructor | |--------|------------------| -| -0x41 | `except_ref` | +| -0x0x5 | `except_ref` | #### value_type @@ -361,15 +351,28 @@ encoded above. #### Other Types -##### except_type +##### event_type + +An event specifier specifies the kind of event an event type represents. Currently, +the only value event specifier is: + +| Name | Value | +|-----------|-------| +| exception | 0 | + -Each exception definition (defining an exception tag) has a type signature, -which corresponds to the data fields of the exception. +Each event type (defining an event tag) has (at a minimum) an event specifier +and a type signature. Each event type begins with the fields -| Field | Type | Description | -|-------|------|-------------| -| `count` | `varuint32` | The number of types in the signature | -| `type` | `value_type*` | The type of each element in the signature | +| Field | Type | Description | +|-------------|-------------|------------------------------------------------| +| `specifier` | `varuint32` | The kind of event. | +| `type` | `varuint32` | Index to the type defining its type signature. | + + +Followed by (based on specifier): + +`exception`: No additional fields. ##### external_kind @@ -380,62 +383,61 @@ or defined: * `1` indicating a `Table` [import](Modules.md#imports) or [definition](Modules.md#table-section) * `2` indicating a `Memory` [import](Modules.md#imports) or [definition](Modules.md#linear-memory-section) * `3` indicating a `Global` [import](Modules.md#imports) or [definition](Modules.md#global-section) -* `4` indicating an `Exception` [import](#import-section) or [definition](#exception-section) +* `4` indicating an `Event` [import](#import-section) or [definition](#event-section) ### Module structure #### High-level structure -A new `exception` section is introduced and is named `exception`. If included, +A new event section is introduced and is named `event`. If included, it must appear after immediately after the global section. -##### Exception section +##### Event section -The `exception` section is the named section 'exception'. The exception section -declares a list of exception definitions, defining corresponding exception tags. +The `event` section is the named section 'event'. The event section declares a +list of event types for a module. -| Field | Type | Description | -|-------|------|-------------| -| count | `varuint32` | count of the number of exceptions to follow | -| sig | `except_type*` | The type signature of the data fields for the tagged exception value | +Currently, event kinds are: +| Field | Type | Description | +|---------|--------------|-------------------------------------------| +| count | `varuint32` | count of the number of events to follow | +| entries | `event_type* | list of defined event types. | ##### Import section The import section is extended to include exception definitions by extending an `import_entry` as follows: -If the `kind` is `Exception`: +If the `kind` is `event`: -| Field | Type | Description | -|-------|------|-------------| -| `sig` | `except_type` | the type signature of the exception | +| Field | Type | Description | +|-------|------------|---------------------| +| event | event_type | The event to import | ##### Export section -The export section is extended to reference exception definitions by by -extending an `export_entry` as follows: - -If the `kind` is `Exception`, then the `index` is into the corresponding -exception index in the [exception index space](#exception-index-space). +The export section is extended to reference event types by extending an +`export_entry` as follows: +If the `kind` is `Event`, then the `index` is into the corresponding +event index in the [event index space](#event-index-space). ##### Name section The set of known values for `name_type` of a name section is extended as follows: -| Name Type | Code | Description | -| --------- | ---- | ----------- | -| [Function](#function-names) | `1` | Assigns names to functions | -| [Local](#local-names) | `2` | Assigns names to locals in functions | -| [Exception](#exception-names) | `3` | Assigns names to exception types | +| Name Type | Code | Description | +|-----------------------------|------|--------------------------------------| +| [Function](#function-names) | `1` | Assigns names to functions | +| [Local](#local-names) | `2` | Assigns names to locals in functions | +| [Event](#event-names) | `3` | Assigns names to event types | -###### Exception names +###### Event names -The exception names subsection is a `name_map` which assigns names to a subset -of the _exception_ indices from the exception section. (Used for both imports -and module-defined). +The event names subsection is a `name_map` which assigns names to a subset +of the event indices, defined in the import and event sections of the module. ### Control flow operators From f4cee329ae694310b062a2d96873fdb440e5c3a1 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Mon, 26 Feb 2018 11:52:07 -0800 Subject: [PATCH 035/302] wip: working out delimited continuations --- proposals/Level-1+N.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/proposals/Level-1+N.md b/proposals/Level-1+N.md index 1f0fb15b38..ed92ed52db 100644 --- a/proposals/Level-1+N.md +++ b/proposals/Level-1+N.md @@ -236,3 +236,42 @@ function main(): print(i) resume e() ``` + +### Example: Delimited Continuations + +Consider the following example taken from +https://en.wikipedia.org/wiki/Delimited_continuation: + +```scheme +(* 2 (reset (+ 1 (shift k (k 5))))) +``` + +This can be translated into a resumable exceptions program. We'll start by +rewriting the program so that it's closer to the high level syntax we've been +using. Note that this program uses WebAssembly's stack machine nature. + +``` +function main(): + 2 + reset: + 1 + shift k: + k(5) + + + * +``` + +Now we can convert the program to use resumable exceptions: + +``` + + +function main(): + 2 + reset: + 1 + shift k: + k(5) + + + * +``` From 7a32c4b8d2ad69d4ecf77da506165fb3defbafaf Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Mon, 26 Feb 2018 11:52:51 -0800 Subject: [PATCH 036/302] Revert "Define events" This reverts commit b7fce8e78dfa3601fb726f06b75b5c77c925dd04. Fixes #46 --- proposals/Level-1.md | 362 +++++++++++++++++++++---------------------- 1 file changed, 180 insertions(+), 182 deletions(-) diff --git a/proposals/Level-1.md b/proposals/Level-1.md index 4ed625b4f2..7d6720e692 100644 --- a/proposals/Level-1.md +++ b/proposals/Level-1.md @@ -21,49 +21,49 @@ thrown. The exception can be any exception known by the WebAssembly module, or it may an unknown exception that was thrown by a called imported function. One of the problems with exception handling is that both WebAssembly and the -embedder probably have different notions of what exceptions are, but both must -be aware of the other. +host VM probably have different notions of what exceptions are, but both must be +aware of the other. -It is difficult to define exceptions in WebAssembly because (in general) it -doesn't have knowledge of the embedder. Further, adding such knowledge to -WebAssembly would limit the ability for other embedders to support WebAssembly +It is difficult to define exceptions in WebAssembly because (in general) +it doesn't have knowledge of the host VM. Further, adding such knowledge to +WebAssembly would limit the ability for other host VMs to support WebAssembly exceptions. One issue is that both sides need to know if an exception was thrown by the other, because cleanup may need to be performed. -Another problem is that WebAssembly doesn't have direct access to the embedder's -memory. As a result, WebAssembly defers the handling of exceptions to the -embedder. +Another problem is that WebAssembly doesn't have direct access to the host VM's +memory. As a result, WebAssembly defers the handling of exceptions to the host +VM. To access exceptions, WebAssembly provides instructions to check if the exception is one that WebAssembly understands. If so, the data of the -WebAssembly exception data is extracted and copied onto the stack, allowing +WebAssembly exceptions's data is extracted and copied onto the stack, allowing succeeding instructions to process the data. -Lastly, exception lifetimes must be maintained by the embedder, so that it can -collect and reuse the memory used by exceptions. This implies that the embedder -must know where exceptions are stored, so that it can determine when an -exception can be garbage collected. +Lastly, exception lifetimes must be maintained by the host VM, so that it can +collect and reuse the memory used by exceptions. This implies that the host must +know where exceptions are stored, so that it can determine when an exception can +be garbage collected. -This also implies that the embedder must provide a garbage collector for -exceptions. For embedders that have garbage collection (such as JavaScript), +This also implies that the host VM must provide a garbage collector for +exceptions. For host VMs that have garbage collection (such as JavaScript), this is not a problem. -However, not all embedders may have a garbage collector. For this reason, -WebAssembly exceptions are designed to allow the use of reference counters (to -exceptions) to perform the the garbage collection in the embedder. +However, not all host VMs may have a garbage collector. For this reason, +WebAssembly exceptions are designed to allow the use of reference counters to +perform the the garbage collection in the host VM. -To do this, WebAssembly exceptions are immutable once created. This avoids -cyclic data structures that can't be garbage collected. It also means that -exceptions can't be stored into WebAssembly's linear memory. The rationale for -this is twofold: +To do this, WebAssembly exceptions are immutable once created, to avoid cyclic +data structures that can't be garbage collected. It also means that exceptions +can't be stored into linear memory. The rationale for this is twofold: -* For security. Loads and stores do not guarantee that the data read was of the - same type as stored. This allows spoofing of exception references that may - allow a WebAssembly module to access data it should not know in the embedder. +* For security. Loads + and stores do not guarantee that the data read was of the same type as + stored. This allows spoofing of exception references that may allow a + WebAssembly module to access data it should not know in the host VM. -* The embedder does not know the layout of data in linear memory, so it can't +* The host VM does not know the layout of data in linear memory, so it can't find places where exception references are stored. Hence, while an exception reference is a new first class type, this proposal @@ -78,94 +78,92 @@ instruction. Thrown exceptions are handled as follows: 1. Throws not caught within a function body continue up the call stack, popping call frames, until an enclosing try block is found. -1. If the call stack is exhausted without any enclosing try blocks, embedder +1. If the call stack is exhausted without any enclosing try blocks, the host VM defines how to handle the uncaught exception. ### Event handling This proposal focusses on adding exception handling, but tries to be more -general in its specification. This allows future generalizations to WebAssembly -without having to redo exception handling. +general in its specification such that more general kinds of event handling can +be added to WebAssembly in the future without having to redo exception handling. -Events are generated by event yielding instructions. They yeild to an -appropriate event handler. The event handler is then run. That event handler -can either resume control at the point of the event handler, or optionally -resume by sending values back to the yielding instruction allow the -originating code to resume. +An event handler allows one to process an event generated by a block of +code. Events yield the current execution and look for an enclosing try block to +handle the event. If found, the corresponding event handler is run. The event +handler can optionally resume by sending values back to the yielded instruction, +allowing the originating code to resume. Exceptions are a special case of an event in that they never resume. Similarly, -a throw instruction is the yielding instruction of an exception, and the -corresponding catching block is the event handler of the exception. +a throw instruction is the yielding event of an exception. The catch block +associated with a try block defines how to handle the throw. -An `event` is an internal construct in WebAssembly that is maintained by the -embedder. WebAssembly events are defined by a new `event section` of a -WebAssembly module. +An `event` (such as an exception) is an internal construct in WebAssembly that +is maintained by the host. WebAssembly events are defined by a new `handler` +section` of a WebAssembly module. The handler section is a list of event types +that are defined by the module. -The event section defines a list of event types that may be handled by the -module. Each `event type` has (at a minimum) an `event specifier` and a `type -signature`. The event specifier defines the kind of event while the type -signature defines the list of values associated with the event. Depending on +Each `event type` has a `event specifier` and a `type signature`. Depending on the value of the event specifier, additional values may be specified in the event type. -For level 1, the only event specifier is the constant 0, and denotes that the -event is an `exception`. It has no additional values specified (other than the -type signature). Future extensions my add additional event specifiers, such as -resumable events. +For level 1, the only event specifier is the constant 0 which denotes that the +event is an exception. Future extensions my add additional event specifiers. -The `type signature` of an event type is an index into the `type` section. The -type signature is defined by a function type. The parameter list of the type -signature defines the list of values returned to the corresponding enclosing -catch. The result type defines the list of values to be used when resuming on an -event. For exceptions, that can't resume, the result type must always be type -'void'. +The type signature of an event type is an index to the corresponding function +signature defined in the `type` section. The parameter of the function signature +defines the list of values associated with the thrown exception. The return +value(s) of the signature defines what is passed back to the throw so that +execution may resume. -Note: Resumable events may not use the `throw` instruction. Rather, they may use -a new (yet to be defined) `yeild` instruction that passes value(s) to its -enclosing contexts. Such an instruction would allow the calling context to -return values back, and resume with the instruction following the yeild -instruction, based on the values returned. +Note: Resumable events may not use the `throw` instruction, and may use new (yet +to be defined) `yeild` instructions for which value(s) may be passed back to it +and allow it to resume with the instruction following the yeild instruction. Within a module, event types are identified by an `event index` to the [event -index space](#event-index-space). Each event index refers to a corresponding -runtime tag that uniquely identifies the corresponding event to be handled. The -corresponding runtime tag is called an `event tag`. +index space](#event-index-space). This (module specific) index identifies the +corresponding identify runtime `event tag` that uniquely identifies the +corresponding event type. -Event types are numbered numerically, starting with the import section, and then -followed by event types in the event section. Each event type within a module -are associated with unique event tags. +### Exceptions -Event types can also be exported by adding appropriate descriptors in the export -section of the module. Each imported/exported event index must be named to -reconcile the corresponding (runtime) event tag. +An `exception` is an internal construct in WebAssembly that is maintained by the +host. WebAssembly exceptions (as opposed to host exceptions) are defined by a +new `exception section` of a WebAssembly module. The exception section is a list +of exception definitions, from which exceptions can be created. -### Exceptions +Each exception definition describe the structure of corresponding exception +values that can be generated from it. Exception definitions may also appear in +the import section of a module. + +Each exception definition has a `type signature`. The type signature defines the +list of values associated with corresponding thrown exception values. + +Within the module, exception definitions are identified by an index into the +[exception index space](#exception-index-space). This static index refers to the +corresponding runtime tag that uniquely identifies exception values created +using the exception definition, and is called the `exception tag`. -An `exception` is a WebAssembly event that can be thrown and caught. That is, -an `exception type` is an event type whose event specifier is 0. The `type -signature` of the exception is the corresponding type signature of the event -type. That is, the parameter list of the type signature defines the list of -values associated with the exception, and the result type must be type `void`. +Each exception definition within a module (i.e. in the exception and import +section) are associated with unique exception tags. -Exceptions are identified by the by the corresponding event index, and is called -an `exception index`. The corresponding (runtime) event tag is called the -`exception tag`. Like all event types, each exception type within a module -(i.e. in the event and import sections) are associated with unique exception -tags. +Exception tags can also be exported by adding the appropriate descriptors in the +export section of the module. All imported/exported indices must be named to +reconcile the corresponding exception tag referenced by exception indices +between modules. Exception indices are used by: -1. The `throw` instruction which creates a WebAssembly exception with the - corresponding exception tag, and then throws it. +1. The `throw` instruction which creates a WebAssembly exception value + with the corresponding exception tag, and then throws it. -2. The `if_except` instruction that queries an exception to see if the exception - tag corresponding to the module's exception index. If true it pushes the - corresponding values of the exception onto the stack. +2. The `if_except` instruction that queries an exception value to see if the + exception tag corresponding to the module's exception index. If true it + pushes the corresponding values of the exception onto the stack. ### The exception reference data type -Data types are extended to have a new `except_ref` type. The representation is -left to the embedder. +Data types are extended to have a new `except_ref` type. The representation of +an exception value is left to the host VM. ### Try and catch blocks @@ -184,8 +182,7 @@ end ``` A try block ends with a `catch block` that is defined by the list of -instructions after the `catch` instruction. The catch block is the event handler -for all exceptions thrown in the try block. +instructions after the `catch` instruction. Try blocks, like control-flow blocks, have a _block type_. The block type of a try block defines the values yielded by the evaluation the try block when either @@ -198,16 +195,15 @@ In the initial implementation, try blocks may only yield 0 or 1 values. The `throw` instruction takes an exception index as an immediate argument. That index is used to identify the exception tag to use to create and throw the -corresponding exception. +corresponding exception value. The values on top of the stack must correspond to the the type signature associated with the exception index. These values are popped of the stack and are used (along with the corresponding exception tag) to create the -corresponding exception value. Along with the values, a stack trace is also -associated with the exception. That exception is then thrown. +corresponding exception value. That exception value is then thrown. -When an exception is thrown, the embedder searches for nearest enclosing try -block body that execution is in. That try block is called the _catching_ try +When an exception value is thrown, the host VM searches for nearest enclosing +try block body that execution is in. That try block is called the _catching_ try block. If the throw appears within the body of a try block, it is the catching try @@ -216,47 +212,52 @@ block. If a throw occurs within a function body, and it doesn't appear inside the body of a try block, the throw continues up the call stack until it is in the body of an an enclosing try block, or the call stack is flushed. If the call stack is -flushed, the embeddder defines how to handle uncaught exceptions. Otherwise, the +flushed, the host VM defines how to handle uncaught exceptions. Otherwise, the found enclosing try block is the catching try block. A throw inside the body of a catch block is never caught by the corresponding try block of the catch block, since instructions in the body of the catch block are not in the body of the try block. -Once a catching try block is found for the thrown exception, the operand stack -is popped back to the size the operand stack had when the try block was entered, -and then an except_ref (for the exception) is pushed back onto the stack. +Once a catching try block is found for the thrown exception value, the operand +stack is popped back to the size the operand stack had when the try block was +entered, and then the values of the caught exception value is pushed onto the +stack. If control is transferred to the body of a catch block, and the last instruction in the body is executed, control then exits the try block. If the selected catch block does not throw an exception, it must yield the value(s) expected by the corresponding catching try block. This includes popping -the caught except_ref. +the caught exception. -Note that a caught exception except_ref value can be rethrown using the -`rethrow` instruction. +Note that a caught exception value can be rethrown using the `rethrow` +instruction. ### Rethrowing an exception -The `rethrow` instruction takes the exception associated with the `except_ref` -on top of the stack, and rethrows that exception. A rethrow has the same effect -as a throw, other than an exception is not created. Rather, the referenced -exception on top of the stack is popped and then thrown. +The `rethrow` instruction takes the exception value associated with the +`except_ref` on top of the stack, and rethrows the exception. A rethrow has the +same effect as a throw, other than an exception is not created. Rather, the +referenced exception value on top of the stack is popped and then thrown. ### Exception data extraction -The `if_except block` defines a conditional query of the exception in the -except_ref on top of the stack. The except_ref is popped when queried. The -if_except block has two subblocks, the `then` and `else` subblocks, like that of -an `if` block. The then block is a sequence of instructions following the -`if_except` instruction. The else block begins with the `else` instruction. The -scope of the if_except block is from the `if_except` instruction to the -corresponding `end` instruction. +The `if_except block` defines a conditional query of the exception value on top +of the stack. The exception value is not popped when queried. The if_except +block has two subblocks, the `then` and `else` subblocks, like that of an `if` +block. The then block is a sequence of instructions following the `if_except` +instruction. The else block is optional, and if it appears, it begins with the +`else` instruction. The scope of the if_except block is from the `if_except` +instruction to the corresponding `end` instruction. That is, the forms of an if_except block is: ``` +if_except block_type except_index + Instruction* +end + if_except block_type except_index Instruction* else @@ -264,19 +265,25 @@ else end ``` -The conditional query of an exception succeeds when the exception in the -except_ref on the top of the stack has the corresponding exception tag (defined -by `except_index`). After the query, the except_ref is popped from the stack. +The conditional query of an exception succeeds when the exception value on the +top of the stack has the corresponding exception tag (defined by `except_index`). If the query succeeds, the values (associated with the exception value) are extracted and pushed onto the stack, and control transfers to the instructions -in the then block. If the query fails, control is transfertd to the else block. +in the then block. -### Stack traces +If the query fails, it either enters the else block, or transfer control to the +end of the if_except block if there is no else block. -When an exception is thrown, conceptually a runtime stack is associated with the -exception. However, WebAssembly does not have (direct) access to the stack -trace. Hence, it is left to the embedder to maintain and use at it sees fit. +### Debugging + +Earlier discussion implied that when an exception is thrown, the runtime will +pop the operand stack across function calls until a corresponding, enclosing try +block is found. The implementation may actually not do this. Rather, it may +first search up the call stack to see if there is an enclosing try. If none are +found, it could terminate the thread at the point of the throw. This would +allow better debugging capability, since the corresponding call stack is still +there to query. ## Changes to the text format. @@ -292,6 +299,7 @@ The following rules are added to *instructions*: except except_index | throw except_index | rethrow | + if_except resulttype except_index then instruction* end | if_except resulttype except_index then instruction* else instruction* end ``` @@ -300,49 +308,51 @@ instructions are *structured* control flow instructions, and can be labeled. This allows branch instructions to exit try and `if_except` blocks. The `except_index` of the `throw` and `if_except` instructions defines the -exception type (and hence, exception tag) to create/extract form. See [event -index space](#event-index-space) for further clarification of exception -tags. +exception value (and hence, exception tag) to create/extract form. See +[exception index space](#exception-index-space) for further clarification of +exception tags. ## Changes to Modules document. This section describes change in the [Modules document](https://github.com/WebAssembly/design/blob/master/Modules.md). -### Event index space +### Exception index space -The `event index space` indexes all imported and internally-defined events, -assigning monotonically-increasing indices based on the order defined in the -import and event sections. Thus, the index space starts at zero with imported -events followed by internally-defined events in the [event -section](#event-section). +The _exception index space_ indexes all imported and internally-defined +exceptions, assigning monotonically-increasing indices based on the order +defined in the import and exception sections. Thus, the index space starts at +zero with imported exceptions followed by internally-defined exceptions in +the [exception section](#exception-section). -The event index space defines the (module) static version of runtine event -tags. These (runtime) event tags are guaranteed to be unique over all loaded +The exception index space defines the (module) static version of runtine +exception tags. For exception indicies that are not imported/exported, the +corresponding exception tag is guaranteed to be unique over all loaded modules. -For event indices imported/exported, unique event tags are created for +For exception indices imported/exported, unique exception tags are created for each unique name imported/exported, and are aliased to the corresponding -event index defined in each module. +exception index defined in each module. ## Changes to the binary model -This section describes changes in the [binary encoding design -document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md). +This section describes changes in +the +[binary encoding design document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md). ### Data Types #### except_ref -An exception reference points to an exception. The size is fixed, but unknown in -WebAssembly. +An exception reference points to an exception value. The size +is fixed, but unknown in WebAssembly (the host defines the size in bytes). ### Language Types | Opcode | Type constructor | |--------|------------------| -| -0x0x5 | `except_ref` | +| -0x41 | `except_ref` | #### value_type @@ -351,28 +361,15 @@ encoded above. #### Other Types -##### event_type - -An event specifier specifies the kind of event an event type represents. Currently, -the only value event specifier is: - -| Name | Value | -|-----------|-------| -| exception | 0 | - +##### except_type -Each event type (defining an event tag) has (at a minimum) an event specifier -and a type signature. Each event type begins with the fields +Each exception definition (defining an exception tag) has a type signature, +which corresponds to the data fields of the exception. -| Field | Type | Description | -|-------------|-------------|------------------------------------------------| -| `specifier` | `varuint32` | The kind of event. | -| `type` | `varuint32` | Index to the type defining its type signature. | - - -Followed by (based on specifier): - -`exception`: No additional fields. +| Field | Type | Description | +|-------|------|-------------| +| `count` | `varuint32` | The number of types in the signature | +| `type` | `value_type*` | The type of each element in the signature | ##### external_kind @@ -383,61 +380,62 @@ or defined: * `1` indicating a `Table` [import](Modules.md#imports) or [definition](Modules.md#table-section) * `2` indicating a `Memory` [import](Modules.md#imports) or [definition](Modules.md#linear-memory-section) * `3` indicating a `Global` [import](Modules.md#imports) or [definition](Modules.md#global-section) -* `4` indicating an `Event` [import](#import-section) or [definition](#event-section) +* `4` indicating an `Exception` [import](#import-section) or [definition](#exception-section) ### Module structure #### High-level structure -A new event section is introduced and is named `event`. If included, +A new `exception` section is introduced and is named `exception`. If included, it must appear after immediately after the global section. -##### Event section +##### Exception section -The `event` section is the named section 'event'. The event section declares a -list of event types for a module. +The `exception` section is the named section 'exception'. The exception section +declares a list of exception definitions, defining corresponding exception tags. -Currently, event kinds are: +| Field | Type | Description | +|-------|------|-------------| +| count | `varuint32` | count of the number of exceptions to follow | +| sig | `except_type*` | The type signature of the data fields for the tagged exception value | -| Field | Type | Description | -|---------|--------------|-------------------------------------------| -| count | `varuint32` | count of the number of events to follow | -| entries | `event_type* | list of defined event types. | ##### Import section The import section is extended to include exception definitions by extending an `import_entry` as follows: -If the `kind` is `event`: +If the `kind` is `Exception`: -| Field | Type | Description | -|-------|------------|---------------------| -| event | event_type | The event to import | +| Field | Type | Description | +|-------|------|-------------| +| `sig` | `except_type` | the type signature of the exception | ##### Export section -The export section is extended to reference event types by extending an -`export_entry` as follows: +The export section is extended to reference exception definitions by by +extending an `export_entry` as follows: + +If the `kind` is `Exception`, then the `index` is into the corresponding +exception index in the [exception index space](#exception-index-space). -If the `kind` is `Event`, then the `index` is into the corresponding -event index in the [event index space](#event-index-space). ##### Name section The set of known values for `name_type` of a name section is extended as follows: -| Name Type | Code | Description | -|-----------------------------|------|--------------------------------------| -| [Function](#function-names) | `1` | Assigns names to functions | -| [Local](#local-names) | `2` | Assigns names to locals in functions | -| [Event](#event-names) | `3` | Assigns names to event types | +| Name Type | Code | Description | +| --------- | ---- | ----------- | +| [Function](#function-names) | `1` | Assigns names to functions | +| [Local](#local-names) | `2` | Assigns names to locals in functions | +| [Exception](#exception-names) | `3` | Assigns names to exception types | -###### Event names +###### Exception names -The event names subsection is a `name_map` which assigns names to a subset -of the event indices, defined in the import and event sections of the module. +The exception names subsection is a `name_map` which assigns names to a subset +of the _exception_ indices from the exception section. (Used for both imports +and module-defined). ### Control flow operators From 875176522fb25717a2986f1c0715d9f2e367c267 Mon Sep 17 00:00:00 2001 From: KarlSchimpf Date: Mon, 26 Feb 2018 13:32:13 -0800 Subject: [PATCH 037/302] Revert merge #45 (#47) From b228f3ac3ae0504866783e7dbba1d3dec425cd90 Mon Sep 17 00:00:00 2001 From: KarlSchimpf Date: Thu, 8 Mar 2018 12:42:26 -0800 Subject: [PATCH 038/302] Generalize exceptions to events (#49) * Add event handling * Clean up text * Clean up more * Fix order of arguments for if_except * Clean up description of event index/tag * Fix mispellings * Fix more nits --- proposals/Level-1.md | 301 +++++++++++++++++++------------------------ 1 file changed, 134 insertions(+), 167 deletions(-) diff --git a/proposals/Level-1.md b/proposals/Level-1.md index 7d6720e692..5cbabbd9d5 100644 --- a/proposals/Level-1.md +++ b/proposals/Level-1.md @@ -20,50 +20,49 @@ Exception handling allows code to break control flow when an exception is thrown. The exception can be any exception known by the WebAssembly module, or it may an unknown exception that was thrown by a called imported function. -One of the problems with exception handling is that both WebAssembly and the -host VM probably have different notions of what exceptions are, but both must be -aware of the other. +One of the problems with exception handling is that both WebAssembly and an +embedder have different notions of what exceptions are, but both must be aware +of the other. -It is difficult to define exceptions in WebAssembly because (in general) -it doesn't have knowledge of the host VM. Further, adding such knowledge to -WebAssembly would limit the ability for other host VMs to support WebAssembly +It is difficult to define exceptions in WebAssembly because (in general) it +doesn't have knowledge of any embedder. Further, adding such knowledge to +WebAssembly would limit the ability for other embedders to support WebAssembly exceptions. One issue is that both sides need to know if an exception was thrown by the other, because cleanup may need to be performed. -Another problem is that WebAssembly doesn't have direct access to the host VM's +Another problem is that WebAssembly doesn't have direct access to an embedder's memory. As a result, WebAssembly defers the handling of exceptions to the host VM. To access exceptions, WebAssembly provides instructions to check if the exception is one that WebAssembly understands. If so, the data of the -WebAssembly exceptions's data is extracted and copied onto the stack, allowing +WebAssembly exception is extracted and copied onto the stack, allowing succeeding instructions to process the data. -Lastly, exception lifetimes must be maintained by the host VM, so that it can -collect and reuse the memory used by exceptions. This implies that the host must -know where exceptions are stored, so that it can determine when an exception can -be garbage collected. +Lastly, exception lifetimes may be maintained by the embedder, so that it can +collect and reuse the memory used by exceptions. This implies that an embedder +needs to know where exceptions are stored, so that it can determine when an +exception can be garbage collected. -This also implies that the host VM must provide a garbage collector for -exceptions. For host VMs that have garbage collection (such as JavaScript), +This also implies that that embedders must provide a garbage collector for +exceptions. For embedders that have garbage collection (such as JavaScript), this is not a problem. -However, not all host VMs may have a garbage collector. For this reason, -WebAssembly exceptions are designed to allow the use of reference counters to -perform the the garbage collection in the host VM. +However, not all embedders may have a garbage collector. For this reason, +WebAssembly exceptions are designed to allow other storage management methods, +such as reference counting, to perform the garbage collection in the embedder. To do this, WebAssembly exceptions are immutable once created, to avoid cyclic -data structures that can't be garbage collected. It also means that exceptions +data structures that cannot be garbage collected. It also means that exceptions can't be stored into linear memory. The rationale for this is twofold: -* For security. Loads - and stores do not guarantee that the data read was of the same type as - stored. This allows spoofing of exception references that may allow a - WebAssembly module to access data it should not know in the host VM. +* For security. Loads and stores do not guarantee that the data read was of the + same type as stored. This allows spoofing of exception references that may + allow a WebAssembly module to access data it should not know in the host VM. -* The host VM does not know the layout of data in linear memory, so it can't +* The embedder does not know the layout of data in linear memory, so it can't find places where exception references are stored. Hence, while an exception reference is a new first class type, this proposal @@ -78,92 +77,63 @@ instruction. Thrown exceptions are handled as follows: 1. Throws not caught within a function body continue up the call stack, popping call frames, until an enclosing try block is found. -1. If the call stack is exhausted without any enclosing try blocks, the host VM +1. If the call stack is exhausted without any enclosing try blocks, the embedder defines how to handle the uncaught exception. ### Event handling -This proposal focusses on adding exception handling, but tries to be more -general in its specification such that more general kinds of event handling can -be added to WebAssembly in the future without having to redo exception handling. +This proposal adds exception handling to WebAssembly. Part of this proposal is +to define a new section to declare exceptions. However, rather than limiting +this new section to just defining exceptions, it defines a more general format +that allows the declaration of other forms of events. -An event handler allows one to process an event generated by a block of -code. Events yield the current execution and look for an enclosing try block to -handle the event. If found, the corresponding event handler is run. The event -handler can optionally resume by sending values back to the yielded instruction, -allowing the originating code to resume. +In general, an event handler allows one to process an event generated by a block +of code. Events suspend the current execution and look for a corresponding event +handler. If found, the corresponding event handler is run. Some event handlers +may send values back to the suspended instruction, allowing the originating code +to resume. Exceptions are a special case of an event in that they never resume. Similarly, -a throw instruction is the yielding event of an exception. The catch block +a throw instruction is the suspending event of an exception. The catch block associated with a try block defines how to handle the throw. -An `event` (such as an exception) is an internal construct in WebAssembly that -is maintained by the host. WebAssembly events are defined by a new `handler` -section` of a WebAssembly module. The handler section is a list of event types -that are defined by the module. +WebAssembly events (i.e. exceptions) are defined by a new `event` section of a +WebAssembly module. The event section is a list of declared events associated +with the module. -Each `event type` has a `event specifier` and a `type signature`. Depending on -the value of the event specifier, additional values may be specified in the -event type. +Each event has an `attribute` and a `type`. Currently, the attribute can only +specify that the event is an exception. In the future, additional attribute +values may be added when other events are added to WebAssembly. -For level 1, the only event specifier is the constant 0 which denotes that the -event is an exception. Future extensions my add additional event specifiers. +The type of an event is denoted by an index to a function signature defined in +the `type` section. The parameters of the function signature defines the list of +values associated with the exception event. The result type must be 'void'. -The type signature of an event type is an index to the corresponding function -signature defined in the `type` section. The parameter of the function signature -defines the list of values associated with the thrown exception. The return -value(s) of the signature defines what is passed back to the throw so that -execution may resume. - -Note: Resumable events may not use the `throw` instruction, and may use new (yet -to be defined) `yeild` instructions for which value(s) may be passed back to it -and allow it to resume with the instruction following the yeild instruction. - -Within a module, event types are identified by an `event index` to the [event -index space](#event-index-space). This (module specific) index identifies the -corresponding identify runtime `event tag` that uniquely identifies the -corresponding event type. +An `event tag` is a value to distinguish different events, while an `event index +is a numeric name to refer to an (imported or defined) event tag within a module +(see [event index space](#event-index-space) for details). ### Exceptions -An `exception` is an internal construct in WebAssembly that is maintained by the -host. WebAssembly exceptions (as opposed to host exceptions) are defined by a -new `exception section` of a WebAssembly module. The exception section is a list -of exception definitions, from which exceptions can be created. - -Each exception definition describe the structure of corresponding exception -values that can be generated from it. Exception definitions may also appear in -the import section of a module. - -Each exception definition has a `type signature`. The type signature defines the -list of values associated with corresponding thrown exception values. - -Within the module, exception definitions are identified by an index into the -[exception index space](#exception-index-space). This static index refers to the -corresponding runtime tag that uniquely identifies exception values created -using the exception definition, and is called the `exception tag`. - -Each exception definition within a module (i.e. in the exception and import -section) are associated with unique exception tags. - -Exception tags can also be exported by adding the appropriate descriptors in the -export section of the module. All imported/exported indices must be named to -reconcile the corresponding exception tag referenced by exception indices -between modules. +An `exception` is an internal construct in WebAssembly . WebAssembly exceptions +are defined in the `event` and import sections of a module. Each event (with an +exception attribute) defines an `exception`. The event index is also called the +`exception index`. Similarly, the corresponding event tag is called an +`exception tag`. Exception indices are used by: -1. The `throw` instruction which creates a WebAssembly exception value +1. The `throw` instruction which creates a WebAssembly exception with the corresponding exception tag, and then throws it. -2. The `if_except` instruction that queries an exception value to see if the - exception tag corresponding to the module's exception index. If true it - pushes the corresponding values of the exception onto the stack. +2. The `if_except` instruction queries an exception to see if the corresponding + exception tag denoted by the exception index. If true it pushes the + corresponding values of the exception onto the stack. ### The exception reference data type -Data types are extended to have a new `except_ref` type. The representation of -an exception value is left to the host VM. +Data types are extended to have a new `except_ref` type, that refers to an +exception. The representation of an exception is left to the implementation. ### Try and catch blocks @@ -195,15 +165,15 @@ In the initial implementation, try blocks may only yield 0 or 1 values. The `throw` instruction takes an exception index as an immediate argument. That index is used to identify the exception tag to use to create and throw the -corresponding exception value. +corresponding exception. -The values on top of the stack must correspond to the the type signature -associated with the exception index. These values are popped of the stack and -are used (along with the corresponding exception tag) to create the -corresponding exception value. That exception value is then thrown. +The values on top of the stack must correspond to the type associated with the +exception. These values are popped of the stack and are used (along with the +corresponding exception tag) to create the corresponding exception. That +exception is then thrown. -When an exception value is thrown, the host VM searches for nearest enclosing -try block body that execution is in. That try block is called the _catching_ try +When an exception is thrown, the embedder searches for the nearest enclosing try +block body that execution is in. That try block is called the _catching_ try block. If the throw appears within the body of a try block, it is the catching try @@ -212,17 +182,17 @@ block. If a throw occurs within a function body, and it doesn't appear inside the body of a try block, the throw continues up the call stack until it is in the body of an an enclosing try block, or the call stack is flushed. If the call stack is -flushed, the host VM defines how to handle uncaught exceptions. Otherwise, the +flushed, the embedder defines how to handle uncaught exceptions. Otherwise, the found enclosing try block is the catching try block. A throw inside the body of a catch block is never caught by the corresponding try block of the catch block, since instructions in the body of the catch block are not in the body of the try block. -Once a catching try block is found for the thrown exception value, the operand -stack is popped back to the size the operand stack had when the try block was -entered, and then the values of the caught exception value is pushed onto the -stack. +Once a catching try block is found for the thrown exception, the operand stack +is popped back to the size the operand stack had when the try block was entered, +and then an except_ref referring to the caught exception is pushed back onto the +operand stack. If control is transferred to the body of a catch block, and the last instruction in the body is executed, control then exits the try block. @@ -231,25 +201,19 @@ If the selected catch block does not throw an exception, it must yield the value(s) expected by the corresponding catching try block. This includes popping the caught exception. -Note that a caught exception value can be rethrown using the `rethrow` -instruction. +Note that a caught exception can be rethrown using the `rethrow` instruction. ### Rethrowing an exception -The `rethrow` instruction takes the exception value associated with the -`except_ref` on top of the stack, and rethrows the exception. A rethrow has the -same effect as a throw, other than an exception is not created. Rather, the -referenced exception value on top of the stack is popped and then thrown. +The `rethrow` instruction takes the exception associated with the `except_ref` +on top of the stack, and rethrows the exception. A rethrow has the same effect +as a throw, other than an exception is not created. Rather, the referenced +exception on top of the stack is popped and then thrown. ### Exception data extraction -The `if_except block` defines a conditional query of the exception value on top -of the stack. The exception value is not popped when queried. The if_except -block has two subblocks, the `then` and `else` subblocks, like that of an `if` -block. The then block is a sequence of instructions following the `if_except` -instruction. The else block is optional, and if it appears, it begins with the -`else` instruction. The scope of the if_except block is from the `if_except` -instruction to the corresponding `end` instruction. +The `if_except` block begins with an `if_except` instruction, and +has two instruction blocks, That is, the forms of an if_except block is: @@ -265,25 +229,29 @@ else end ``` -The conditional query of an exception succeeds when the exception value on the -top of the stack has the corresponding exception tag (defined by `except_index`). +In the first form, the instructions between the `if_except` and 'end' define the +`then block`. In the second form, the instructions between the `if_except` and +`else` define the `then block`, while the instructions between the `else` and +the `end` define the `else block`. + +The conditional query of an exception checks the exception tag of exception on +top of the stack. It succeeds only if the exception index of the instruction +matches the corresponding exception tag. Once the query completes, the exception +is popped off the stack. -If the query succeeds, the values (associated with the exception value) are +If the query succeeds the values (associated with the popped exception) are extracted and pushed onto the stack, and control transfers to the instructions in the then block. If the query fails, it either enters the else block, or transfer control to the end of the if_except block if there is no else block. -### Debugging +### Stack traces -Earlier discussion implied that when an exception is thrown, the runtime will -pop the operand stack across function calls until a corresponding, enclosing try -block is found. The implementation may actually not do this. Rather, it may -first search up the call stack to see if there is an enclosing try. If none are -found, it could terminate the thread at the point of the throw. This would -allow better debugging capability, since the corresponding call stack is still -there to query. +When an exception is thrown, the runtime will pop the stack across +function calls until a corresponding, enclosing try block is found. It may also +associate a stack trace that can be used to report uncaught exceptions. However, +the details of this is left to the embedder. ## Changes to the text format. @@ -308,7 +276,7 @@ instructions are *structured* control flow instructions, and can be labeled. This allows branch instructions to exit try and `if_except` blocks. The `except_index` of the `throw` and `if_except` instructions defines the -exception value (and hence, exception tag) to create/extract form. See +exception (and hence, exception tag) to create/extract from. See [exception index space](#exception-index-space) for further clarification of exception tags. @@ -317,22 +285,18 @@ exception tags. This section describes change in the [Modules document](https://github.com/WebAssembly/design/blob/master/Modules.md). -### Exception index space +### Event index space -The _exception index space_ indexes all imported and internally-defined -exceptions, assigning monotonically-increasing indices based on the order -defined in the import and exception sections. Thus, the index space starts at -zero with imported exceptions followed by internally-defined exceptions in -the [exception section](#exception-section). +The `event index space` indexes all imported and internally-defined events, +assigning monotonically-increasing indices based on the order defined in the +import and event sections. Thus, the index space starts at zero with +imported events, followed by internally-defined events in the [event +section](#event-section). -The exception index space defines the (module) static version of runtine -exception tags. For exception indicies that are not imported/exported, the -corresponding exception tag is guaranteed to be unique over all loaded -modules. - -For exception indices imported/exported, unique exception tags are created for -each unique name imported/exported, and are aliased to the corresponding -exception index defined in each module. +The event index space defines the (module) static version of runtine event +tags. For event indices that are not imported/exported, the corresponding event +tag is guaranteed to be unique over all loaded modules. Events that are imported +or exported alias the respective events defined elsewhere, and use the same tag. ## Changes to the binary model @@ -340,19 +304,17 @@ This section describes changes in the [binary encoding design document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md). - ### Data Types #### except_ref -An exception reference points to an exception value. The size -is fixed, but unknown in WebAssembly (the host defines the size in bytes). +An exception reference points to an exception. ### Language Types | Opcode | Type constructor | |--------|------------------| -| -0x41 | `except_ref` | +| -0x18 | `except_ref` | #### value_type @@ -361,15 +323,20 @@ encoded above. #### Other Types -##### except_type +##### event_type + +The set of event attributes are: + +| Name | Value | +|-----------|-------| +| Exception | 0 | -Each exception definition (defining an exception tag) has a type signature, -which corresponds to the data fields of the exception. +Each event type has the fields: | Field | Type | Description | |-------|------|-------------| -| `count` | `varuint32` | The number of types in the signature | -| `type` | `value_type*` | The type of each element in the signature | +| `attribute` | `varuint32` | The attribute of the event. | +| `type` | `varuint32` | The type index for its corresponding type signature | ##### external_kind @@ -380,45 +347,46 @@ or defined: * `1` indicating a `Table` [import](Modules.md#imports) or [definition](Modules.md#table-section) * `2` indicating a `Memory` [import](Modules.md#imports) or [definition](Modules.md#linear-memory-section) * `3` indicating a `Global` [import](Modules.md#imports) or [definition](Modules.md#global-section) -* `4` indicating an `Exception` [import](#import-section) or [definition](#exception-section) +* `4` indicating an `Event` [import](#import-section) or [definition](#event-section) ### Module structure #### High-level structure -A new `exception` section is introduced and is named `exception`. If included, -it must appear after immediately after the global section. +A new `event` section is introduced and is named `event`. If included, it must +appear after immediately after the global section. -##### Exception section +##### Event section -The `exception` section is the named section 'exception'. The exception section -declares a list of exception definitions, defining corresponding exception tags. +The `section` section is the named section 'event'. The event section +declares a list of event types as follows: | Field | Type | Description | |-------|------|-------------| -| count | `varuint32` | count of the number of exceptions to follow | -| sig | `except_type*` | The type signature of the data fields for the tagged exception value | - +| count | `varuint32` | count of the number of events to follow | +| type | `except_type*` | The definitions of the event types | ##### Import section -The import section is extended to include exception definitions by extending an +The import section is extended to include event definitions by extending an `import_entry` as follows: -If the `kind` is `Exception`: +If the `kind` is `Event`: | Field | Type | Description | |-------|------|-------------| -| `sig` | `except_type` | the type signature of the exception | +| `type` | `event_type` | the event being imported | ##### Export section -The export section is extended to reference exception definitions by by +The export section is extended to reference event types by extending an `export_entry` as follows: -If the `kind` is `Exception`, then the `index` is into the corresponding -exception index in the [exception index space](#exception-index-space). +If the `kind` is `Event`: +| Field | Type | Description | +|-------|------|-------------| +| `index` | `varuint32` | the index into the corresponding event index space | ##### Name section @@ -429,13 +397,12 @@ follows: | --------- | ---- | ----------- | | [Function](#function-names) | `1` | Assigns names to functions | | [Local](#local-names) | `2` | Assigns names to locals in functions | -| [Exception](#exception-names) | `3` | Assigns names to exception types | +| [Event](#event-names) | `3` | Assigns names to event types | -###### Exception names +###### Event names -The exception names subsection is a `name_map` which assigns names to a subset -of the _exception_ indices from the exception section. (Used for both imports -and module-defined). +The event names subsection is a `name_map` which assigns names to a subset of +the event indices (Used for both imports and module-defined). ### Control flow operators @@ -448,7 +415,7 @@ throws, and rethrows as follows: | `catch` | `0x07` | | begins the catch block of the try block | | `throw` | `0x08` | index : `varint32` | Creates an exception defined by the exception `index`and then throws it | | `rethrow` | `0x09` | | Pops the `except_ref` on top of the stack and throws it | -| `if_except` | `0x0a` | sig : `block_type` , index : `varuint32` | Begin exception data extraction if exception on stack was created using the corresponding exception `index` | +| `if_except` | `0x0a` | index : `varuint32`, sig : `block_type` | Begin exception data extraction if exception on stack was created using the corresponding exception `index` | The *sig* fields of `block`, `if`, `try` and `if_except` operators are block signatures which describe their use of the operand stack. From ce6840ecac2e69d786857c78f8f7d60854f2be77 Mon Sep 17 00:00:00 2001 From: Sven SAULEAU Date: Wed, 11 Apr 2018 19:24:39 +0200 Subject: [PATCH 039/302] docs: fix typo (#56) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cae5105c86..a987ee7c1c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This repository holds a -[propsal](https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md) for +[proposal](https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md) for adding exception handling to WebAssembly. The repository is a copy From ecd361e8f34513ba8b7fd8bf6d1ef13fcfe772fc Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Fri, 13 Apr 2018 11:34:46 -0700 Subject: [PATCH 040/302] Fix typos --- proposals/Level-1+N.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/Level-1+N.md b/proposals/Level-1+N.md index ed92ed52db..ee82a1d4a4 100644 --- a/proposals/Level-1+N.md +++ b/proposals/Level-1+N.md @@ -52,7 +52,7 @@ try resulttype end ``` -Note that the `catch exteption_index` and `catch` forms of the catch clause should be given different opcodes. +Note that the `catch exception_index` and `catch` forms of the catch clause should be given different opcodes. ### Alternate Form: Catch Lists @@ -69,7 +69,7 @@ end One downside of this form is that it does not directly support running different code for different exception types. This can still be accomplished, however, by -dyanmically inspecting the exception inside the catch block. +dynamically inspecting the exception inside the catch block. # Level 3 From dc2915a98178c09ccfc84fd2de986b3e2a986be7 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Fri, 13 Apr 2018 15:30:58 -0700 Subject: [PATCH 041/302] Finish delimited continuation example --- proposals/Level-1+N.md | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/proposals/Level-1+N.md b/proposals/Level-1+N.md index ee82a1d4a4..7372ef029a 100644 --- a/proposals/Level-1+N.md +++ b/proposals/Level-1+N.md @@ -186,14 +186,14 @@ function run(): try: produce() catch e: yield(): - c1 = e + e end // Start the consumer try: consume() catch e: yield(): - c2 = e + e end loop: @@ -248,30 +248,23 @@ https://en.wikipedia.org/wiki/Delimited_continuation: This can be translated into a resumable exceptions program. We'll start by rewriting the program so that it's closer to the high level syntax we've been -using. Note that this program uses WebAssembly's stack machine nature. +using. ``` function main(): - 2 - reset: - 1 - shift k: - k(5) - + - * + 2 * (reset => 1 + (shift k => k(5))) ``` -Now we can convert the program to use resumable exceptions: +Now we can convert the program to use resumable exceptions. For convenience, we +use JavaScript-style lambdas (e.g. `(x, y) => x + y`) and assume a later pass +will compile this away. ``` - +Exception shift_k: (fn (i32) -> i32) -> i32 function main(): - 2 - reset: - 1 - shift k: - k(5) - + - * + 2 * (try: + 1 + (throw shift_k((k) => k(5))) + catch e: shift_k(f): + f((v) => resume e(v))) ``` From 32ad95172332f7a3b9a8e56fd1423adfc63d382a Mon Sep 17 00:00:00 2001 From: Max Nordlund Date: Mon, 27 Aug 2018 08:18:52 +0200 Subject: [PATCH 042/302] Fix syntax typo (#59) --- proposals/Level-1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/Level-1.md b/proposals/Level-1.md index 5cbabbd9d5..e2c829fbae 100644 --- a/proposals/Level-1.md +++ b/proposals/Level-1.md @@ -109,7 +109,7 @@ The type of an event is denoted by an index to a function signature defined in the `type` section. The parameters of the function signature defines the list of values associated with the exception event. The result type must be 'void'. -An `event tag` is a value to distinguish different events, while an `event index +An `event tag` is a value to distinguish different events, while an `event index` is a numeric name to refer to an (imported or defined) event tag within a module (see [event index space](#event-index-space) for details). From 7148890879cc7c8688aafec31f6d2ee6237822b8 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Wed, 24 Oct 2018 00:14:08 -0700 Subject: [PATCH 043/302] Merge two proposals in a single doc (#61) * Merge two proposals in a single doc So far there have been two proposals, we have not decided on which to use for the instruction part. We have agreed to use the second proposal for the module and binary model (new event section and its format). This patch tries to update the spec to the status quo: this describes both proposals for the instruction part, and present the single agreed-on proposal for the module/binary part. I plan to add some more stuff to the proposal, such as some modifications to `rethrow` and the restriction on the order of the event section, but it will come after this patch. - Little bit of backstory: The initial motivation for the second proposal, which proposes a first-class exception ref type, was to ease some of toolchain implementation problems. The problems do not exist anymore for some other reason, but some people want to keep the second proposal on table because possible benefits it may bring, for example, better expressiveness. So we update this proposal to reflect the status quo and not to confuse people. We will eventually unify this to a single proposal. --- proposals/Exceptions.md | 587 ++++++++++++++++++++++++------- proposals/old/Exceptions.md | 391 ++++++++++++++++++++ proposals/{ => old}/Level-1+N.md | 0 proposals/{ => old}/Level-1.md | 0 4 files changed, 850 insertions(+), 128 deletions(-) create mode 100644 proposals/old/Exceptions.md rename proposals/{ => old}/Level-1+N.md (100%) rename proposals/{ => old}/Level-1.md (100%) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index d234b3cebd..7d35c01ce3 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -1,27 +1,15 @@ -THIS DOCUMENT IS OBSOLETE! - -Please see The new [Level 1 MVP Proposal] instead. - -[Level 1 MVP Proposal]: https://github.com/WebAssembly/exception-handling/blob/master/proposals/Level-1.md - -The original proposal is preserved here for reference. - # Exception handling -There are four sections to this proposal - -1. A overview of the proposed extension to WebAssembly - -1. Changes to the text format document. - -1. Changes to the Modules document. - -1. Changes of the WebAssembly Binary Design document. +So far there have been two proposals ([first proposal](old/Exceptions.md), +[second proposal](old/Level-1.md)) proposed. We are going to use the second +proposal for the binary section spec, but we have not decided on which one to +use for the instruction part of the spec. This document describes status quo of +the exception handling proposal: for some parts we present both candidate +options until we fully decide. -The proposal here is also meant to be a minimal proposal that may be further -extended sometime in the future. +--- -## Overview +## First Proposal - Instruction Part Exception handling allows code to break control flow when an exception is thrown. The exception can be an exception known by the WebAssembly module, or it @@ -34,7 +22,7 @@ Thrown exceptions are handled as follows: 1. Throws not caught within a function body continue up the call stack until an enclosing try block is found. - + 1. If the call stack is exhausted without any enclosing try blocks, it terminates the application. @@ -55,9 +43,8 @@ by a new _exception_ section of a WebAssembly module. The exception section is a list of exceptions. Each exception has a _type signature_. The type signature defines the list of values associated with an exception. -Within the module, exceptions are identified by an index into -the [exception index space](#exception-index-space). This index is referred to -as the _exception tag_. +Within the module, exceptions are identified by an index into the [exception +index space](#exception-index-space). This index references an _exception tag_. Exceptions can be imported and exported by adding the appropriate entries to the import and export sections of the module. All imported/exported exceptions must @@ -76,7 +63,7 @@ but the data of the exception can't be accessed. ### Try and catch blocks. A _try_ block defines a list of instructions that may need to catch exceptions -and/or clean up state when an exception is thrown. Like other higher-level +and/or clean up state when an exception is thrown. Like other higher-level constructs, a try block begins with a `try` instruction, and ends with an `end` instruction. That is, a try block is sequence of instructions having the following form: @@ -113,10 +100,10 @@ corresponding exception tag. Catch blocks that begin with a `catch` instruction are considered _tagged_ catch blocks. The last catch block of an exception can be a tagged catch block. Alternatively, -it can begin with the `catch_all` instruction. If it begins with the -`catch_all` instruction, it defines the _default_ catch block. The default -catch block has no exception type, and is used to catch all exceptions not -caught by any of the tagged catch blocks. +it can begin with the `catch_all` instruction. If it begins with the `catch_all` +instruction, it defines the _default_ catch block. The default catch block has +no exception type, and is used to catch all exceptions not caught by any of the +tagged catch blocks. Try blocks, like control-flow blocks, have a _block type_. The block type of a try block defines the values yielded by the evaluation the try block when either @@ -128,14 +115,14 @@ In the initial implementation, try blocks may only yield 0 or 1 values. ### Throws -The `throw` instruction has a single immediate argument, an exception tag. The +The `throw` instruction has a single immediate argument, an exception tag. The exception tag is used to define the data fields of the allocated exception. The values for the data fields must be on top of the operand stack, and must correspond to the exception type signature for the exception. When an exception is thrown, the exception is allocated and the values on the stack (corresponding to the type signature) are popped off and assigned to the -allocated exception. The exception is stored internally for access when the +allocated exception. The exception is stored internally for access when the exception is caught. The runtime then searches for nearest enclosing try block body that execution is in. That try block is called the _catching_ try block. @@ -152,18 +139,18 @@ A throw inside a the body of a catch block is never caught by the corresponding try block of the catch block, since instructions in the body of the catch block are not in the body of the try block. -Once a catching try block is found for the throw, the operand stack is popped back -to the size the operand stack had when the try block was entered. Then, tagged -catch blocks are tried in the order they appear in the catching try block, until -one matches. +Once a catching try block is found for the throw, the operand stack is popped +back to the size the operand stack had when the try block was entered. Then, +tagged catch blocks are tried in the order they appear in the catching try +block, until one matches. If a matched tagged catch block is found, control is transferred to the body of the catch block, and the data fields of the exception are pushed back onto the stack. -Otherwise, control is transferred to the body of the default catch -block. However, unlike tagged catch blocks, the constructor arguments are not -copied back onto the operand stack. +Otherwise, control is transferred to the body of the default catch block. +However, unlike tagged catch blocks, the constructor arguments are not copied +back onto the operand stack. If no tagged catch blocks were matched, and the catching try block doesn't have a default catch block, the exception is rethrown to the next enclosing try @@ -182,7 +169,7 @@ also be sure to also pop off the caught exception values. ### Rethrows -The `rethrow` instruction can only appear in the body of a catch block. The +The `rethrow` instruction can only appear in the body of a catch block. The `rethrow` instruction always re-throws the exception caught by an enclosing catch block. This allows the catch block to clean up state before the exception is passed back to the next enclosing try block. @@ -219,10 +206,10 @@ end ``` In this example, `N` is used to disambiguate which caught exception is being -rethrown. It could rethrow any of the three caught expceptions. Hence, -`rethrow 0` corresponds to the exception caught by `catch 3`, `rethrow 1` -corresponds to the exception caught by `catch 2`, and `rethrow 3` corresponds -to the exception caught by `catch 1`. +rethrown. It could rethrow any of the three caught expceptions. Hence, `rethrow +0` corresponds to the exception caught by `catch 3`, `rethrow 1` corresponds to +the exception caught by `catch 2`, and `rethrow 3` corresponds to the exception +caught by `catch 1`. Note that `rethrow 2` is not allowed because it does not reference a `try` instruction. Rather, it references a `block` instruction. @@ -233,14 +220,14 @@ Earlier discussion implied that when an exception is thrown, the runtime will pop the operand stack across function calls until a corresponding, enclosing try block is found. The implementation may actually not do this. Rather, it may first search up the call stack to see if there is an enclosing try. If none are -found, it could terminate the thread at the point of the throw. This would -allow better debugging capability, since the corresponding call stack is still -there to query. +found, it could terminate the thread at the point of the throw. This would allow +better debugging capability, since the corresponding call stack is still there +to query. ## Changes to the text format. -This section describes change in the -[instruction syntax document](https://github.com/WebAssembly/spec/blob/master/document/text/instructions.rst). +This section describes change in the [instruction syntax +document](https://github.com/WebAssembly/spec/blob/master/document/text/instructions.rst). ### Control Instructions @@ -252,7 +239,7 @@ instructions ::= try resulttype instr* catch+ end | throw except_index | rethrow label - + catch ::= catch except_index inst* | catch_all inst* @@ -262,130 +249,474 @@ Like the `block`, `loop`, and `if` instructions, the `try` instruction is a *structured* instruction, and is implicitly labeled. This allows branch instructions to exit try blocks. -The `except_index` of the `catch` instruction is the exception tag for the caught -exception. Similarly, the `except_index` of the `throw` instruction is the tag for -the constructed exception. See [exception index space](#exception-index-space) -for further clarification of exception tags. +The `except_index` of the `catch` instruction denotes the exception tag for the +caught exception. Similarly, the `except_index` of the `throw` instruction +denotes the tag for the constructed exception. See [exception index +space](#exception-index-space) for further clarification of exception tags. The `label` of the `rethrow` instruction is the label to the corresponding try block, defining the catch to rethrow. +## Changes to the binary model + +This section describes changes in the [binary encoding design +document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md). + +### Control flow operators + +The control flow operators are extended to define try blocks, catch blocks, +throws, and rethrows as follows: + +| Name | Opcode | Immediates | Description | +| ---- | ---- | ---- | ---- | +| `unreachable` | `0x00` | | trap immediately | +| `nop` | `0x01` | | no operation | +| `block` | `0x02` | sig : `block_type` | begin a sequence of expressions, yielding 0 or 1 values | +| `loop` | `0x03` | sig : `block_type` | begin a block which can also form control flow loops | +| `if` | `0x04` | sig : `block_type` | begin if expression | +| `else` | `0x05` | | begin else expression of if or try | +| `try` | `0x06` | sig : `block_type` | begins a block which can handle thrown exceptions | +| `catch` | `0x07` | tag : `varuint32` | begins a block when the exception `tag` is caught | +| `throw` | `0x08` | tag : `varuint32` | Throws an exception defined by the exception `tag` | +| `rethrow` | `0x09` | relative_depth : `varuint32` | re-throws the exception caught by the corresponding try block | +| `end` | `0x0b` | | end a block, loop, if, and try | +| `br` | `0x0c` | relative_depth : `varuint32` | break that targets an outer nested block | +| `br_if` | `0x0d` | relative_depth : `varuint32` | conditional break that targets an outer nested block | +| `br_table` | `0x0e` | see below | branch table control flow construct | +| `return` | `0x0f` | | return zero or one value from this function | + +The *sig* fields of `block`, `if`, and `try` operators are block signatures +which describe their use of the operand stack. + +Note that the textual `catch_all` instruction is implemented using the `else` +operator. Since the `else` operator is always unambiguous in the binary format, +there is no need to tie up a separate opcode for the `catch_all` instruction. + + +--- + +## Second Proposal - Instruction Part + +Exception handling allows code to break control flow when an exception is +thrown. The exception can be any exception known by the WebAssembly module, or +it may an unknown exception that was thrown by a called imported function. + +One of the problems with exception handling is that both WebAssembly and an +embedder have different notions of what exceptions are, but both must be aware +of the other. + +It is difficult to define exceptions in WebAssembly because (in general) it +doesn't have knowledge of any embedder. Further, adding such knowledge to +WebAssembly would limit the ability for other embedders to support WebAssembly +exceptions. + +One issue is that both sides need to know if an exception was thrown by the +other, because cleanup may need to be performed. + +Another problem is that WebAssembly doesn't have direct access to an embedder's +memory. As a result, WebAssembly defers the handling of exceptions to the host +VM. + +To access exceptions, WebAssembly provides instructions to check if the +exception is one that WebAssembly understands. If so, the data of the +WebAssembly exception is extracted and copied onto the stack, allowing +succeeding instructions to process the data. + +Lastly, exception lifetimes may be maintained by the embedder, so that it can +collect and reuse the memory used by exceptions. This implies that an embedder +needs to know where exceptions are stored, so that it can determine when an +exception can be garbage collected. + +This also implies that that embedders must provide a garbage collector for +exceptions. For embedders that have garbage collection (such as JavaScript), +this is not a problem. + +However, not all embedders may have a garbage collector. For this reason, +WebAssembly exceptions are designed to allow other storage management methods, +such as reference counting, to perform the garbage collection in the embedder. + +To do this, WebAssembly exceptions are immutable once created, to avoid cyclic +data structures that cannot easily be reference-counted. It also means that +exceptions can't be stored into linear memory. The rationale for this is +twofold: + +* For security. Loads and stores do not guarantee that the data read was of the + same type as stored. This allows spoofing of exception references that may + allow a WebAssembly module to access data it should not know in the host VM. + +* The embedder does not know the layout of data in linear memory, so it can't + find places where exception references are stored. + +Hence, while an exception reference is a new first class type, this proposal +disallows their usage in linear memory. The exception reference type can be +represented as a subtype of `anyref` type introduced in [WebAssembly reference +type +proposal](https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md). + +A WebAssembly exception is created when you throw it with the `throw` +instruction. Thrown exceptions are handled as follows: + +1. They can be caught by a catch block in an enclosing try block of a function + body. The caught exception is pushed onto the stack. + +1. Throws not caught within a function body continue up the call stack, popping + call frames, until an enclosing try block is found. + +1. If the call stack is exhausted without any enclosing try blocks, the embedder + defines how to handle the uncaught exception. + +### Event handling + +This proposal adds exception handling to WebAssembly. Part of this proposal is +to define a new section to declare exceptions. However, rather than limiting +this new section to just defining exceptions, it defines a more general format +that allows the declaration of other forms of events. + +In general, an event handler allows one to process an event generated by a block +of code. Events suspend the current execution and look for a corresponding event +handler. If found, the corresponding event handler is run. Some event handlers +may send values back to the suspended instruction, allowing the originating code +to resume. + +Exceptions are a special case of an event in that they never resume. Similarly, +a throw instruction is the suspending event of an exception. The catch block +associated with a try block defines how to handle the throw. + +WebAssembly events (i.e. exceptions) are defined by a new `event` section of a +WebAssembly module. The event section is a list of declared events associated +with the module. + +Each event has an `attribute` and a `type`. Currently, the attribute can only +specify that the event is an exception. In the future, additional attribute +values may be added when other events are added to WebAssembly. + +The type of an event is denoted by an index to a function signature defined in +the `type` section. The parameters of the function signature defines the list of +values associated with the exception event. The result type must be 'void'. + +An `event tag` is a value to distinguish different events, while an `event +index` is a numeric name to refer to an (imported or defined) event tag within a +module (see [event index space](#event-index-space) for details). + +### Exceptions + +An `exception` is an internal construct in WebAssembly . WebAssembly exceptions +are defined in the `event` and import sections of a module. Each event (with an +exception attribute) defines an `exception`. The event index is also called the +`exception index`. Similarly, the corresponding event tag is called an +`exception tag`. + +Exception indices are used by: + +1. The `throw` instruction which creates a WebAssembly exception with the + corresponding exception tag, and then throws it. + +2. The `if_except` instruction queries an exception to see if the corresponding + exception tag denoted by the exception index. If true it pushes the + corresponding values of the exception onto the stack. + +### The exception reference data type + +Data types are extended to have a new `except_ref` type, that refers to an +exception. The representation of an exception is left to the implementation. + +### Try and catch blocks + +A _try block_ defines a list of instructions that may need to process exceptions +and/or clean up state when an exception is thrown. Like other higher-level +constructs, a try block begins with a `try` instruction, and ends with an `end` +instruction. That is, a try block is sequence of instructions having the +following form: + +``` +try block_type + instruction* +catch + instruction* +end +``` + +A try block ends with a `catch block` that is defined by the list of +instructions after the `catch` instruction. + +Try blocks, like control-flow blocks, have a _block type_. The block type of a +try block defines the values yielded by the evaluation the try block when either +no exception is thrown, or the exception is successfully caught by the catch +block. + +In the initial implementation, try blocks may only yield 0 or 1 values. + +### Throwing an exception + +The `throw` instruction takes an exception index as an immediate argument. That +index is used to identify the exception tag to use to create and throw the +corresponding exception. + +The values on top of the stack must correspond to the type associated with the +exception. These values are popped of the stack and are used (along with the +corresponding exception tag) to create the corresponding exception. That +exception is then thrown. + +When an exception is thrown, the embedder searches for the nearest enclosing try +block body that execution is in. That try block is called the _catching_ try +block. + +If the throw appears within the body of a try block, it is the catching try +block. + +If a throw occurs within a function body, and it doesn't appear inside the body +of a try block, the throw continues up the call stack until it is in the body of +an an enclosing try block, or the call stack is flushed. If the call stack is +flushed, the embedder defines how to handle uncaught exceptions. Otherwise, the +found enclosing try block is the catching try block. + +A throw inside the body of a catch block is never caught by the corresponding +try block of the catch block, since instructions in the body of the catch block +are not in the body of the try block. + +Once a catching try block is found for the thrown exception, the operand stack +is popped back to the size the operand stack had when the try block was entered, +and then an except_ref referring to the caught exception is pushed back onto the +operand stack. + +If control is transferred to the body of a catch block, and the last instruction +in the body is executed, control then exits the try block. + +If the selected catch block does not throw an exception, it must yield the +value(s) expected by the corresponding catching try block. This includes popping +the caught exception. + +Note that a caught exception can be rethrown using the `rethrow` instruction. + +### Rethrowing an exception + +The `rethrow` instruction takes the exception associated with the `except_ref` +on top of the stack, and rethrows the exception. A rethrow has the same effect +as a throw, other than an exception is not created. Rather, the referenced +exception on top of the stack is popped and then thrown. + +### Exception data extraction + +The `if_except` block begins with an `if_except` instruction, and has two +instruction blocks, + +That is, the forms of an if_except block is: + +``` +if_except block_type except_index + Instruction* +end + +if_except block_type except_index + Instruction* +else + Instruction* +end +``` + +In the first form, the instructions between the `if_except` and 'end' define the +`then block`. In the second form, the instructions between the `if_except` and +`else` define the `then block`, while the instructions between the `else` and +the `end` define the `else block`. + +The conditional query of an exception checks the exception tag of exception on +top of the stack. It succeeds only if the exception index of the instruction +matches the corresponding exception tag. Once the query completes, the exception +is popped off the stack. + +If the query succeeds the values (associated with the popped exception) are +extracted and pushed onto the stack, and control transfers to the instructions +in the then block. + +If the query fails, it either enters the else block, or transfer control to the +end of the if_except block if there is no else block. + +### Stack traces + +When an exception is thrown, the runtime will pop the stack across function +calls until a corresponding, enclosing try block is found. It may also associate +a stack trace that can be used to report uncaught exceptions. However, the +details of this is left to the embedder. + +## Changes to the text format. + +This section describes change in the [instruction syntax +document](https://github.com/WebAssembly/spec/blob/master/document/core/instructions.rst). + +### New instructions + +The following rules are added to *instructions*: + +``` + try resulttype instruction* catch instruction* end | + throw except_index | + rethrow | + if_except resulttype except_index then instruction* end | + if_except resulttype except_index then instruction* else instruction* end +``` + +Like the `block`, `loop`, and `if` instructions, the `try` and `if_except` +instructions are *structured* control flow instructions, and can be labeled. +This allows branch instructions to exit try and `if_except` blocks. + +The `except_index` of the `throw` and `if_except` instructions defines the +exception (and hence, exception tag) to create/extract from. See [exception +index space](#exception-index-space) for further clarification of exception +tags. + +## Changes to the binary model + +This section describes changes in the [binary encoding design +document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md). + +### Data Types + +#### except_ref + +An exception reference points to an exception. + +### Language Types + +| Opcode | Type constructor | +|--------|------------------| +| -0x18 | `except_ref` | + +#### value_type + +A `varint7` indicating a `value_type` is extended to include `except_ref` as +encoded above. + +### Control flow operators + +The control flow operators are extended to define try blocks, catch blocks, +throws, and rethrows as follows: + +| Name | Opcode | Immediates | Description | +| ---- | ---- | ---- | ---- | +| `try` | `0x06` | sig : `block_type` | begins a block which can handle thrown exceptions | +| `catch` | `0x07` | | begins the catch block of the try block | +| `throw` | `0x08` | index : `varint32` | Creates an exception defined by the exception `index`and then throws it | +| `rethrow` | `0x09` | | Pops the `except_ref` on top of the stack and throws it | +| `if_except` | `0x0a` | index : `varuint32`, sig : `block_type` | Begin exception data extraction if exception on stack was created using the corresponding exception `index` | + +The *sig* fields of `block`, `if`, `try` and `if_except` operators are block +signatures which describe their use of the operand stack. + + +--- + +## Common part + +This part describes changes to the module and binary model. This part comes from +the [second proposal](old/Level-1.md) and we are going to use it for this part. + ## Changes to Modules document. -This section describes change in the -[Modules document](https://github.com/WebAssembly/design/blob/master/Modules.md). +This section describes change in the [Modules +document](https://github.com/WebAssembly/design/blob/master/Modules.md). -#### Exception index space +### Event index space -The _exception index space_ indexes all imported and internally-defined -exceptions, assigning monotonically-increasing indices based on the order -defined in the import and exception sections. Thus, the index space starts at -zero with imported exceptions followed by internally-defined exceptions in -the [exception section](#exception-section). +The `event index space` indexes all imported and internally-defined events, +assigning monotonically-increasing indices based on the order defined in the +import and event sections. Thus, the index space starts at zero with imported +events, followed by internally-defined events in the [event +section](#event-section). + +The event index space defines the (module) static version of runtine event tags. +For event indices that are not imported/exported, the corresponding event tag is +guaranteed to be unique over all loaded modules. Events that are imported or +exported alias the respective events defined elsewhere, and use the same tag. ## Changes to the binary model -This section describes changes in -the -[binary encoding design document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md). +This section describes changes in the [binary encoding design +document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md). + +#### Other Types + +##### event_type + +The set of event attributes are: -### except_type +| Name | Value | +|-----------|-------| +| Exception | 0 | -An exception is described by its exception type signature, which corresponds to -the data fields of the exception. +Each event type has the fields: | Field | Type | Description | |-------|------|-------------| -| `count` | `varuint32` | The number of types in the signature | -| `type` | `value_type*` | The type of each element in the signature | +| `attribute` | `varuint32` | The attribute of the event. | +| `type` | `varuint32` | The type index for its corresponding type signature | -### External kind - -`external_kind` +##### external_kind A single-byte unsigned integer indicating the kind of definition being imported or defined: -* `0` indicating a `Function` [import](Modules.md#imports) or [definition](Modules.md#function-and-code-sections) -* `1` indicating a `Table` [import](Modules.md#imports) or [definition](Modules.md#table-section) -* `2` indicating a `Memory` [import](Modules.md#imports) or [definition](Modules.md#linear-memory-section) -* `3` indicating a `Global` [import](Modules.md#imports) or [definition](Modules.md#global-section) -* `4` indicating an `Exception` [import](#import-section) or [definition](#exception-sectio) +* `0` indicating a `Function` [import](Modules.md#imports) or +[definition](Modules.md#function-and-code-sections) +* `1` indicating a `Table` [import](Modules.md#imports) or +[definition](Modules.md#table-section) +* `2` indicating a `Memory` [import](Modules.md#imports) or +[definition](Modules.md#linear-memory-section) +* `3` indicating a `Global` [import](Modules.md#imports) or +[definition](Modules.md#global-section) +* `4` indicating an `Event` [import](#import-section) or +[definition](#event-section) + +### Module structure + +#### High-level structure -### Exception section +A new `event` section is introduced and is named `event`. If included, it must +appear immediately after the global section. -The `exception` section is the named section 'exception'. The exception section -declares exception types using exception type signatures. +##### Event section + +The `event` section is the named section 'event'. The event section declares a +list of event types as follows: | Field | Type | Description | |-------|------|-------------| -| count | `varuint32` | count of the number of exceptions to follow | -| sig | `except_type*` | The type signature of the data fields for each exception | +| count | `varuint32` | count of the number of events to follow | +| type | `except_type*` | The definitions of the event types | -### Import section +##### Import section -The import section is extended to include exception types by extending an +The import section is extended to include event definitions by extending an `import_entry` as follows: -If the `kind` is `Exception`: +If the `kind` is `Event`: | Field | Type | Description | |-------|------|-------------| -| `sig` | `except_type` | the type signature of the exception | +| `type` | `event_type` | the event being imported | -### Export section +##### Export section -The export section is extended to include exception types by extending an +The export section is extended to reference event types by extending an `export_entry` as follows: -If the `kind` is `Exception`, then the `index` is into the corresponding -exception in the [exception index space](#exception-index-space). +If the `kind` is `Event`: + +| Field | Type | Description | +|-------|------|-------------| +| `index` | `varuint32` | the index into the corresponding event index space | -### Name section +##### Name section The set of known values for `name_type` of a name section is extended as follows: - | Name Type | Code | Description | | --------- | ---- | ----------- | | [Function](#function-names) | `1` | Assigns names to functions | | [Local](#local-names) | `2` | Assigns names to locals in functions | -| [Exception](#exception-names) | `3` | Assigns names to exception types | - -### Exception names +| [Event](#event-names) | `3` | Assigns names to event types | -The exception names subsection is a `name_map` which assigns names to a subset -of the _exception_ indices from the exception section. (Used for both imports -and module-defined). - -### Control flow operators - -The control flow operators are extended to define try blocks, catch blocks, -throws, and rethrows as follows: - -| Name | Opcode | Immediates | Description | -| ---- | ---- | ---- | ---- | -| `unreachable` | `0x00` | | trap immediately | -| `nop` | `0x01` | | no operation | -| `block` | `0x02` | sig : `block_type` | begin a sequence of expressions, yielding 0 or 1 values | -| `loop` | `0x03` | sig : `block_type` | begin a block which can also form control flow loops | -| `if` | `0x04` | sig : `block_type` | begin if expression | -| `else` | `0x05` | | begin else expression of if or try | -| `try` | `0x06` | sig : `block_type` | begins a block which can handle thrown exceptions | -| `catch` | `0x07` | tag : `varuint32` | begins a block when the exception `tag` is thrown | -| `throw` | `0x08` | tag : `varuint32` | Throws an exception defined by the exception `tag` | -| `rethrow` | `0x09` | relative_depth : `varuint32` | re-throws the exception caught by the corresponding try block | -| `end` | `0x0b` | | end a block, loop, if, and try | -| `br` | `0x0c` | relative_depth : `varuint32` | break that targets an outer nested block | -| `br_if` | `0x0d` | relative_depth : `varuint32` | conditional break that targets an outer nested block | -| `br_table` | `0x0e` | see below | branch table control flow construct | -| `return` | `0x0f` | | return zero or one value from this function | - -The *sig* fields of `block`, `if`, and `try` operators are block signatures -which describe their use of the operand stack. +###### Event names -Note that the textual `catch_all` instruction is implemented using the -`else` operator. Since the `else` operator is always unambiguous in the binary -format, there is no need to tie up a separate opcode for the `catch_all` -instruction. +The event names subsection is a `name_map` which assigns names to a subset of +the event indices (Used for both imports and module-defined). diff --git a/proposals/old/Exceptions.md b/proposals/old/Exceptions.md new file mode 100644 index 0000000000..d234b3cebd --- /dev/null +++ b/proposals/old/Exceptions.md @@ -0,0 +1,391 @@ +THIS DOCUMENT IS OBSOLETE! + +Please see The new [Level 1 MVP Proposal] instead. + +[Level 1 MVP Proposal]: https://github.com/WebAssembly/exception-handling/blob/master/proposals/Level-1.md + +The original proposal is preserved here for reference. + +# Exception handling + +There are four sections to this proposal + +1. A overview of the proposed extension to WebAssembly + +1. Changes to the text format document. + +1. Changes to the Modules document. + +1. Changes of the WebAssembly Binary Design document. + +The proposal here is also meant to be a minimal proposal that may be further +extended sometime in the future. + +## Overview + +Exception handling allows code to break control flow when an exception is +thrown. The exception can be an exception known by the WebAssembly module, or it +may be an unknown exception thrown by an imported call. + +Thrown exceptions are handled as follows: + +1. They can be caught by a catch block in an enclosing try block of a function + body. + +1. Throws not caught within a function body continue up the call stack until an + enclosing try block is found. + +1. If the call stack is exhausted without any enclosing try blocks, it + terminates the application. + +This proposal looks at the changes needed to incorporate these concepts into the +portable binary encoding of WebAssembly modules. + +At the specification level, these changes do not infer whether an implementation +must implement lightweight or heavyweight exceptions. Rather, it defers that +choice to the runtime implementation. + +Exception handling is defined using *exceptions*, *try blocks*, *catch blocks*, +and the instructions `throw` and `rethrow`. + +### Exceptions + +An _exception_ is an internal construct in WebAssembly. Exceptions are defined +by a new _exception_ section of a WebAssembly module. The exception section is a +list of exceptions. Each exception has a _type signature_. The type signature +defines the list of values associated with an exception. + +Within the module, exceptions are identified by an index into +the [exception index space](#exception-index-space). This index is referred to +as the _exception tag_. + +Exceptions can be imported and exported by adding the appropriate entries to the +import and export sections of the module. All imported/exported exceptions must +be named to reconcile exception tags between modules. + +Exception tags are used by throw and catch instructions. The throw instruction +uses the tag to allocate the exception with the corresponding data fields +defined by the exception's type signature. The catch instruction uses the tag to +identify if the thrown exception is one it can catch. + +Exceptions can also be thrown by called, imported functions. If it corresponds +to an imported exception, it can be caught by an appropriate catch instruction. +If the exception is not imported, it still can be caught to allow code clean-up, +but the data of the exception can't be accessed. + +### Try and catch blocks. + +A _try_ block defines a list of instructions that may need to catch exceptions +and/or clean up state when an exception is thrown. Like other higher-level +constructs, a try block begins with a `try` instruction, and ends with an `end` +instruction. That is, a try block is sequence of instructions having the +following form: + +``` +try + instruction* +catch i + instruction* +catch j + instruction* +... +catch n + instruction* +catch_all + instruction* +end +``` + +A try block also contains one or more catch blocks, and all but the last catch +block must begin with a`catch` instruction. The last catch block can begin with +either a `catch` or `catch_all` instruction. The `catch`/`catch_all` +instructions (within the try construct) are called the _catching_ instructions. + +The _body_ of the try block is the list of instructions before the first +catching instruction. The _body_ of each catch block is the sequence of +instructions following the corresponding catching instruction, and the next +catching instruction (or the `end` instruction if it is the last catching +block). + +The `catch` instruction has an exception tag associated with it. The tag +identifies what exceptions it can catch. That is, any exception created with the +corresponding exception tag. Catch blocks that begin with a `catch` instruction +are considered _tagged_ catch blocks. + +The last catch block of an exception can be a tagged catch block. Alternatively, +it can begin with the `catch_all` instruction. If it begins with the +`catch_all` instruction, it defines the _default_ catch block. The default +catch block has no exception type, and is used to catch all exceptions not +caught by any of the tagged catch blocks. + +Try blocks, like control-flow blocks, have a _block type_. The block type of a +try block defines the values yielded by the evaluation the try block when either +no exception is thrown, or the exception is successfully caught by one of its +catch blocks, and the instructions within the catch block can recover from the +throw. + +In the initial implementation, try blocks may only yield 0 or 1 values. + +### Throws + +The `throw` instruction has a single immediate argument, an exception tag. The +exception tag is used to define the data fields of the allocated exception. The +values for the data fields must be on top of the operand stack, and must +correspond to the exception type signature for the exception. + +When an exception is thrown, the exception is allocated and the values on the +stack (corresponding to the type signature) are popped off and assigned to the +allocated exception. The exception is stored internally for access when the +exception is caught. The runtime then searches for nearest enclosing try block +body that execution is in. That try block is called the _catching_ try block. + +If the throw appears within the body of a try block, it is the catching try +block. + +If a throw occurs within a function body, and it doesn't appear inside the body +of a try block, the throw continues up the call stack until it is in the body of +an an enclosing try block, or the call stack is flushed. If the call stack is +flushed, execution is terminated. Otherwise, the found enclosing try block is +the catching try block. + +A throw inside a the body of a catch block is never caught by the corresponding +try block of the catch block, since instructions in the body of the catch block +are not in the body of the try block. + +Once a catching try block is found for the throw, the operand stack is popped back +to the size the operand stack had when the try block was entered. Then, tagged +catch blocks are tried in the order they appear in the catching try block, until +one matches. + +If a matched tagged catch block is found, control is transferred to the body of +the catch block, and the data fields of the exception are pushed back onto the +stack. + +Otherwise, control is transferred to the body of the default catch +block. However, unlike tagged catch blocks, the constructor arguments are not +copied back onto the operand stack. + +If no tagged catch blocks were matched, and the catching try block doesn't have +a default catch block, the exception is rethrown to the next enclosing try +block. + +If control is transferred to the body of a catch block, and the last instruction +in the body is executed, control then exits the try block. + +Also note that when the thrown exception is caught by a catch block, it is not +destroyed until the catch block is exited. This is done so that the catch block +can rethrow the exception. + +If the selected catch block does not rethrow an exception, it must yield the +value(s) expected by the enclosing try block. For tagged catch blocks, they must +also be sure to also pop off the caught exception values. + +### Rethrows + +The `rethrow` instruction can only appear in the body of a catch block. The +`rethrow` instruction always re-throws the exception caught by an enclosing +catch block. This allows the catch block to clean up state before the exception +is passed back to the next enclosing try block. + +Associated with the `rethrow` instruction is a _label_. The label is used to +disambiguate which exception is to be rethrown, when inside nested catch blocks. + +The label is the relative block depth to the corresponding try block for which +the catching block appears. + +For example consider the following: + +``` +try + ... +catch 1 + ... + block + ... + try + ... + catch 2 + ... + try + ... + catch 3 + ... + rethrow N + end + end + end + ... +end +``` + +In this example, `N` is used to disambiguate which caught exception is being +rethrown. It could rethrow any of the three caught expceptions. Hence, +`rethrow 0` corresponds to the exception caught by `catch 3`, `rethrow 1` +corresponds to the exception caught by `catch 2`, and `rethrow 3` corresponds +to the exception caught by `catch 1`. + +Note that `rethrow 2` is not allowed because it does not reference a `try` +instruction. Rather, it references a `block` instruction. + +### Debugging + +Earlier discussion implied that when an exception is thrown, the runtime will +pop the operand stack across function calls until a corresponding, enclosing try +block is found. The implementation may actually not do this. Rather, it may +first search up the call stack to see if there is an enclosing try. If none are +found, it could terminate the thread at the point of the throw. This would +allow better debugging capability, since the corresponding call stack is still +there to query. + +## Changes to the text format. + +This section describes change in the +[instruction syntax document](https://github.com/WebAssembly/spec/blob/master/document/text/instructions.rst). + +### Control Instructions + +The following rule is added to *instructions*: + +``` +instructions ::= + ... + try resulttype instr* catch+ end | + throw except_index | + rethrow label + +catch ::= + catch except_index inst* | + catch_all inst* +``` + +Like the `block`, `loop`, and `if` instructions, the `try` instruction is a +*structured* instruction, and is implicitly labeled. This allows branch +instructions to exit try blocks. + +The `except_index` of the `catch` instruction is the exception tag for the caught +exception. Similarly, the `except_index` of the `throw` instruction is the tag for +the constructed exception. See [exception index space](#exception-index-space) +for further clarification of exception tags. + +The `label` of the `rethrow` instruction is the label to the corresponding try +block, defining the catch to rethrow. + +## Changes to Modules document. + +This section describes change in the +[Modules document](https://github.com/WebAssembly/design/blob/master/Modules.md). + +#### Exception index space + +The _exception index space_ indexes all imported and internally-defined +exceptions, assigning monotonically-increasing indices based on the order +defined in the import and exception sections. Thus, the index space starts at +zero with imported exceptions followed by internally-defined exceptions in +the [exception section](#exception-section). + +## Changes to the binary model + +This section describes changes in +the +[binary encoding design document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md). + +### except_type + +An exception is described by its exception type signature, which corresponds to +the data fields of the exception. + +| Field | Type | Description | +|-------|------|-------------| +| `count` | `varuint32` | The number of types in the signature | +| `type` | `value_type*` | The type of each element in the signature | + +### External kind + +`external_kind` + +A single-byte unsigned integer indicating the kind of definition being imported +or defined: + +* `0` indicating a `Function` [import](Modules.md#imports) or [definition](Modules.md#function-and-code-sections) +* `1` indicating a `Table` [import](Modules.md#imports) or [definition](Modules.md#table-section) +* `2` indicating a `Memory` [import](Modules.md#imports) or [definition](Modules.md#linear-memory-section) +* `3` indicating a `Global` [import](Modules.md#imports) or [definition](Modules.md#global-section) +* `4` indicating an `Exception` [import](#import-section) or [definition](#exception-sectio) + +### Exception section + +The `exception` section is the named section 'exception'. The exception section +declares exception types using exception type signatures. + +| Field | Type | Description | +|-------|------|-------------| +| count | `varuint32` | count of the number of exceptions to follow | +| sig | `except_type*` | The type signature of the data fields for each exception | + +### Import section + +The import section is extended to include exception types by extending an +`import_entry` as follows: + +If the `kind` is `Exception`: + +| Field | Type | Description | +|-------|------|-------------| +| `sig` | `except_type` | the type signature of the exception | + +### Export section + +The export section is extended to include exception types by extending an +`export_entry` as follows: + +If the `kind` is `Exception`, then the `index` is into the corresponding +exception in the [exception index space](#exception-index-space). + +### Name section + +The set of known values for `name_type` of a name section is extended as +follows: + + +| Name Type | Code | Description | +| --------- | ---- | ----------- | +| [Function](#function-names) | `1` | Assigns names to functions | +| [Local](#local-names) | `2` | Assigns names to locals in functions | +| [Exception](#exception-names) | `3` | Assigns names to exception types | + +### Exception names + +The exception names subsection is a `name_map` which assigns names to a subset +of the _exception_ indices from the exception section. (Used for both imports +and module-defined). + +### Control flow operators + +The control flow operators are extended to define try blocks, catch blocks, +throws, and rethrows as follows: + +| Name | Opcode | Immediates | Description | +| ---- | ---- | ---- | ---- | +| `unreachable` | `0x00` | | trap immediately | +| `nop` | `0x01` | | no operation | +| `block` | `0x02` | sig : `block_type` | begin a sequence of expressions, yielding 0 or 1 values | +| `loop` | `0x03` | sig : `block_type` | begin a block which can also form control flow loops | +| `if` | `0x04` | sig : `block_type` | begin if expression | +| `else` | `0x05` | | begin else expression of if or try | +| `try` | `0x06` | sig : `block_type` | begins a block which can handle thrown exceptions | +| `catch` | `0x07` | tag : `varuint32` | begins a block when the exception `tag` is thrown | +| `throw` | `0x08` | tag : `varuint32` | Throws an exception defined by the exception `tag` | +| `rethrow` | `0x09` | relative_depth : `varuint32` | re-throws the exception caught by the corresponding try block | +| `end` | `0x0b` | | end a block, loop, if, and try | +| `br` | `0x0c` | relative_depth : `varuint32` | break that targets an outer nested block | +| `br_if` | `0x0d` | relative_depth : `varuint32` | conditional break that targets an outer nested block | +| `br_table` | `0x0e` | see below | branch table control flow construct | +| `return` | `0x0f` | | return zero or one value from this function | + +The *sig* fields of `block`, `if`, and `try` operators are block signatures +which describe their use of the operand stack. + +Note that the textual `catch_all` instruction is implemented using the +`else` operator. Since the `else` operator is always unambiguous in the binary +format, there is no need to tie up a separate opcode for the `catch_all` +instruction. diff --git a/proposals/Level-1+N.md b/proposals/old/Level-1+N.md similarity index 100% rename from proposals/Level-1+N.md rename to proposals/old/Level-1+N.md diff --git a/proposals/Level-1.md b/proposals/old/Level-1.md similarity index 100% rename from proposals/Level-1.md rename to proposals/old/Level-1.md From 1cc5ba0070f5eacf27a2c5c9b84a2058dbba1582 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Wed, 24 Oct 2018 00:29:16 -0700 Subject: [PATCH 044/302] Specify a restriction on order of event section (#62) --- proposals/Exceptions.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index 7d35c01ce3..8e9ade624d 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -675,8 +675,12 @@ appear immediately after the global section. ##### Event section -The `event` section is the named section 'event'. The event section declares a -list of event types as follows: +The `event` section is the named section 'event'. For ease of validation, this +section comes after the [import +section(https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#import-section) +and before the [export +section](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#export-section). +The event section declares a list of event types as follows: | Field | Type | Description | |-------|------|-------------| From dda2d7be5554774fa5ca054c1452765d8fc35b95 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Wed, 24 Oct 2018 14:27:26 -0700 Subject: [PATCH 045/302] Add pros and cons of the two proposals (#63) --- proposals/Exceptions.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index 8e9ade624d..a576f4b03a 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -724,3 +724,30 @@ follows: The event names subsection is a `name_map` which assigns names to a subset of the event indices (Used for both imports and module-defined). + + +--- + +## Comparisons of the two proposals + +- Proposal 2 is more expressive and possibly provides more flexibility + for future frontend developers for other languages. + +- As Proposal 2 introduces first-class exception reference type, we have to + manage lifetime of exception objects, from which arises several questions. + - How do we manage exception objects' lifetime in non-GC embeddings? Do we + make reference counting mandatory? + - Who is responsible for deleting exception objects? + - What should we do for except_ref values of invalid exception objects already + deleted? + - How should exception reference type be related to the existing reference + type or GC proposal? + +- In Proposal 2, the unwinder must stop at every call stack frame with `catch` + instruction because the tag matching happens within a `catch` block, whereas + in Proposal 1 the unwinder does not need to stop at call stack frames that + do not contain `catch`s with the current exception's tag. Stopping at every + call frame might degrade performance. + +- It is suggested that Proposal 2 may be more compatible with effect handlers, + which can be might be added to wasm in the future. From ca408dcf52de22462e4e947dc8699acfce1d7b62 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Wed, 24 Oct 2018 14:46:13 -0700 Subject: [PATCH 046/302] Explain try blocks can be targeted from branches (#64) --- proposals/Exceptions.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index a576f4b03a..d05e5bda1d 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -109,7 +109,8 @@ Try blocks, like control-flow blocks, have a _block type_. The block type of a try block defines the values yielded by the evaluation the try block when either no exception is thrown, or the exception is successfully caught by one of its catch blocks, and the instructions within the catch block can recover from the -throw. +throw. Because `try` and `end` instructions define a control-flow block, they +can be targets for branches (`br` and `br_if`) as well. In the initial implementation, try blocks may only yield 0 or 1 values. @@ -443,6 +444,11 @@ Try blocks, like control-flow blocks, have a _block type_. The block type of a try block defines the values yielded by the evaluation the try block when either no exception is thrown, or the exception is successfully caught by the catch block. +Try blocks, like control-flow blocks, have a _block type_. The block type of a +try block defines the values yielded by the evaluation the try block when either +no exception is thrown, or the exception is successfully caught by the catch +block. Because `try` and `end` instructions define a control-flow block, they +can be targets for branches (`br` and `br_if`) as well. In the initial implementation, try blocks may only yield 0 or 1 values. From 51411c72a820e59f55197ff1af541574f8d51f8d Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Thu, 25 Oct 2018 18:06:56 -0700 Subject: [PATCH 047/302] Update comparison of the 2 proposals. (#65) --- proposals/Exceptions.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index d05e5bda1d..ff171acdb4 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -736,11 +736,8 @@ the event indices (Used for both imports and module-defined). ## Comparisons of the two proposals -- Proposal 2 is more expressive and possibly provides more flexibility - for future frontend developers for other languages. - -- As Proposal 2 introduces first-class exception reference type, we have to - manage lifetime of exception objects, from which arises several questions. +- Proposal 2 introduces a first-class exception reference type. This raises several + questions about exception lifetime management: - How do we manage exception objects' lifetime in non-GC embeddings? Do we make reference counting mandatory? - Who is responsible for deleting exception objects? @@ -748,6 +745,15 @@ the event indices (Used for both imports and module-defined). deleted? - How should exception reference type be related to the existing reference type or GC proposal? + + Consequently, Proposal 1 would be simpler to implement for VMs which do not need + reference types or related functionality such as GC objects. + +- The first-class exception type makes Proposal 2 more expressive, possibly providing + more flexibility for frontend developers for non-C langauges. In particular, allowing + exception objects to escape catch blocks may simplify control flow translation. + Conversely, it is slightly more complex for languages which do not have convenient ways to model + reference types. - In Proposal 2, the unwinder must stop at every call stack frame with `catch` instruction because the tag matching happens within a `catch` block, whereas From e07a4bf23d883f351474b5d6b2dd75635b85ea4b Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Fri, 26 Oct 2018 23:17:28 -0700 Subject: [PATCH 048/302] Add a missing ] in the document --- proposals/Exceptions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index ff171acdb4..87b18383f0 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -683,7 +683,7 @@ appear immediately after the global section. The `event` section is the named section 'event'. For ease of validation, this section comes after the [import -section(https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#import-section) +section](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#import-section) and before the [export section](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#export-section). The event section declares a list of event types as follows: From 417366dba914baf2748d998c496b5ff6014bdaf1 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Sun, 28 Oct 2018 03:35:37 -0700 Subject: [PATCH 049/302] Fix links in the documents in old/ directory --- proposals/old/Exceptions.md | 2 +- proposals/old/Level-1.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/old/Exceptions.md b/proposals/old/Exceptions.md index d234b3cebd..5a9fdc279b 100644 --- a/proposals/old/Exceptions.md +++ b/proposals/old/Exceptions.md @@ -2,7 +2,7 @@ THIS DOCUMENT IS OBSOLETE! Please see The new [Level 1 MVP Proposal] instead. -[Level 1 MVP Proposal]: https://github.com/WebAssembly/exception-handling/blob/master/proposals/Level-1.md +[Level 1 MVP Proposal]: https://github.com/WebAssembly/exception-handling/blob/master/proposals/old/Level-1.md The original proposal is preserved here for reference. diff --git a/proposals/old/Level-1.md b/proposals/old/Level-1.md index e2c829fbae..f0310cd676 100644 --- a/proposals/old/Level-1.md +++ b/proposals/old/Level-1.md @@ -12,7 +12,7 @@ levels, and either: This document supersedes the original [Exceptions Proposal]. -[Exceptions Proposal]: https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md +[Exceptions Proposal]: https://github.com/WebAssembly/exception-handling/blob/master/proposals/old/Exceptions.md ## Overview From 62240cbf66983282e3c9e3d5f3d3088cccfe224b Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Tue, 30 Oct 2018 02:43:23 -0700 Subject: [PATCH 050/302] Update Exceptions.md --- proposals/Exceptions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index 87b18383f0..028fb99339 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -691,7 +691,7 @@ The event section declares a list of event types as follows: | Field | Type | Description | |-------|------|-------------| | count | `varuint32` | count of the number of events to follow | -| type | `except_type*` | The definitions of the event types | +| type | `event_type*` | The definitions of the event types | ##### Import section From aacf0192d17afb4f3a5ea442bc20baf2a951c346 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Wed, 7 Nov 2018 11:58:32 -0800 Subject: [PATCH 051/302] Use the second proposal (#66) Now we have voted for the second proposal, change the document to represent the right one. --- proposals/Exceptions.md | 426 +++++----------------------------------- 1 file changed, 46 insertions(+), 380 deletions(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index 028fb99339..b324e76b02 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -1,302 +1,18 @@ # Exception handling -So far there have been two proposals ([first proposal](old/Exceptions.md), -[second proposal](old/Level-1.md)) proposed. We are going to use the second -proposal for the binary section spec, but we have not decided on which one to -use for the instruction part of the spec. This document describes status quo of -the exception handling proposal: for some parts we present both candidate -options until we fully decide. +There were two alternative proposals +([1st](https://github.com/WebAssembly/exception-handling/blob/master/proposals/old/Exceptions.md) +and +[2nd](https://github.com/WebAssembly/exception-handling/blob/master/proposals/old/Level-1.md)) +for the design of exception handling and we +[decided](https://github.com/WebAssembly/meetings/blob/master/2018/TPAC.md#exception-handling-ben-titzer) +on the second proposal, which uses first-class exception types, mainly based on +the reasoning that it is more expressive and also more extendible to other kinds +of events. --- -## First Proposal - Instruction Part - -Exception handling allows code to break control flow when an exception is -thrown. The exception can be an exception known by the WebAssembly module, or it -may be an unknown exception thrown by an imported call. - -Thrown exceptions are handled as follows: - -1. They can be caught by a catch block in an enclosing try block of a function - body. - -1. Throws not caught within a function body continue up the call stack until an - enclosing try block is found. - -1. If the call stack is exhausted without any enclosing try blocks, it - terminates the application. - -This proposal looks at the changes needed to incorporate these concepts into the -portable binary encoding of WebAssembly modules. - -At the specification level, these changes do not infer whether an implementation -must implement lightweight or heavyweight exceptions. Rather, it defers that -choice to the runtime implementation. - -Exception handling is defined using *exceptions*, *try blocks*, *catch blocks*, -and the instructions `throw` and `rethrow`. - -### Exceptions - -An _exception_ is an internal construct in WebAssembly. Exceptions are defined -by a new _exception_ section of a WebAssembly module. The exception section is a -list of exceptions. Each exception has a _type signature_. The type signature -defines the list of values associated with an exception. - -Within the module, exceptions are identified by an index into the [exception -index space](#exception-index-space). This index references an _exception tag_. - -Exceptions can be imported and exported by adding the appropriate entries to the -import and export sections of the module. All imported/exported exceptions must -be named to reconcile exception tags between modules. - -Exception tags are used by throw and catch instructions. The throw instruction -uses the tag to allocate the exception with the corresponding data fields -defined by the exception's type signature. The catch instruction uses the tag to -identify if the thrown exception is one it can catch. - -Exceptions can also be thrown by called, imported functions. If it corresponds -to an imported exception, it can be caught by an appropriate catch instruction. -If the exception is not imported, it still can be caught to allow code clean-up, -but the data of the exception can't be accessed. - -### Try and catch blocks. - -A _try_ block defines a list of instructions that may need to catch exceptions -and/or clean up state when an exception is thrown. Like other higher-level -constructs, a try block begins with a `try` instruction, and ends with an `end` -instruction. That is, a try block is sequence of instructions having the -following form: - -``` -try - instruction* -catch i - instruction* -catch j - instruction* -... -catch n - instruction* -catch_all - instruction* -end -``` - -A try block also contains one or more catch blocks, and all but the last catch -block must begin with a`catch` instruction. The last catch block can begin with -either a `catch` or `catch_all` instruction. The `catch`/`catch_all` -instructions (within the try construct) are called the _catching_ instructions. - -The _body_ of the try block is the list of instructions before the first -catching instruction. The _body_ of each catch block is the sequence of -instructions following the corresponding catching instruction, and the next -catching instruction (or the `end` instruction if it is the last catching -block). - -The `catch` instruction has an exception tag associated with it. The tag -identifies what exceptions it can catch. That is, any exception created with the -corresponding exception tag. Catch blocks that begin with a `catch` instruction -are considered _tagged_ catch blocks. - -The last catch block of an exception can be a tagged catch block. Alternatively, -it can begin with the `catch_all` instruction. If it begins with the `catch_all` -instruction, it defines the _default_ catch block. The default catch block has -no exception type, and is used to catch all exceptions not caught by any of the -tagged catch blocks. - -Try blocks, like control-flow blocks, have a _block type_. The block type of a -try block defines the values yielded by the evaluation the try block when either -no exception is thrown, or the exception is successfully caught by one of its -catch blocks, and the instructions within the catch block can recover from the -throw. Because `try` and `end` instructions define a control-flow block, they -can be targets for branches (`br` and `br_if`) as well. - -In the initial implementation, try blocks may only yield 0 or 1 values. - -### Throws - -The `throw` instruction has a single immediate argument, an exception tag. The -exception tag is used to define the data fields of the allocated exception. The -values for the data fields must be on top of the operand stack, and must -correspond to the exception type signature for the exception. - -When an exception is thrown, the exception is allocated and the values on the -stack (corresponding to the type signature) are popped off and assigned to the -allocated exception. The exception is stored internally for access when the -exception is caught. The runtime then searches for nearest enclosing try block -body that execution is in. That try block is called the _catching_ try block. - -If the throw appears within the body of a try block, it is the catching try -block. - -If a throw occurs within a function body, and it doesn't appear inside the body -of a try block, the throw continues up the call stack until it is in the body of -an an enclosing try block, or the call stack is flushed. If the call stack is -flushed, execution is terminated. Otherwise, the found enclosing try block is -the catching try block. - -A throw inside a the body of a catch block is never caught by the corresponding -try block of the catch block, since instructions in the body of the catch block -are not in the body of the try block. - -Once a catching try block is found for the throw, the operand stack is popped -back to the size the operand stack had when the try block was entered. Then, -tagged catch blocks are tried in the order they appear in the catching try -block, until one matches. - -If a matched tagged catch block is found, control is transferred to the body of -the catch block, and the data fields of the exception are pushed back onto the -stack. - -Otherwise, control is transferred to the body of the default catch block. -However, unlike tagged catch blocks, the constructor arguments are not copied -back onto the operand stack. - -If no tagged catch blocks were matched, and the catching try block doesn't have -a default catch block, the exception is rethrown to the next enclosing try -block. - -If control is transferred to the body of a catch block, and the last instruction -in the body is executed, control then exits the try block. - -Also note that when the thrown exception is caught by a catch block, it is not -destroyed until the catch block is exited. This is done so that the catch block -can rethrow the exception. - -If the selected catch block does not rethrow an exception, it must yield the -value(s) expected by the enclosing try block. For tagged catch blocks, they must -also be sure to also pop off the caught exception values. - -### Rethrows - -The `rethrow` instruction can only appear in the body of a catch block. The -`rethrow` instruction always re-throws the exception caught by an enclosing -catch block. This allows the catch block to clean up state before the exception -is passed back to the next enclosing try block. - -Associated with the `rethrow` instruction is a _label_. The label is used to -disambiguate which exception is to be rethrown, when inside nested catch blocks. - -The label is the relative block depth to the corresponding try block for which -the catching block appears. - -For example consider the following: - -``` -try - ... -catch 1 - ... - block - ... - try - ... - catch 2 - ... - try - ... - catch 3 - ... - rethrow N - end - end - end - ... -end -``` - -In this example, `N` is used to disambiguate which caught exception is being -rethrown. It could rethrow any of the three caught expceptions. Hence, `rethrow -0` corresponds to the exception caught by `catch 3`, `rethrow 1` corresponds to -the exception caught by `catch 2`, and `rethrow 3` corresponds to the exception -caught by `catch 1`. - -Note that `rethrow 2` is not allowed because it does not reference a `try` -instruction. Rather, it references a `block` instruction. - -### Debugging - -Earlier discussion implied that when an exception is thrown, the runtime will -pop the operand stack across function calls until a corresponding, enclosing try -block is found. The implementation may actually not do this. Rather, it may -first search up the call stack to see if there is an enclosing try. If none are -found, it could terminate the thread at the point of the throw. This would allow -better debugging capability, since the corresponding call stack is still there -to query. - -## Changes to the text format. - -This section describes change in the [instruction syntax -document](https://github.com/WebAssembly/spec/blob/master/document/text/instructions.rst). - -### Control Instructions - -The following rule is added to *instructions*: - -``` -instructions ::= - ... - try resulttype instr* catch+ end | - throw except_index | - rethrow label - -catch ::= - catch except_index inst* | - catch_all inst* -``` - -Like the `block`, `loop`, and `if` instructions, the `try` instruction is a -*structured* instruction, and is implicitly labeled. This allows branch -instructions to exit try blocks. - -The `except_index` of the `catch` instruction denotes the exception tag for the -caught exception. Similarly, the `except_index` of the `throw` instruction -denotes the tag for the constructed exception. See [exception index -space](#exception-index-space) for further clarification of exception tags. - -The `label` of the `rethrow` instruction is the label to the corresponding try -block, defining the catch to rethrow. - -## Changes to the binary model - -This section describes changes in the [binary encoding design -document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md). - -### Control flow operators - -The control flow operators are extended to define try blocks, catch blocks, -throws, and rethrows as follows: - -| Name | Opcode | Immediates | Description | -| ---- | ---- | ---- | ---- | -| `unreachable` | `0x00` | | trap immediately | -| `nop` | `0x01` | | no operation | -| `block` | `0x02` | sig : `block_type` | begin a sequence of expressions, yielding 0 or 1 values | -| `loop` | `0x03` | sig : `block_type` | begin a block which can also form control flow loops | -| `if` | `0x04` | sig : `block_type` | begin if expression | -| `else` | `0x05` | | begin else expression of if or try | -| `try` | `0x06` | sig : `block_type` | begins a block which can handle thrown exceptions | -| `catch` | `0x07` | tag : `varuint32` | begins a block when the exception `tag` is caught | -| `throw` | `0x08` | tag : `varuint32` | Throws an exception defined by the exception `tag` | -| `rethrow` | `0x09` | relative_depth : `varuint32` | re-throws the exception caught by the corresponding try block | -| `end` | `0x0b` | | end a block, loop, if, and try | -| `br` | `0x0c` | relative_depth : `varuint32` | break that targets an outer nested block | -| `br_if` | `0x0d` | relative_depth : `varuint32` | conditional break that targets an outer nested block | -| `br_table` | `0x0e` | see below | branch table control flow construct | -| `return` | `0x0f` | | return zero or one value from this function | - -The *sig* fields of `block`, `if`, and `try` operators are block signatures -which describe their use of the operand stack. - -Note that the textual `catch_all` instruction is implemented using the `else` -operator. Since the `else` operator is always unambiguous in the binary format, -there is no need to tie up a separate opcode for the `catch_all` instruction. - - ---- - -## Second Proposal - Instruction Part +## Overview Exception handling allows code to break control flow when an exception is thrown. The exception can be any exception known by the WebAssembly module, or @@ -441,14 +157,10 @@ A try block ends with a `catch block` that is defined by the list of instructions after the `catch` instruction. Try blocks, like control-flow blocks, have a _block type_. The block type of a -try block defines the values yielded by the evaluation the try block when either -no exception is thrown, or the exception is successfully caught by the catch -block. -Try blocks, like control-flow blocks, have a _block type_. The block type of a -try block defines the values yielded by the evaluation the try block when either -no exception is thrown, or the exception is successfully caught by the catch -block. Because `try` and `end` instructions define a control-flow block, they -can be targets for branches (`br` and `br_if`) as well. +try block defines the values yielded by evaluating the try block when either no +exception is thrown, or the exception is successfully caught by the catch block. +Because `try` and `end` instructions define a control-flow block, they can be +targets for branches (`br` and `br_if`) as well. In the initial implementation, try blocks may only yield 0 or 1 values. @@ -544,7 +256,7 @@ calls until a corresponding, enclosing try block is found. It may also associate a stack trace that can be used to report uncaught exceptions. However, the details of this is left to the embedder. -## Changes to the text format. +## Changes to the text format This section describes change in the [instruction syntax document](https://github.com/WebAssembly/spec/blob/master/document/core/instructions.rst). @@ -570,53 +282,7 @@ exception (and hence, exception tag) to create/extract from. See [exception index space](#exception-index-space) for further clarification of exception tags. -## Changes to the binary model - -This section describes changes in the [binary encoding design -document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md). - -### Data Types - -#### except_ref - -An exception reference points to an exception. - -### Language Types - -| Opcode | Type constructor | -|--------|------------------| -| -0x18 | `except_ref` | - -#### value_type - -A `varint7` indicating a `value_type` is extended to include `except_ref` as -encoded above. - -### Control flow operators - -The control flow operators are extended to define try blocks, catch blocks, -throws, and rethrows as follows: - -| Name | Opcode | Immediates | Description | -| ---- | ---- | ---- | ---- | -| `try` | `0x06` | sig : `block_type` | begins a block which can handle thrown exceptions | -| `catch` | `0x07` | | begins the catch block of the try block | -| `throw` | `0x08` | index : `varint32` | Creates an exception defined by the exception `index`and then throws it | -| `rethrow` | `0x09` | | Pops the `except_ref` on top of the stack and throws it | -| `if_except` | `0x0a` | index : `varuint32`, sig : `block_type` | Begin exception data extraction if exception on stack was created using the corresponding exception `index` | - -The *sig* fields of `block`, `if`, `try` and `if_except` operators are block -signatures which describe their use of the operand stack. - - ---- - -## Common part - -This part describes changes to the module and binary model. This part comes from -the [second proposal](old/Level-1.md) and we are going to use it for this part. - -## Changes to Modules document. +## Changes to Modules document This section describes change in the [Modules document](https://github.com/WebAssembly/design/blob/master/Modules.md). @@ -639,6 +305,23 @@ exported alias the respective events defined elsewhere, and use the same tag. This section describes changes in the [binary encoding design document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md). +### Data Types + +#### except_ref + +An exception reference points to an exception. + +### Language Types + +| Opcode | Type constructor | +|--------|------------------| +| -0x18 | `except_ref` | + +#### value_type + +A `varint7` indicating a `value_type` is extended to include `except_ref` as +encoded above. + #### Other Types ##### event_type @@ -731,35 +414,18 @@ follows: The event names subsection is a `name_map` which assigns names to a subset of the event indices (Used for both imports and module-defined). +### Control flow operators ---- +The control flow operators are extended to define try blocks, catch blocks, +throws, and rethrows as follows: -## Comparisons of the two proposals - -- Proposal 2 introduces a first-class exception reference type. This raises several - questions about exception lifetime management: - - How do we manage exception objects' lifetime in non-GC embeddings? Do we - make reference counting mandatory? - - Who is responsible for deleting exception objects? - - What should we do for except_ref values of invalid exception objects already - deleted? - - How should exception reference type be related to the existing reference - type or GC proposal? - - Consequently, Proposal 1 would be simpler to implement for VMs which do not need - reference types or related functionality such as GC objects. - -- The first-class exception type makes Proposal 2 more expressive, possibly providing - more flexibility for frontend developers for non-C langauges. In particular, allowing - exception objects to escape catch blocks may simplify control flow translation. - Conversely, it is slightly more complex for languages which do not have convenient ways to model - reference types. - -- In Proposal 2, the unwinder must stop at every call stack frame with `catch` - instruction because the tag matching happens within a `catch` block, whereas - in Proposal 1 the unwinder does not need to stop at call stack frames that - do not contain `catch`s with the current exception's tag. Stopping at every - call frame might degrade performance. - -- It is suggested that Proposal 2 may be more compatible with effect handlers, - which can be might be added to wasm in the future. +| Name | Opcode | Immediates | Description | +| ---- | ---- | ---- | ---- | +| `try` | `0x06` | sig : `block_type` | begins a block which can handle thrown exceptions | +| `catch` | `0x07` | | begins the catch block of the try block | +| `throw` | `0x08` | index : `varint32` | Creates an exception defined by the exception `index`and then throws it | +| `rethrow` | `0x09` | | Pops the `except_ref` on top of the stack and throws it | +| `if_except` | `0x0a` | index : `varuint32`, sig : `block_type` | Begin exception data extraction if exception on stack was created using the corresponding exception `index` | + +The *sig* fields of `block`, `if`, `try` and `if_except` operators are block +signatures which describe their use of the operand stack. From d568424aadb4d48e142a7520cf1168bfc4c52dee Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Wed, 7 Nov 2018 12:03:52 -0800 Subject: [PATCH 052/302] Add section table and event section code (#67) --- proposals/Exceptions.md | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index b324e76b02..0f6b368248 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -365,10 +365,27 @@ appear immediately after the global section. ##### Event section The `event` section is the named section 'event'. For ease of validation, this -section comes after the [import -section](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#import-section) +section comes after the [global +section](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#global-section) and before the [export section](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#export-section). +So the list of all sections will be: + +| Section Name | Code | Description | +| ------------ | ---- | ----------- | +| Type | `1` | Function signature declarations | +| Import | `2` | Import declarations | +| Function | `3` | Function declarations | +| Table | `4` | Indirect function table and other tables | +| Memory | `5` | Memory attributes | +| Global | `6` | Global declarations | +| Event | `12` | Event declarations | +| Export | `7` | Exports | +| Start | `8` | Start function declaration | +| Element | `9` | Elements section | +| Code | `10` | Function bodies (code) | +| Data | `11` | Data segments | + The event section declares a list of event types as follows: | Field | Type | Description | From 530d2b97588b2291e4765ff8c814a380d1ad5c75 Mon Sep 17 00:00:00 2001 From: Thomas BARRAS Date: Sun, 18 Nov 2018 20:14:54 -0500 Subject: [PATCH 053/302] DOC: typo (#69) --- proposals/Exceptions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index 0f6b368248..28d9fb3ec9 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -44,7 +44,7 @@ collect and reuse the memory used by exceptions. This implies that an embedder needs to know where exceptions are stored, so that it can determine when an exception can be garbage collected. -This also implies that that embedders must provide a garbage collector for +This also implies that embedders must provide a garbage collector for exceptions. For embedders that have garbage collection (such as JavaScript), this is not a problem. From 2bbeec2dd354b6564b702f40969ee42f37cf962d Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Mon, 3 Dec 2018 14:54:11 -0800 Subject: [PATCH 054/302] Add reference types proposal as a prerequisite (#72) --- proposals/Exceptions.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index 28d9fb3ec9..69678bd0dd 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -10,6 +10,11 @@ on the second proposal, which uses first-class exception types, mainly based on the reasoning that it is more expressive and also more extendible to other kinds of events. +This proposal requires the [reference types +proposal](https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md) +as a prerequisite, since the [`except_ref`](#the-exception-reference-data-type) +type should be represented as a subtype of `anyref`. + --- ## Overview From 3c7f11a6fe511d0f501d3a78799aaa905589e584 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Mon, 3 Dec 2018 15:51:34 -0800 Subject: [PATCH 055/302] Simplify exception dispatch to branches (#71) This proposes to use the idea suggested by #58 on using `br_on_exn` instead of `if_except`. --- proposals/Exceptions.md | 93 +++++++++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 37 deletions(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index 69678bd0dd..25e4b3f6f0 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -133,9 +133,10 @@ Exception indices are used by: 1. The `throw` instruction which creates a WebAssembly exception with the corresponding exception tag, and then throws it. -2. The `if_except` instruction queries an exception to see if the corresponding - exception tag denoted by the exception index. If true it pushes the - corresponding values of the exception onto the stack. +2. The `br_on_exn` instruction queries an exception to see if it matches the + corresponding exception tag denoted by the exception index. If true it + branches to the given label and pushes the corresponding argument values of + the exception onto the stack. ### The exception reference data type @@ -220,39 +221,58 @@ exception on top of the stack is popped and then thrown. ### Exception data extraction -The `if_except` block begins with an `if_except` instruction, and has two -instruction blocks, - -That is, the forms of an if_except block is: +The `br_on_exn` instruction is a conditional branch that checks the exception +tag of an exception on top of the stack, in the form of: ``` -if_except block_type except_index - Instruction* -end +br_on_exn label except_index +``` + +The `br_on_exn` instruction checks the exception tag of an `except_ref` on top +of the stack if it matches the given exception index. If it does, it branches +out to the label referenced by the instruction (In the binary form, the label +will be converted to a relative depth immediate, like other branch +instructions), and while doing that, pops the `except_ref` value from the stack +and instead pushes the exception's argument values on top of the stack. In order +to use these popped values, the block signature of the branch target has to +match the exception types - because it receives the exception arguments as +branch operands. If the exception tag does not match, the `except_ref` value +remains on the stack. For example, when an `except_ref` contains an exception of +type (i32 i64), the target block signature should be (i32 i64) as well, as in +the following example: -if_except block_type except_index - Instruction* -else - Instruction* +``` +block $l (result i32 i64) + ... + ;; except_ref $e is on the stack at this point + br_on_exn $l ;; branch to $l with $e's arguments + ... end ``` -In the first form, the instructions between the `if_except` and 'end' define the -`then block`. In the second form, the instructions between the `if_except` and -`else` define the `then block`, while the instructions between the `else` and -the `end` define the `else block`. - -The conditional query of an exception checks the exception tag of exception on -top of the stack. It succeeds only if the exception index of the instruction -matches the corresponding exception tag. Once the query completes, the exception -is popped off the stack. +This can now be used to construct handler switches in the same way `br_table` +is used to construct regular switch: -If the query succeeds the values (associated with the popped exception) are -extracted and pushed onto the stack, and control transfers to the instructions -in the then block. +``` +block $end + block $l1 + ... + block $lN + br_on_exn $l1 + ... + br_on_exn $lN + rethrow + end $lN + ;; handler for $eN here + br $end + ... + end $l1 + ;; handler for $e1 +end $end +``` -If the query fails, it either enters the else block, or transfer control to the -end of the if_except block if there is no else block. +If the query fails, the control flow falls through, and no values are pushed +onto the stack. ### Stack traces @@ -274,15 +294,14 @@ The following rules are added to *instructions*: try resulttype instruction* catch instruction* end | throw except_index | rethrow | - if_except resulttype except_index then instruction* end | - if_except resulttype except_index then instruction* else instruction* end + br_on_exn label except_index ``` -Like the `block`, `loop`, and `if` instructions, the `try` and `if_except` -instructions are *structured* control flow instructions, and can be labeled. -This allows branch instructions to exit try and `if_except` blocks. +Like the `block`, `loop`, and `if` instructions, the `try` instruction is +*structured* control flow instruction, and can be labeled. This allows branch +instructions to exit try blocks. -The `except_index` of the `throw` and `if_except` instructions defines the +The `except_index` of the `throw` and `br_on_exn` instructions defines the exception (and hence, exception tag) to create/extract from. See [exception index space](#exception-index-space) for further clarification of exception tags. @@ -447,7 +466,7 @@ throws, and rethrows as follows: | `catch` | `0x07` | | begins the catch block of the try block | | `throw` | `0x08` | index : `varint32` | Creates an exception defined by the exception `index`and then throws it | | `rethrow` | `0x09` | | Pops the `except_ref` on top of the stack and throws it | -| `if_except` | `0x0a` | index : `varuint32`, sig : `block_type` | Begin exception data extraction if exception on stack was created using the corresponding exception `index` | +| `br_on_exn` | `0x0a` | relative_depth : `varuint32`, index : `varuint32` | Branches to the given label and extracts data within `except_ref` on top of stack if it was created using the corresponding exception `index` | -The *sig* fields of `block`, `if`, `try` and `if_except` operators are block -signatures which describe their use of the operand stack. +The *sig* fields of `block`, `if`, and `try` operators are block signatures +which describe their use of the operand stack. From 7a079d4d4d9975e2ba783f2dc53d54862e4fd332 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Wed, 5 Dec 2018 22:24:12 -0800 Subject: [PATCH 056/302] Change event section code to 13 (#75) We decided to change the event section code from 12 to 13 in #70 as the new DataCount section in the bulk memory operations proposal will take the code 12 instead. --- proposals/Exceptions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index 25e4b3f6f0..a0c6ab61df 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -403,7 +403,7 @@ So the list of all sections will be: | Table | `4` | Indirect function table and other tables | | Memory | `5` | Memory attributes | | Global | `6` | Global declarations | -| Event | `12` | Event declarations | +| Event | `13` | Event declarations | | Export | `7` | Exports | | Start | `8` | Start function declaration | | Element | `9` | Elements section | From 42eeba87c8e6e34a21394a0b52d23c9b40cdd0fa Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Sat, 26 Jan 2019 22:03:02 -0800 Subject: [PATCH 057/302] Fix a typo --- proposals/Exceptions.md | 2 +- proposals/old/Level-1.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index a0c6ab61df..7915873919 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -177,7 +177,7 @@ index is used to identify the exception tag to use to create and throw the corresponding exception. The values on top of the stack must correspond to the type associated with the -exception. These values are popped of the stack and are used (along with the +exception. These values are popped off the stack and are used (along with the corresponding exception tag) to create the corresponding exception. That exception is then thrown. diff --git a/proposals/old/Level-1.md b/proposals/old/Level-1.md index f0310cd676..802046adf0 100644 --- a/proposals/old/Level-1.md +++ b/proposals/old/Level-1.md @@ -168,7 +168,7 @@ index is used to identify the exception tag to use to create and throw the corresponding exception. The values on top of the stack must correspond to the type associated with the -exception. These values are popped of the stack and are used (along with the +exception. These values are popped off the stack and are used (along with the corresponding exception tag) to create the corresponding exception. That exception is then thrown. From af146bcdc00b053fe1758bea998e629a729ffbf9 Mon Sep 17 00:00:00 2001 From: Mirko Sertic Date: Thu, 20 Jun 2019 19:36:53 +0200 Subject: [PATCH 058/302] Fixed a typo --- proposals/Exceptions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index 7915873919..79e6d9fd4f 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -319,7 +319,7 @@ import and event sections. Thus, the index space starts at zero with imported events, followed by internally-defined events in the [event section](#event-section). -The event index space defines the (module) static version of runtine event tags. +The event index space defines the (module) static version of runtime event tags. For event indices that are not imported/exported, the corresponding event tag is guaranteed to be unique over all loaded modules. Events that are imported or exported alias the respective events defined elsewhere, and use the same tag. From 77795997b3dec19b66dbb75a6ea735cfe402931a Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Sun, 14 Jul 2019 02:46:22 -0700 Subject: [PATCH 059/302] Rename except_ref type to exnref (#84) In #79 we agreed to change `except_ref` to `exnref`. --- proposals/Exceptions.md | 53 ++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/proposals/Exceptions.md b/proposals/Exceptions.md index 79e6d9fd4f..7915940b5a 100644 --- a/proposals/Exceptions.md +++ b/proposals/Exceptions.md @@ -12,8 +12,8 @@ of events. This proposal requires the [reference types proposal](https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md) -as a prerequisite, since the [`except_ref`](#the-exception-reference-data-type) -type should be represented as a subtype of `anyref`. +as a prerequisite, since the [`exnref`](#the-exception-reference-data-type) type +should be represented as a subtype of `anyref`. --- @@ -140,7 +140,7 @@ Exception indices are used by: ### The exception reference data type -Data types are extended to have a new `except_ref` type, that refers to an +Data types are extended to have a new `exnref` type, that refers to an exception. The representation of an exception is left to the implementation. ### Try and catch blocks @@ -200,7 +200,7 @@ are not in the body of the try block. Once a catching try block is found for the thrown exception, the operand stack is popped back to the size the operand stack had when the try block was entered, -and then an except_ref referring to the caught exception is pushed back onto the +and then an `exnref` referring to the caught exception is pushed back onto the operand stack. If control is transferred to the body of a catch block, and the last instruction @@ -214,10 +214,10 @@ Note that a caught exception can be rethrown using the `rethrow` instruction. ### Rethrowing an exception -The `rethrow` instruction takes the exception associated with the `except_ref` -on top of the stack, and rethrows the exception. A rethrow has the same effect -as a throw, other than an exception is not created. Rather, the referenced -exception on top of the stack is popped and then thrown. +The `rethrow` instruction takes the exception associated with the `exnref` on +top of the stack, and rethrows the exception. A rethrow has the same effect as a +throw, other than an exception is not created. Rather, the referenced exception +on top of the stack is popped and then thrown. ### Exception data extraction @@ -228,23 +228,22 @@ tag of an exception on top of the stack, in the form of: br_on_exn label except_index ``` -The `br_on_exn` instruction checks the exception tag of an `except_ref` on top -of the stack if it matches the given exception index. If it does, it branches -out to the label referenced by the instruction (In the binary form, the label -will be converted to a relative depth immediate, like other branch -instructions), and while doing that, pops the `except_ref` value from the stack -and instead pushes the exception's argument values on top of the stack. In order -to use these popped values, the block signature of the branch target has to -match the exception types - because it receives the exception arguments as -branch operands. If the exception tag does not match, the `except_ref` value -remains on the stack. For example, when an `except_ref` contains an exception of -type (i32 i64), the target block signature should be (i32 i64) as well, as in -the following example: +The `br_on_exn` instruction checks the exception tag of an `exnref` on top of +the stack if it matches the given exception index. If it does, it branches out +to the label referenced by the instruction (In the binary form, the label will +be converted to a relative depth immediate, like other branch instructions), and +while doing that, pops the `exnref` value from the stack and instead pushes the +exception's argument values on top of the stack. In order to use these popped +values, the block signature of the branch target has to match the exception +types - because it receives the exception arguments as branch operands. If the +exception tag does not match, the `exnref` value remains on the stack. For +example, when an `exnref` contains an exception of type (i32 i64), the target +block signature should be (i32 i64) as well, as in the following example: ``` block $l (result i32 i64) ... - ;; except_ref $e is on the stack at this point + ;; exnref $e is on the stack at this point br_on_exn $l ;; branch to $l with $e's arguments ... end @@ -331,7 +330,7 @@ document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md). ### Data Types -#### except_ref +#### exnref An exception reference points to an exception. @@ -339,12 +338,12 @@ An exception reference points to an exception. | Opcode | Type constructor | |--------|------------------| -| -0x18 | `except_ref` | +| -0x18 | `exnref` | #### value_type -A `varint7` indicating a `value_type` is extended to include `except_ref` as -encoded above. +A `varint7` indicating a `value_type` is extended to include `exnref` as encoded +above. #### Other Types @@ -465,8 +464,8 @@ throws, and rethrows as follows: | `try` | `0x06` | sig : `block_type` | begins a block which can handle thrown exceptions | | `catch` | `0x07` | | begins the catch block of the try block | | `throw` | `0x08` | index : `varint32` | Creates an exception defined by the exception `index`and then throws it | -| `rethrow` | `0x09` | | Pops the `except_ref` on top of the stack and throws it | -| `br_on_exn` | `0x0a` | relative_depth : `varuint32`, index : `varuint32` | Branches to the given label and extracts data within `except_ref` on top of stack if it was created using the corresponding exception `index` | +| `rethrow` | `0x09` | | Pops the `exnref` on top of the stack and throws it | +| `br_on_exn` | `0x0a` | relative_depth : `varuint32`, index : `varuint32` | Branches to the given label and extracts data within `exnref` on top of stack if it was created using the corresponding exception `index` | The *sig* fields of `block`, `if`, and `try` operators are block signatures which describe their use of the operand stack. From e7196b7b5110cf6cb7da56d401bf3761c715d555 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Tue, 20 Aug 2019 11:10:55 +0200 Subject: [PATCH 060/302] Import the JS API specification. (#88) * [js-api] Import upstream specification. Source: https://github.com/WebAssembly/spec/commit/666dc4cb8d4a81d386a7a716000bb85fbbbd06a2 * [js-api] Import reference-types changes. Source: https://github.com/WebAssembly/reference-types/commit/aa596e574b8e26a97ed34df8bd2385d65b955f14 * [js-api] Link to reference-types proposal. --- document/js-api/Makefile | 44 ++ document/js-api/index.bs | 1171 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 1215 insertions(+) create mode 100644 document/js-api/Makefile create mode 100644 document/js-api/index.bs diff --git a/document/js-api/Makefile b/document/js-api/Makefile new file mode 100644 index 0000000000..84ba5d3abd --- /dev/null +++ b/document/js-api/Makefile @@ -0,0 +1,44 @@ +BUILDDIR = _build +STATICDIR = _static +DOWNLOADDIR = _download +NAME = WebAssembly + +.PHONY: all +all: + mkdir -p $(BUILDDIR)/html + bikeshed spec index.bs $(BUILDDIR)/html/index.html + @echo "Build finished. The HTML pages are in `pwd`/$(BUILDDIR)/html." + +.PHONY: publish +publish: + (cd ..; make publish-js-api) + +.PHONY: clean +clean: + rm -rf $(BUILDDIR) + rm -rf $(STATICDIR) + +.PHONY: diff +diff: all + @echo "Downloading the old single-file html spec..." + curl `grep "^TR" index.bs | cut -d' ' -f2` -o $(BUILDDIR)/html/old.html + @echo "Done." + @echo "Diffing new against old..." + perl ../util/htmldiff.pl $(BUILDDIR)/html/old.html $(BUILDDIR)/html/index.html $(BUILDDIR)/html/diff.html + @echo "Done. The diff is at $(BUILDDIR)/html/diff.html" + +.PHONY: WD-tar +WD-tar: + bikeshed echidna --just-tar index.bs $(BUILDDIR)/html/index.html + mv test.tar $(BUILDDIR)/WD.tar + @echo "Built $(BUILDDIR)/WD.tar." + +.PHONY: WD-echidna +WD-echidna: + @if [ -z $(W3C_USERNAME) ] || \ + [ -z $(W3C_PASSWORD) ] || \ + [ -z $(DECISION_URL) ] ; then \ + echo "Must provide W3C_USERNAME, W3C_PASSWORD, and DECISION_URL environment variables"; \ + exit 1; \ + fi + bikeshed echidna index.bs --u $(W3C_USERNAME) --p $(W3C_PASSWORD) --d $(DECISION_URL) diff --git a/document/js-api/index.bs b/document/js-api/index.bs new file mode 100644 index 0000000000..c72be76454 --- /dev/null +++ b/document/js-api/index.bs @@ -0,0 +1,1171 @@ + + +
+{
+  "WEBASSEMBLY": {
+    "href": "https://webassembly.github.io/spec/core/",
+    "title": "WebAssembly Core Specification",
+    "publisher": "W3C WebAssembly Community Group",
+    "status": "Draft"
+  }
+}
+
+ +
+urlPrefix: https://tc39.github.io/ecma262/; spec: ECMASCRIPT
+    type: interface; for: ECMAScript
+        text: ArrayBuffer; url: sec-arraybuffer-objects
+    type: exception; for: ECMAScript
+        text: Error; url: sec-error-objects
+        text: NativeError; url: sec-nativeerror-constructors
+        text: TypeError; url: sec-native-error-types-used-in-this-standard-typeerror
+        text: RangeError; url: sec-native-error-types-used-in-this-standard-rangeerror
+    type: dfn
+        text: agent cluster; url: sec-agent-clusters
+        text: agent; url: agent
+        text: data block; url: sec-data-blocks
+        text: Bound Function; url: sec-bound-function-exotic-objects
+        text: NumericLiteral; url: sec-literals-numeric-literals
+        text: surrounding agent; url: surrounding-agent
+        text: ToNumber; url: sec-tonumber
+        text: ToInt32; url: sec-toint32
+        text: ToString; url: sec-tostring
+        url: sec-ecmascript-data-types-and-values
+            text: Type
+            text: Type(x)
+        url: sec-iscallable
+            text: IsCallable
+            text: callable; for: ECMAScript
+        url: sec-well-known-intrinsic-objects
+            text: %ErrorPrototype%
+        text: %ObjectPrototype%; url: sec-properties-of-the-object-prototype-object
+        text: %FunctionPrototype%; url: sec-properties-of-the-function-prototype-object
+        text: %Promise%; url: sec-promise-constructor
+        text: Property Descriptor; url: sec-property-descriptor-specification-type
+        text: array index; url: sec-array-exotic-objects
+        text: OrdinaryGetOwnProperty; url: sec-ordinarygetownproperty
+        text: OrdinaryDefineOwnProperty; url: sec-ordinarydefineownproperty
+        text: OrdinaryPreventExtensions; url: sec-ordinarypreventextensions
+        text: OrdinarySet; url: sec-ordinaryset
+        text: equally close values; url: sec-ecmascript-language-types-number-type
+        text: internal slot; url: sec-object-internal-methods-and-internal-slots
+        text: JavaScript execution context stack; url: execution-context-stack
+        text: running JavaScript execution context; url: running-execution-context
+        text: GetIterator; url: sec-getiterator
+        text: IteratorStep; url: sec-iteratorstep
+        text: NormalCompletion; url: sec-normalcompletion
+        text: IteratorValue; url: sec-iteratorvalue
+        url: sec-well-known-symbols
+            text: @@iterator
+            text: @@toStringTag
+        text: CreateDataProperty; url: sec-createdataproperty
+        text: DetachArrayBuffer; url: sec-detacharraybuffer
+        text: SetIntegrityLevel; url: sec-setintegritylevel
+        text: Call; url: sec-call
+        text: Get; url: sec-get-o-p
+        text: DefinePropertyOrThrow; url: sec-definepropertyorthrow
+        text: current Realm; url: current-realm
+        text: ObjectCreate; url: sec-objectcreate
+        text: CreateBuiltinFunction; url: sec-createbuiltinfunction
+        text: SetFunctionName; url: sec-setfunctionname
+        text: SetFunctionLength; url: sec-setfunctionlength
+        text: the Number value; url: sec-ecmascript-language-types-number-type
+        text: NumberToRawBytes; url: sec-numbertorawbytes
+        text: Built-in Function Objects; url: sec-built-in-function-objects
+urlPrefix: https://webassembly.github.io/reference-types/core/; spec: WebAssembly; type: dfn
+    url: valid/modules.html#valid-module
+        text: valid
+        text: WebAssembly module validation
+    text: module grammar; url: binary/modules.html#binary-module
+    text: custom section; url: binary/modules.html#custom-section
+    text: customsec; url: binary/modules.html#binary-customsec
+    text: memory instance; url: exec/runtime.html#memory-instances
+    text: table instance; url: exec/runtime.html#table-instances
+    text: global instance; url: exec/runtime.html#global-instances
+    text: trap; url: exec/runtime.html#syntax-trap
+    url: exec/runtime.html#values
+        text: WebAssembly value
+        text: 𝗂𝟨𝟦.𝖼𝗈𝗇𝗌𝗍
+        text: 𝗂𝟥𝟤.𝖼𝗈𝗇𝗌𝗍
+        text: 𝖿𝟥𝟤.𝖼𝗈𝗇𝗌𝗍
+        text: 𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍
+        text: ref.null
+        text: ref.func
+        text: ref.host
+    text: function index; url: syntax/modules.html#syntax-funcidx
+    text: function instance; url: exec/runtime.html#function-instances
+    text: store_init; url: appendix/embedding.html#embed-store-init
+    text: module_decode; url: appendix/embedding.html#embed-module-decode
+    text: module_validate; url: appendix/embedding.html#embed-module-validate
+    text: module_instantiate; url: appendix/embedding.html#embed-module-instantiate
+    text: module_imports; url: appendix/embedding.html#embed-module-imports
+    text: module_exports; url: appendix/embedding.html#embed-module-exports
+    text: instance_export; url: appendix/embedding.html#embed-instance-export
+    text: func_alloc; url: appendix/embedding.html#embed-func-alloc
+    text: func_type; url: appendix/embedding.html#embed-func-type
+    text: func_invoke; url: appendix/embedding.html#embed-func-invoke
+    text: table_alloc; url: appendix/embedding.html#embed-table-alloc
+    text: table_type; url: appendix/embedding.html#embed-table-type
+    text: table_read; url: appendix/embedding.html#embed-table-read
+    text: table_write; url: appendix/embedding.html#embed-table-write
+    text: table_size; url: appendix/embedding.html#embed-table-size
+    text: table_grow; url: appendix/embedding.html#embed-table-grow
+    text: mem_alloc; url: appendix/embedding.html#embed-mem-alloc
+    text: mem_type; url: appendix/embedding.html#embed-mem-type
+    text: mem_read; url: appendix/embedding.html#embed-mem-read
+    text: mem_write; url: appendix/embedding.html#embed-mem-write
+    text: mem_size; url: appendix/embedding.html#embed-mem-size
+    text: mem_grow; url: appendix/embedding.html#embed-mem-grow
+    text: global_alloc; url: appendix/embedding.html#embed-global-alloc
+    text: global_type; url: appendix/embedding.html#embed-global-type
+    text: global_read; url: appendix/embedding.html#embed-global-read
+    text: global_write; url: appendix/embedding.html#embed-global-write
+    text: error; url: appendix/embedding.html#embed-error
+    text: store; url: exec/runtime.html#syntax-store
+    text: table type; url: syntax/types.html#syntax-tabletype
+    text: table address; url: exec/runtime.html#syntax-tableaddr
+    text: function address; url: exec/runtime.html#syntax-funcaddr
+    text: memory address; url: exec/runtime.html#syntax-memaddr
+    text: global address; url: exec/runtime.html#syntax-globaladdr
+    text: host address; url: exec/runtime.html#syntax-hostaddr
+    url: syntax/types.html#syntax-numtype
+        text: 𝗂𝟥𝟤
+        text: 𝗂𝟨𝟦
+        text: 𝖿𝟥𝟤
+        text: 𝖿𝟨𝟦
+    url: syntax/types.html#syntax-reftype
+        text: anyref
+        text: funcref
+    text: function element; url: exec/runtime.html#syntax-funcelem
+    text: import component; url: syntax/modules.html#imports
+    text: external value; url: exec/runtime.html#syntax-externval
+    text: host function; url: exec/runtime.html#syntax-hostfunc
+    text: the instantiation algorithm; url: exec/modules.html#instantiation
+    text: module; url: syntax/modules.html#syntax-module
+    text: 𝗂𝗆𝗉𝗈𝗋𝗍𝗌; url: syntax/modules.html#syntax-module
+    text: import; url: syntax/modules.html#syntax-import
+    url: syntax/types.html#external-types
+        text: external type
+        text: 𝖿𝗎𝗇𝖼
+        text: 𝗍𝖺𝖻𝗅𝖾
+        text: 𝗆𝖾𝗆
+        text: 𝗀𝗅𝗈𝖻𝖺𝗅
+    text: global type; url: syntax/types.html#syntax-globaltype
+    url: syntax/types.html#syntax-mut
+        text: var
+        text: const
+    text: address; url: exec/runtime.html#addresses
+    text: signed_32; url: exec/numerics.html#aux-signed
+    text: memory.grow; url: exec/instructions.html#exec-memory-grow
+    text: current frame; url: exec/conventions.html#exec-notation-textual
+    text: 𝗆𝗈𝖽𝗎𝗅𝖾; url: exec/runtime.html#syntax-frame
+    text: 𝗆𝖾𝗆𝖺𝖽𝖽𝗋𝗌; url: exec/runtime.html#syntax-moduleinst
+    text: sequence; url: syntax/conventions.html#grammar-notation
+
+ + + +This API privides a way to access WebAssembly [[WEBASSEMBLY]] through a bridge to explicitly construct modules from JavaScript [[ECMASCRIPT]]. + +

Sample API Usage

+ +

This section is non-normative.

+ +Given `demo.wat` (encoded to `demo.wasm`): + +```lisp +(module + (import "js" "import1" (func $i1)) + (import "js" "import2" (func $i2)) + (func $main (call $i1)) + (start $main) + (func (export "f") (call $i2)) +) +``` + +and the following JavaScript, run in a browser: + +```javascript +var importObj = {js: { + import1: () => console.log("hello,"), + import2: () => console.log("world!") +}}; +fetch('demo.wasm').then(response => + response.arrayBuffer() +).then(buffer => + WebAssembly.instantiate(buffer, importObj) +).then(({module, instance}) => + instance.exports.f() +); +``` + +

Internal storage

+ +

Interaction of the WebAssembly Store with JavaScript

+ +Note: WebAssembly semantics are defined in terms of an abstract [=store=], representing the state of the WebAssembly abstract machine. WebAssembly operations take a store and return an updated store. + +Each [=agent=] has an associated store. When a new agent is created, its associated store is set to the result of [=store_init=](). + +Note: In this specification, no WebAssembly-related objects, memory or addresses can be shared among agents in an [=agent cluster=]. In a future version of WebAssembly, this may change. + +Elements of the WebAssembly store may be identified with JavaScript values. In particular, each WebAssembly [=memory instance=] with a corresponding {{Memory}} object is identified with a JavaScript [=Data Block=]; modifications to this Data Block are identified to updating the agent's store to a store which reflects those changes, and vice versa. + +

WebAssembly JS Object Caches

+ +Note: There are several WebAssembly objects that may have a corresponding JavaScript object. The correspondence is stored in a per-agent mapping from WebAssembly [=address=]es to JavaScript objects. +This mapping is used to ensure that, for a given [=agent=], there exists at most one JavaScript object for a particular WebAssembly address. However, this property does not hold for shared objects. + +Each [=agent=] is associated with the following [=ordered map=]s: + * The Memory object cache, mapping [=memory address=]es to {{Memory}} objects. + * The Table object cache, mapping [=table address=]es to {{Table}} objects. + * The Exported Function cache, mapping [=function address=]es to [=Exported Function=] objects. + * The Global object cache, mapping [=global address=]es to {{Global}} objects. + * The Host value cache, mapping [=host address=]es to values. + +

The WebAssembly Namespace

+ +
+dictionary WebAssemblyInstantiatedSource {
+    required Module module;
+    required Instance instance;
+};
+
+[Exposed=(Window,Worker,Worklet)]
+namespace WebAssembly {
+    boolean validate(BufferSource bytes);
+    Promise<Module> compile(BufferSource bytes);
+
+    Promise<WebAssemblyInstantiatedSource> instantiate(
+        BufferSource bytes, optional object importObject);
+
+    Promise<Instance> instantiate(
+        Module moduleObject, optional object importObject);
+};
+
+ + + +
+ To compile a WebAssembly module from source bytes |bytes|, perform the following steps: + 1. Let |module| be [=module_decode=](|bytes|). If |module| is [=error=], return [=error=]. + 1. If [=module_validate=](|module|) is [=error=], return [=error=]. + 1. Return |module|. +
+ +
+ The validate(|bytes|) method, when invoked, performs the following steps: + 1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|. + 1. [=Compile a WebAssembly module|Compile=] |stableBytes| as a WebAssembly module and store the results as |module|. + 1. If |module| is [=error=], return false. + 1. Return true. +
+ +
+A {{Module}} object represents a single WebAssembly module. Each {{Module}} object has the following internal slots: + + * \[[Module]] : a WebAssembly [=module=] + * \[[Bytes]] : the source bytes of \[[Module]]. +
+ +
+ To construct a WebAssembly module object from a module |module| and source bytes |bytes|, perform the following steps: + + 1. Let |moduleObject| be a new {{Module}} object. + 1. Set |moduleObject|.\[[Module]] to |module|. + 1. Set |moduleObject|.\[[Bytes]] to |bytes|. + 1. Return |moduleObject|. +
+ +
+ To asynchronously compile a WebAssembly module from source bytes |bytes|, using optional [=task source=] |taskSource|, perform the following steps: + + 1. Let |promise| be [=a new promise=]. + 1. Run the following steps [=in parallel=]: + 1. [=compile a WebAssembly module|Compile the WebAssembly module=] |bytes| and store the result as |module|. + 1. [=Queue a task=] to perform the following steps. If |taskSource| was provided, queue the task on that task source. + 1. If |module| is [=error=], reject |promise| with a {{CompileError}} exception. + 1. Otherwise, + 1. [=Construct a WebAssembly module object=] from |module| and |bytes|, and let |moduleObject| be the result. + 1. [=Resolve=] |promise| with |moduleObject|. + 1. Return |promise|. +
+ +
+ The compile(|bytes|) method, when invoked, performs the following steps: + 1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|. + 1. [=Asynchronously compile a WebAssembly module=] from |stableBytes| and return the result. +
+ +
+ To read the imports from a WebAssembly module |module| from imports object |importObject|, perform the following steps: + 1. If |module|.[=𝗂𝗆𝗉𝗈𝗋𝗍𝗌=] is not an empty list, and |importObject| is undefined, throw a {{TypeError}} exception. + 1. Let |imports| be an empty [=list=] of [=external value=]s. + 1. For each (|moduleName|, |componentName|, |externtype|) in [=module_imports=](|module|), do + 1. Let |o| be ? [=Get=](|importObject|, |moduleName|). + 1. If [=Type=](|o|) is not Object, throw a {{TypeError}} exception. + 1. Let |v| be ? [=Get=](|o|, |componentName|) + 1. If |externtype| is of the form [=𝖿𝗎𝗇𝖼=] |functype|, + 1. If [=IsCallable=](|v|) is false, throw a {{LinkError}} exception. + 1. If |v| has a \[[FunctionAddress]] internal slot, and therefore is an [=Exported Function=], + 1. Let |funcaddr| be the value of |v|'s \[[FunctionAddress]] internal slot. + + Note: The signature is checked by [=module_instantiate=] invoked below. + 1. Otherwise, + 1. [=Create a host function=] from |v| and |functype|, and let |funcaddr| be the result. + 1. Let |index| be the number of external functions in |imports|. This value |index| is known as the index of the host function |funcaddr|. + 1. Let |externfunc| be the [=external value=] [=external value|𝖿𝗎𝗇𝖼=] |funcaddr|. + 1. [=Append=] |externfunc| to |imports|. + 1. If |externtype| is of the form [=𝗀𝗅𝗈𝖻𝖺𝗅=] mut |valtype|, + 1. If [=Type=](|v|) is Number, + 1. If |valtype| is [=𝗂𝟨𝟦=], throw a {{LinkError}} exception. + 1. Let |value| be [=ToWebAssemblyValue=](|v|, |valtype|) + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let (|store|, |globaladdr|) be [=global_alloc=](|store|, [=const=] |valtype|, |value|). + 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. + 1. If |v| is a {{Global}} instance, + 1. Let |globaladdr| be |v|.\[[Global]] + 1. Otherwise, + 1. Throw a {{LinkError}} exception. + 1. Let |externglobal| be [=external value|𝗀𝗅𝗈𝖻𝖺𝗅=] |globaladdr|. + 1. [=Append=] |externglobal| to |imports|. + 1. If |externtype| is of the form [=𝗆𝖾𝗆=] memtype, + 1. If |v| is not a {{Memory}} object, throw a {{LinkError}} exception. + 1. Note: [=module_instantiate=] invoked below will check the imported {{Memory}}'s size against the importing module's requirements. + 1. Let |externmem| be the [=external value=] [=external value|𝗆𝖾𝗆=] |v|.\[[Memory]]. + 1. [=Append=] |externmem| to |imports|. + 1. Otherwise, |externtype| is of the form [=𝗍𝖺𝖻𝗅𝖾=] tabletype, + 1. If |v| is not a {{Table}} instance, throw a {{LinkError}} exception. + 1. Note: The table's length, etc. is checked by [=module_instantiate=] invoked below. + 1. Let |tableaddr| be |v|.\[[Table]] + 1. Let |externtable| be the [=external value=] [=external value|𝗍𝖺𝖻𝗅𝖾=] |tableaddr|. + 1. [=Append=] |externtable| to |imports|. + 1. Return |imports|. +
+ +
+ To create an exports object from a WebAssembly module |module| and instance |instance|, perform the following steps: + 1. Let |exportsObject| be ! [=ObjectCreate=](null). + 1. For each pair (|name|, |externtype|) in [=module_exports=](|module|), + 1. Let |externval| be [=instance_export=](|instance|, |name|). + 1. Assert: |externval| is not [=error=]. + 1. If |externtype| is of the form [=𝖿𝗎𝗇𝖼=] functype, + 1. Assert: |externval| is of the form [=external value|𝖿𝗎𝗇𝖼=] |funcaddr|. + 1. Let [=external value|𝖿𝗎𝗇𝖼=] |funcaddr| be |externval|. + 1. Let |func| be the result of creating [=a new Exported Function=] from |funcaddr|. + 1. Let |value| be |func|. + 1. If |externtype| is of the form [=𝗀𝗅𝗈𝖻𝖺𝗅=] globaltype, + 1. Assert: |externval| is of the form [=external value|𝗀𝗅𝗈𝖻𝖺𝗅=] |globaladdr|. + 1. Let [=external value|𝗀𝗅𝗈𝖻𝖺𝗅=] |globaladdr| be |externval|. + 1. Let |global| be [=create a global object|a new Global object=] created from |globaladdr|. + 1. Let |value| be |global|. + 1. If |externtype| is of the form [=𝗆𝖾𝗆=] memtype, + 1. Assert: |externval| is of the form [=external value|𝗆𝖾𝗆=] |memaddr|. + 1. Let [=external value|𝗆𝖾𝗆=] |memaddr| be |externval|. + 1. Let |memory| be [=create a memory object|a new Memory object=] created from |memaddr|. + 1. Let |value| be |memory|. + 1. Otherwise, |externtype| is of the form [=𝗍𝖺𝖻𝗅𝖾=] tabletype, + 1. Assert: |externval| is of the form [=external value|𝗍𝖺𝖻𝗅𝖾=] |tableaddr|. + 1. Let [=external value|𝗍𝖺𝖻𝗅𝖾=] |tableaddr| be |externval|. + 1. Let |table| be [=create a Table object|a new Table object=] created from |tableaddr|. + 1. Let |value| be |table|. + 1. Let |status| be ! [=CreateDataProperty=](|exportsObject|, |name|, |value|). + 1. Assert: |status| is true. + + Note: the validity and uniqueness checks performed during [=WebAssembly module validation=] ensure that each property name is valid and no properties are defined twice. + 1. Perform ! [=SetIntegrityLevel=](|exportsObject|, `"frozen"`). + 1. Return |exportsObject|. +
+ +
+ To initialize an instance object |instanceObject| from a WebAssembly module |module| and instance |instance|, perform the following steps: + + 1. [=Create an exports object=] from |module| and |instance| and let |exportsObject| be the result. + 1. Set |instanceObject|.\[[Instance]] to |instance|. + 1. Set |instanceObject|.\[[Exports]] to |exportsObject|. +
+ +
+ To instantiate the core of a WebAssembly module from a module |module| and imports |imports|, perform the following steps: + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let |result| be [=module_instantiate=](|store|, |module|, |imports|). + 1. If |result| is [=error=], throw an appropriate exception type: + * A {{LinkError}} exception for most cases which occur during linking. + * If the error came when running the start function, throw a {{RuntimeError}} for most errors which occur from WebAssembly, or the error object propagated from inner ECMAScript code. + * Another error type if appropriate, for example an out-of-memory exception, as documented in the WebAssembly error mapping. + 1. Let (|store|, |instance|) be |result|. + 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. + 1. Return |instance|. +
+ +
+ To asynchronously instantiate a WebAssembly module from a {{Module}} |moduleObject| and imports |importObject|, perform the following steps: + 1. Let |promise| be [=a new promise=]. + 1. Let |module| be |moduleObject|.\[[Module]]. + 1. [=Read the imports=] of |module| with imports |importObject|, and let |imports| be the result. + If this operation throws an exception, catch it, [=reject=] |promise| with the exception, and return |promise|. + 1. [=Queue a task=] to perform the following steps: + 1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result. + If this throws an exception, catch it, [=reject=] |promise| with the exception, and terminate these substeps. + 1. Let |instanceObject| be a [=/new=] {{Instance}}. + 1. [=initialize an instance object|Initialize=] |instanceObject| from |module| and |instance|. + If this throws an exception, catch it, [=reject=] |promise| with the exception, and terminate these substeps. + 1. [=Resolve=] |promise| with |instanceObject|. + 1. Return |promise|. +
+ +
+ To instantiate a WebAssembly module from a {{Module}} |moduleObject| and imports |importObject|, perform the following steps: + 1. Let |module| be |moduleObject|.\[[Module]]. + 1. [=Read the imports=] of |module| with imports |importObject|, and let |imports| be the result. + 1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result. + 1. Let |instanceObject| be a [=/new=] {{Instance}}. + 1. [=initialize an instance object|Initialize=] |instanceObject| from |module| and |instance|. + 1. Return |instanceObject|. +
+ +
+ To instantiate a promise of a module |promiseOfModule| with imports |importObject|, perform the following steps: + + 1. Let |promise| be [=a new promise=] + 1. [=Upon fulfillment=] of |promiseOfModule| with value |module|: + 1. [=instantiate a WebAssembly module|Instantiate the WebAssembly module=] |module| importing |importObject|, and let |instance| be the result. If this throws an exception, catch it, [=reject=] |promise| with the exception, and abort these substeps. + 1. Let |result| be a {{WebAssemblyInstantiatedSource}} dictionary with {{WebAssemblyInstantiatedSource/module}} set to |module| and {{WebAssemblyInstantiatedSource/instance}} set to |instance|. + 1. [=Resolve=] |promise| with |result|. + 1. [=Upon rejection=] of |promiseOfModule| with reason |reason|: + 1. [=Reject=] |promise| with |reason|. + 1. Return |promise|. + + Note: It would be valid to perform certain parts of the instantiation [=in parallel=], but several parts need to happen in the event loop, including JavaScript operations to access the |importObject| and execution of the start function. +
+ +
+ The instantiate(|bytes|, |importObject|) method, when invoked, performs the following steps: + 1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|. + 1. [=Asynchronously compile a WebAssembly module=] from |stableBytes| and let |promiseOfModule| be the result. + 1. [=Instantiate a promise of a module|Instantiate=] |promiseOfModule| with imports |importObject| and return the result. +
+ +
+ The instantiate(|moduleObject|, |importObject|) method, when invoked, performs the following steps: + 1. [=asynchronously instantiate a WebAssembly module|Asynchronously instantiate the WebAssembly module=] |moduleObject| importing |importObject|, and return the result. +
+ +Note: A follow-on streaming API is documented in the WebAssembly Web API. + +

Modules

+ +
+enum ImportExportKind {
+  "function",
+  "table",
+  "memory",
+  "global"
+};
+
+dictionary ModuleExportDescriptor {
+  required USVString name;
+  required ImportExportKind kind;
+  // Note: Other fields such as signature may be added in the future.
+};
+
+dictionary ModuleImportDescriptor {
+  required USVString module;
+  required USVString name;
+  required ImportExportKind kind;
+};
+
+[LegacyNamespace=WebAssembly, Constructor(BufferSource bytes), Exposed=(Window,Worker,Worklet)]
+interface Module {
+  static sequence<ModuleExportDescriptor> exports(Module moduleObject);
+  static sequence<ModuleImportDescriptor> imports(Module moduleObject);
+  static sequence<ArrayBuffer> customSections(Module moduleObject, DOMString sectionName);
+};
+
+ +
+ The string value of the extern type |type| is + * "function" if |type| is of the form [=𝖿𝗎𝗇𝖼=] functype + * "table" if |type| is of the form [=𝗍𝖺𝖻𝗅𝖾=] tabletype + * "memory" if |type| is of the form [=𝗆𝖾𝗆=] memtype + * "global" if |type| is of the form [=𝗀𝗅𝗈𝖻𝖺𝗅=] globaltype +
+ +
+ The exports(|moduleObject|) method, when invoked, performs the following steps: + 1. Let |module| be |moduleObject|.\[[Module]]. + 1. Let |exports| be an empty [=list=]. + 1. For each (|name|, |type|) in [=module_exports=](|module|) + 1. Let |kind| be the [=string value of the extern type=] |type|. + 1. Let |obj| be a new {{ModuleExportDescriptor}} dictionary with {{ModuleExportDescriptor/name}} |name| and {{ModuleExportDescriptor/kind}} |kind|. + 1. [=Append=] |obj| to the end of |exports|. + 1. Return |exports|. +
+ +
+ The imports(|moduleObject|) method, when invoked, performs the following steps: + 1. Let |module| be |moduleObject|.\[[Module]]. + 1. Let |imports| be an empty [=list=]. + 1. For each (|moduleName|, |name|, |type|) in [=module_imports=](|module|), + 1. Let |kind| be the [=string value of the extern type=] |type|. + 1. Let |obj| be a new {{ModuleImportDescriptor}} dictionary with {{ModuleImportDescriptor/module}} |moduleName|, {{ModuleImportDescriptor/name}} |name| and {{ModuleImportDescriptor/kind}} |kind|. + 1. [=Append=] |obj| to the end of |imports|. + 1. Return |imports|. +
+ +
+ The customSections(|moduleObject|, |sectionName|) method, when invoked, performs the following steps: + 1. Let |bytes| be |moduleObject|.\[[Bytes]]. + 1. Let |customSections| be an empty [=list=] of {{ArrayBuffer}}s. + 1. For each [=custom section=] |customSection| in |bytes|, interpreted according to the [=module grammar=], + 1. Let |name| be the name of |customSection|, [=UTF-8 decode without BOM or fail|decoded as UTF-8=]. + 1. Assert: |name| is not failure (|moduleObject|.\[[Module]] is [=valid=]). + 1. If |name| equals |sectionName| as string values, + 1. [=Append=] a new {{ArrayBuffer}} containing a copy of the bytes in |bytes| for the range matched by this [=customsec=] production. + 1. Return |customSections|. +
+ +
+ The Module(|bytes|) constructor, when invoked, performs the follwing steps: + + 1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|. + 1. [=Compile a WebAssembly module|Compile the WebAssembly module=] |stableBytes| and store the result as |module|. + 1. If |module| is [=error=], throw a {{CompileError}} exception. + 1. Set **this**.\[[Module]] to |module|. + 1. Set **this**.\[[Bytes]] to |stableBytes|. +
+ +

Instances

+ +
+[LegacyNamespace=WebAssembly, Constructor(Module module, optional object importObject), Exposed=(Window,Worker,Worklet)]
+interface Instance {
+  readonly attribute object exports;
+};
+
+ +
+ The Instance(|module|, |importObject|) constructor, when invoked, runs the following steps: + 1. Let |module| be |module|.\[[Module]]. + 1. [=Read the imports=] of |module| with imports |importObject|, and let |imports| be the result. + 1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result. + 1. [=initialize an instance object|Initialize=] **this** from |module| and |instance|. +
+ +
+ The getter of the exports attribute of {{Instance}} returns **this**.\[[Exports]]. +
+ +

Memories

+ +
+dictionary MemoryDescriptor {
+  required [EnforceRange] unsigned long initial;
+  [EnforceRange] unsigned long maximum;
+};
+
+[LegacyNamespace=WebAssembly, Constructor(MemoryDescriptor descriptor), Exposed=(Window,Worker,Worklet)]
+interface Memory {
+  unsigned long grow([EnforceRange] unsigned long delta);
+  readonly attribute ArrayBuffer buffer;
+};
+
+ +
+A {{Memory}} object represents a single [=memory instance=] +which can be simultaneously referenced by multiple {{Instance}} objects. Each +{{Memory}} object has the following internal slots: + + * \[[Memory]] : a [=memory address=] + * \[[BufferObject]] : an {{ArrayBuffer}} whose [=Data Block=] is [=identified with=] the above memory address +
+ +
+ To create a memory buffer from a [=memory address=] |memaddr|, perform the following steps: + + 1. Let |block| be a [=Data Block=] which is [=identified with=] the underlying memory of |memaddr|. + 1. Let |buffer| be a new {{ArrayBuffer}} whose \[[ArrayBufferData]] is |block| and \[[ArrayBufferByteLength]] is set to the length of |block|. + 1. Set |buffer|.\[[ArrayBufferDetachKey]] to "WebAssembly.Memory". + 1. Return |buffer|. +
+ +
+ To initialize a memory object |memory| from a [=memory address=] |memaddr|, perform the following steps: + 1. Let |map| be the [=surrounding agent=]'s associated [=Memory object cache=]. + 1. Assert: |map|[|memaddr|] doesn't [=map/exist=]. + 1. Let |buffer| be a the result of [=create a memory buffer|creating a memory buffer=] from |memaddr|. + 1. Set |memory|.\[[Memory]] to |memaddr|. + 1. Set |memory|.\[[BufferObject]] to |buffer|. + 1. [=map/Set=] |map|[|memaddr|] to |memory|. +
+ +
+ To create a memory object from a [=memory address=] |memaddr|, perform the following steps: + + 1. Let |map| be the [=surrounding agent=]'s associated [=Memory object cache=]. + 1. If |map|[|memaddr|] [=map/exists=], + 1. Return |map|[|memaddr|]. + 1. Let |memory| be a [=/new=] {{Memory}}. + 1. [=initialize a memory object|Initialize=] |memory| from |memaddr|. + 1. Return |memory|. +
+ +
+ The Memory(|descriptor|) constructor, when invoked, performs the following steps: + 1. let |initial| be |descriptor|["initial"]. + 1. If |descriptor|["maximum"] is [=present=], let |maximum| be |descriptor|["maximum"]; otherwise, let |maximum| be empty. + 1. If |maximum| is not empty and |maximum| < |initial|, throw a {{RangeError}} exception. + 1. Let |memtype| be { min |initial|, max |maximum| } + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let (|store|, |memaddr|) be [=mem_alloc=](|store|, |memtype|). If allocation fails, throw a {{RangeError}} exception. + 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. + 1. [=initialize a memory object|Initialize=] **this** from |memaddr|. +
+ +
+ To reset the Memory buffer of |memaddr|, perform the following steps: + + 1. Let |map| be the [=surrounding agent=]'s associated [=Memory object cache=]. + 1. Assert: |map|[|memaddr|] [=map/exists=]. + 1. Let |memory| be |map|[|memaddr|]. + 1. Perform ! [=DetachArrayBuffer=](|memory|.\[[BufferObject]], "WebAssembly.Memory"). + 1. Let |buffer| be a the result of [=create a memory buffer|creating a memory buffer=] from |memaddr|. + 1. Set |memory|.\[[BufferObject]] to |buffer|. +
+ +
+ The grow(|delta|) method, when invoked, performs the following steps: + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let |memaddr| be **this**.\[[Memory]]. + 1. Let |ret| be the [=mem_size=](|store|, |memaddr|). + 1. Let |store| be [=mem_grow=](|store|, |memaddr|, |delta|). + 1. If |store| is [=error=], throw a {{RangeError}} exception. + 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. + 1. [=Reset the memory buffer=] of |memaddr|. + 1. Return |ret|. +
+ +Immediately after a WebAssembly [=memory.grow=] instruction executes, perform the following steps: + +
+ 1. If the top of the stack is not [=𝗂𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] (−1), then: + 1. Let |frame| be the [=current frame=]. + 1. Assert: due to validation, |frame|.[=𝗆𝗈𝖽𝗎𝗅𝖾=].[=𝗆𝖾𝗆𝖺𝖽𝖽𝗋𝗌=][0] exists. + 1. Let |memaddr| be the memory address |frame|.[=𝗆𝗈𝖽𝗎𝗅𝖾=].[=𝗆𝖾𝗆𝖺𝖽𝖽𝗋𝗌=][0]. + 1. [=Reset the memory buffer=] of |memaddr|. +
+ +
+ The getter of the buffer attribute of {{Memory}} returns **this**.\[[BufferObject]]. +
+ +

Tables

+ +
+enum TableKind {
+  "anyref",
+  "anyfunc",
+  // Note: More values may be added in future iterations,
+  // e.g., typed function references, typed GC references
+};
+
+dictionary TableDescriptor {
+  required TableKind element;
+  required [EnforceRange] unsigned long initial;
+  [EnforceRange] unsigned long maximum;
+};
+
+[LegacyNamespace=WebAssembly, Constructor(TableDescriptor descriptor), Exposed=(Window,Worker,Worklet)]
+interface Table {
+  unsigned long grow([EnforceRange] unsigned long delta);
+  Function? get([EnforceRange] unsigned long index);
+  void set([EnforceRange] unsigned long index, Function? value);
+  readonly attribute unsigned long length;
+};
+
+ +
+A {{Table}} object represents a single [=table instance=] +which can be simultaneously referenced by multiple {{Instance}} objects. Each +{{Table}} object has the following internal slots: + + * \[[Table]] : a [=table address=] + * \[[Values]] : a List whose elements are either null or [=Exported Function=]s. +
+ +
+ To initialize a table object |table| from a [=table address=] |tableaddr|, perform the following steps: + 1. Let |map| be the [=surrounding agent=]'s associated [=Table object cache=]. + 1. Assert: |map|[|tableaddr|] doesn't [=map/exist=]. + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let |values| be a list whose length is [=table_size=](|store|, |tableaddr|) where each element is null. + 1. Set |table|.\[[Table]] to |tableaddr|. + 1. Set |table|.\[[Values]] to |values|. + 1. [=map/Set=] |map|[|tableaddr|] to |table|. +
+ +
+ To create a table object from a [=table address=] |tableaddr|, perform the following steps: + 1. Let |map| be the [=surrounding agent=]'s associated [=Table object cache=]. + 1. If |map|[|tableaddr|] [=map/exists=], + 1. Return |map|[|tableaddr|]. + 1. Let |table| be a [=/new=] {{Table}}. + 1. [=initialize a table object|Initialize=] |table| from |tableaddr|. + 1. Return |table|. +
+ +
+ The Table(|descriptor|) constructor, when invoked, performs the following steps: + 1. let |initial| be |descriptor|["initial"]. + 1. If |descriptor|["maximum"] is [=present=], let |maximum| be |descriptor|["maximum"]; otherwise, let |maximum| be empty. + 1. If |maximum| is not empty and |maximum| < |initial|, throw a {{RangeError}} exception. + 1. Let |type| be the [=table type=] {[=table type|𝗆𝗂𝗇=] n, [=table type|𝗆𝖺𝗑=] |maximum|} [=table type|funcref=]. + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let (|store|, |tableaddr|) be [=table_alloc=](|store|, |type|, [=ref.null=]). + 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. + 1. [=initialize a table object|Initialize=] **this** from |tableaddr|. +
+ +
+ The grow(|delta|) method, when invoked, performs the following steps: + 1. Let |tableaddr| be **this**.\[[Table]]. + 1. Let |initialSize| be the length of **this**.\[[Values]]. + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let |result| be [=table_grow=](|store|, |tableaddr|, |delta|, [=ref.null=]). + 1. If |result| is [=error=], throw a {{RangeError}} exception. + + Note: The above exception may happen due to either insufficient memory or an invalid size parameter. + + 1. Set the [=surrounding agent=]'s [=associated store=] to |result|. + 1. [=Append=] null to **this**.\[[Values]] |delta| times. + 1. Return |initialSize|. +
+ +
+ The getter of the length attribute of {{Table}} returns the length of **this**.\[[Values]]. +
+ +
+ The get(|index|) method, when invoked, performs the following steps: + 1. Let |values| be **this**.\[[Values]]. + 1. Let |size| be the length of |values|. + 1. If |index| ≥ |size|, throw a {{RangeError}} exception. + 1. Return |values|[|index|]. +
+ +
+ The set(|index|, |value|) method, when invoked, performs the following steps: + 1. Let |tableaddr| be **this**.\[[Table]]. + 1. Let |values| be **this**.\[[Values]]. + 1. If |value| is null, let |ref| be [=ref.null=]. + 1. Otherwise, + 1. If |value| does not have a \[[FunctionAddress]] internal slot, throw a {{TypeError}} exception. + 1. Let |ref| be [=ref.func=] |value|.\[[FunctionAddress]]. + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let |store| be [=table_write=](|store|, |tableaddr|, |index|, |ref|). + 1. If |store| is [=error=], throw a {{RangeError}} exception. + 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. + 1. Set |values|[|index|] to |value|. + 1. Return undefined. +
+ +

Globals

+ +
+enum ValueType {
+  "i32",
+  "i64",
+  "f32",
+  "f64"
+};
+
+ +Note: this type may be extended with additional cases in future versions of WebAssembly. + +
+dictionary GlobalDescriptor {
+  required ValueType value;
+  boolean mutable = false;
+};
+
+[LegacyNamespace=WebAssembly, Constructor(GlobalDescriptor descriptor, optional any v), Exposed=(Window,Worker,Worklet)]
+interface Global {
+  any valueOf();
+  attribute any value;
+};
+
+ +
+A {{Global}} object represents a single [=global instance=] +which can be simultaneously referenced by multiple {{Instance}} objects. Each +{{Global}} object has one internal slot: + + * \[[Global]] : a [=global address=] +
+ +
+ To initialize a global object |global| from a [=global address=] |globaladdr|, perform the following steps: + 1. Let |map| be the [=surrounding agent=]'s associated [=Global object cache=]. + 1. Assert: |map|[|globaladdr|] doesn't [=map/exist=]. + 1. Set |global|.\[[Global]] to |globaladdr|. + 1. [=map/Set=] |map|[|globaladdr|] to |global|. +
+ +
+ To create a global object from a [=global address=] |globaladdr|, perform the following steps: + 1. Let |map| be the current [=agent=]'s associated [=Global object cache=]. + 1. If |map|[|globaladdr|] [=map/exists=], + 1. Return |map|[|globaladdr|]. + 1. Let |global| be a [=/new=] {{Global}}. + 1. [=initialize a global object|Initialize=] |global| from |globaladdr|. + 1. Return |global|. +
+ +
+ The algorithm ToValueType(|s|) performs the following steps: + 1. If |s| equals "i32", return [=𝗂𝟥𝟤=]. + 1. If |s| equals "i64", return [=𝗂𝟨𝟦=]. + 1. If |s| equals "f32", return [=𝖿𝟥𝟤=]. + 1. If |s| equals "f64", return [=𝖿𝟨𝟦=]. +
+ +
+ The algorithm DefaultValue(|valuetype|) performs the following steps: + 1. If |valuetype| equals [=𝗂𝟥𝟤=], return [=𝗂𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] 0. + 1. If |valuetype| equals [=𝗂𝟨𝟦=], return [=𝗂𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] 0. + 1. If |valuetype| equals [=𝖿𝟥𝟤=], return [=𝖿𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] 0. + 1. If |valuetype| equals [=𝖿𝟨𝟦=], return [=𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] 0. + 1. Assert: This step is not reached. +
+ +
+ The Global(|descriptor|, |v|) constructor, when invoked, performs the following steps: + 1. Let |mutable| be |descriptor|["mutable"]. + 1. Let |valuetype| be [=ToValueType=](|descriptor|["value"]). + 1. If |v| is undefined, + 1. let |value| be [=DefaultValue=](|valuetype|). + 1. Otherwise, + 1. If |valuetype| is [=𝗂𝟨𝟦=], throw a {{TypeError}} exception. + 1. Let |value| be [=ToWebAssemblyValue=](|v|, |valuetype|). + 1. If |mutable| is true, let |globaltype| be [=var=] |valuetype|; otherwise, let |globaltype| be [=const=] |valuetype|. + 1. Let |store| be the current agent's [=associated store=]. + 1. Let (|store|, |globaladdr|) be [=global_alloc=](|store|, |globaltype|, |value|). + 1. Set the current agent's [=associated store=] to |store|. + 1. [=initialize a global object|Initialize=] **this** from |globaladdr|. +
+ +
+ The algorithm GetGlobalValue({{Global}} |global|) performs the following steps: + 1. Let |store| be the current agent's [=associated store=]. + 1. Let |globaladdr| be |global|.\[[Global]]. + 1. Let |globaltype| be [=global_type=](|store|, |globaladdr|). + 1. If |globaltype| is of the form mut [=𝗂𝟨𝟦=], throw a {{TypeError}}. + 1. Let |value| be [=global_read=](|store|, |globaladdr|). + 1. Return [=ToJSValue=](|value|). +
+ +
+ The getter of the value attribute of {{Global}}, when invoked, performs the following steps: + 1. Return [=GetGlobalValue=](**this**). + + The setter of the value attribute of {{Global}}, when invoked, performs the following steps: + 1. Let |store| be the current agent's [=associated store=]. + 1. Let |globaladdr| be **this**.\[[Global]]. + 1. Let |globaltype| be [=global_type=](|store|, |globaladdr|), where |globaltype| is of the form |mut| |valuetype|. + 1. If |mut| is [=const=], throw a {{TypeError}}. + 1. If |valuetype| is [=𝗂𝟨𝟦=], throw a {{TypeError}}. + 1. Let |value| be [=ToWebAssemblyValue=](**the given value**, |valuetype|). + 1. Let |store| be [=global_write=](|store|, |globaladdr|, |value|). + 1. If |store| is [=error=], throw a {{RangeError}} exception. + 1. Set the current agent's [=associated store=] to |store|. +
+ +
+ The valueOf() method, when invoked, performs the following steps: + 1. Return [=GetGlobalValue=](**this**). +
+ +

Exported Functions

+ +A WebAssembly function is made available in JavaScript as an Exported Function. +Exported Functions are [=Built-in Function Objects=] which are not constructors, and which have a \[[FunctionAddress]] internal slot. +This slot holds a [=function address=] relative to the [=surrounding agent=]'s [=associated store=]. + +
+ The name of the WebAssembly function |funcaddr| is found by performing the following steps: + + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let |funcinst| be |store|.𝖿𝗎𝗇𝖼𝗌[|funcaddr|]. + 1. If |funcinst| is of the form {𝗍𝗒𝗉𝖾 functype, 𝗁𝗈𝗌𝗍𝖼𝗈𝖽𝖾 |hostfunc|}, + 1. Assert: |hostfunc| is a JavaScript object and [=IsCallable=](|hostfunc|) is true. + 1. Let |index| be the [=index of the host function=] |funcaddr|. + 1. Otherwise, + 1. Let |moduleinst| be |funcinst|.𝗆𝗈𝖽𝗎𝗅𝖾. + 1. Assert: |funcaddr| is contained in |moduleinst|.𝖿𝗎𝗇𝖼𝖺𝖽𝖽𝗋𝗌. + 1. Let |index| be the index of |moduleinst|.𝖿𝗎𝗇𝖼𝖺𝖽𝖽𝗋𝗌 where |funcaddr| is found. + 1. Return ! [=ToString=](|index|). +
+ +
+ To create a new Exported Function from a WebAssembly [=function address=] |funcaddr|, perform the following steps: + + 1. Let |map| be the [=surrounding agent=]'s associated [=Exported Function cache=]. + 1. If |map|[|funcaddr|] [=map/exists=], + 1. Return |map|[|funcaddr|]. + 1. Let |steps| be "[=call an Exported Function|call the Exported Function=] |funcaddr| with arguments." + 1. Let |realm| be the [=current Realm=]. + 1. Let |function| be [=CreateBuiltinFunction=](|realm|, |steps|, [=%FunctionPrototype%=], « \[[FunctionAddress]] »). + 1. Set |function|.\[[FunctionAddress]] to |funcaddr|. + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let |functype| be [=func_type=](|store|, |funcaddr|). + 1. Let [|paramTypes|] → [resultTypes] be |functype|. + 1. Let |arity| be the length of |paramTypes|. + 1. Perform ! [=SetFunctionLength=](|function|, |arity|). + 1. Let |name| be the [=name of the WebAssembly function=] |funcaddr|. + 1. Perform ! [=SetFunctionName=](|function|, |name|). + 1. [=map/Set=] |map|[|funcaddr|] to |function|. + 1. Return |function|. +
+ +
+ To call an Exported Function with [=function address=] |funcaddr| and a [=list=] of JavaScript arguments |argValues|, perform the following steps: + + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let |functype| be [=func_type=](|store|, |funcaddr|). + 1. Let [|parameters|] → [|results|] be |functype|. + 1. If |parameters| or |results| contains an [=𝗂𝟨𝟦=], throw a {{TypeError}}. + + Note: the above error is thrown each time the \[[Call]] method is invoked. + + 5. Let |args| be an empty list of WebAssembly values. + 1. Let |i| be 0. + 1. For each type |t| of |parameters|, + 1. If the length of |argValues| > |i|, let |arg| be |argValues|[|i|]. + 1. Otherwise, let |arg| be undefined. + 1. [=Append=] [=ToWebAssemblyValue=](|arg|, |t|, {{TypeError}}) to |args|. + 1. Set |i| to |i| + 1. + 1. Let |argsSeq| be a WebAssembly [=sequence=] containing the elements of |args|. + 1. Let (|store|, |ret|) be the result of [=func_invoke=](|store|, |funcaddr|, |argsSeq|). + 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. + 1. If |ret| is [=error=], throw an exception. This exception should be a WebAssembly {{RuntimeError}} exception, unless otherwise indicated by the WebAssembly error mapping. + 1. If |ret| is empty, return undefined. + 1. Otherwise, return [=ToJSValue=](|v|), where |v| is the singular element of |ret|. +
+ +Note: [=call an Exported Function|Calling an Exported Function=] executes in the \[[Realm]] of the callee Exported Function, as per the definition of [=built-in function objects=]. + +Note: Exported Functions do not have a \[[Construct]] method and thus it is not possible to call one with the `new` operator. + +
+ To run a host function from the JavaScript object |func| and type |functype|, perform the following steps: + + 1. Let [|parameters|] → [|results|] be |functype|. + 1. Assert: |results|'s [=list/size=] is at most one. + 1. If either |parameters| or |results| contains [=𝗂𝟨𝟦=], throw a {{TypeError}}. + 1. Let |arguments| be a [=list=] of the arguments of the invocation of this function. + 1. Let |jsArguments| be an empty [=list=]. + 1. For each |arg| in |arguments|, + 1. [=list/Append=] ! [=ToJSValue=](|arg|) to |jsArguments|. + 1. Let |ret| be ? [=Call=](|func|, undefined, |jsArguments|). + 1. If |results| is [=list/empty=], return undefined. + 1. Otherwise, return ? [=ToWebAssemblyValue=](|ret|, |results|[0]). +
+ +
+ To create a host function from the JavaScript object |func| and type |functype|, perform the following steps: + + 1. Let |hostfunc| be a [=host function=] which performs the following steps when called: + 1. Let |result| be the result of [=run a host function|running a host function=] from |func| and |functype|. + 1. Assert: |result|.\[[Type]] is throw or return. + 1. If |result|.\[[Type]] is [=throw=], then trigger a WebAssembly trap, and propagate |result|.\[[Value]] to the enclosing JavaScript. + 1. Otherwise, return |result|.\[[Value]]. + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let (|store|, |funcaddr|) be [=func_alloc=](|store|, |functype|, |hostfunc|). + 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. + 1. Return |funcaddr| +
+ +
+The algorithm ToJSValue(|w|) coerces a [=WebAssembly value=] to a JavaScript value performs the following steps: + +1. Assert: |w| is not of the form [=𝗂𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] i64. +1. If |w| is of the form [=𝗂𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] |i32|, return [=the Number value=] for [=signed_32=](|i32|). +1. If |w| is of the form [=𝖿𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] |f32|, return [=the Number value=] for |f32|. +1. If |w| is of the form [=𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] |f64|, return [=the Number value=] for |f64|. +1. If |w| is of the form [=ref.null=], return null. +1. If |w| is of the form [=ref.func=] |funcaddr|, return the result of creating [=a new Exported Function=] from |funcaddr|. +1. If |w| is of the form [=ref.host=] |hostaddr|, return the result of [=retrieving a host value=] from |hostaddr|. + + + +Note: Number values which are equal to NaN may have various observable NaN payloads; see [=NumberToRawBytes=] for details. +
+ +
+ For retrieving a host value from a [=host address=] |hostaddr|, perform the following steps: + 1. Let |map| be the [=surrounding agent=]'s associated [=host value cache=]. + 1. Assert: |map|[|hostaddr|] [=map/exists=]. + 1. Return |map|[|hostaddr|]. +
+ +
+The algorithm ToWebAssemblyValue(|v|, |type|, |error|) coerces a JavaScript value to a [=WebAssembly value=] performs the following steps: + + +1. Assert: |type| is not [=𝗂𝟨𝟦=]. +1. If |type| is [=𝗂𝟥𝟤=], + 1. Let |i32| be ? [=ToInt32=](|v|). + 1. Return [=𝗂𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] |i32|. +1. If |type| is [=𝖿𝟥𝟤=], + 1. Let |f32| be ? [=ToNumber=](|v|) rounded to the nearest representable value using IEEE 754-2008 round to nearest, ties to even mode. + 1. Return [=𝖿𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] |f32|. +1. If |type| is [=𝖿𝟨𝟦=], + 1. Let |f64| be ? [=ToNumber=](|v|). + 1. Return [=𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] |f64|. +1. If |type| is [=anyref=], + 1. Return the result of [=allocating a host address=] for |v|. +1. If |type| is [=funcref=], + 1. If |v| is not an [=Exported function=] or null, throw |error|. + 1. Return the result of [=allocating a host address=] for |v|. + +
+ +
+ For allocating a host address for a value |v|, perform the following steps: + 1. If |v| is null, + 1. Return [=ref.null=]. + 1. If |v| is an [=Exported Function=], + 1. Let |funcaddr| be the value of |v|'s \[[FunctionAddress]] internal slot. + 1. Return [=ref.func=] |funcaddr|. + 1. Let |map| be the [=surrounding agent=]'s associated [=host value cache=]. + 1. If a [=host address=] |hostaddr| exists such that |map|[|hostaddr|] is the same as |v|, + 1. Return [=ref.host=] |hostaddr|. + 1. Let [=host address=] |hostaddr| be the smallest address such that |map|[|hostaddr|] [=map/exists=] is false. + 1. [=map/Set=] |map|[|hostaddr|] to |v|. + 1. Return [=ref.host=] |hostaddr|. +
+ + +

Error Objects

+ +WebAssembly defines the following Error classes: {{CompileError}}, {{LinkError}}, and {{RuntimeError}}. WebAssembly errors have the following custom bindings: +- Unlike normal interface types, the interface prototype object for these exception classes must have as its \[[Prototype]] the intrinsic object [=%ErrorPrototype%=]. +- The constructor and properties of WebAssembly errors is as specified for {{NativeError}}. +- If an implementation gives native Error objects special powers or nonstandard properties (such as a stack property), it should also expose those on these exception instances. + +
+[LegacyNamespace=WebAssembly]
+interface CompileError { };
+
+[LegacyNamespace=WebAssembly]
+interface LinkError { };
+
+[LegacyNamespace=WebAssembly]
+interface RuntimeError { };
+
+ +

Error Condition Mappings to JavaScript

+ +Running WebAssembly programs encounter certain events which halt execution of the WebAssembly code. +WebAssembly code (currently) +has no way to catch these conditions and thus an exception will necessarily +propagate to the enclosing non-WebAssembly caller (whether it is a browser, +JavaScript or another runtime system) where it is handled like a normal JavaScript exception. + +If WebAssembly calls JavaScript via import and the JavaScript throws an +exception, the exception is propagated through the WebAssembly activation to the +enclosing caller. + +Because JavaScript exceptions can be handled, and JavaScript can continue to +call WebAssembly exports after a trap has been handled, traps do not, in +general, prevent future execution. + +

Stack Overflow

+ +Whenever a stack overflow occurs in +WebAssembly code, the same class of exception is thrown as for a stack overflow in +JavaScript. The particular exception here is implementation-defined in both cases. + +Note: ECMAScript doesn't specify any sort of behavior on stack overflow; implementations have been observed to throw {{RangeError}}, InternalError or Error. Any is valid here. + +

Out of Memory

+ +Whenever validation, compilation or instantiation run out of memory, the +same class of exception is thrown as for out of memory conditions in JavaScript. +The particular exception here is implementation-defined in both cases. + +Note: ECMAScript doesn't specify any sort of behavior on out-of-memory conditions; implementations have been observed to throw OOMError and to crash. Either is valid here. + +
+ A failed allocation of a large table or memory may either result in + - a {{RangeError}}, as specified in the {{Memory}} {{Memory/grow()}} and {{Table}} {{Table/grow()}} operations + - returning -1 as the [=memory.grow=] instruction + - UA-specific OOM behavior as described in this section. + In a future revision, we may reconsider more reliable and recoverable errors for allocations of large amounts of memory. + + See [Issue 879](https://github.com/WebAssembly/spec/issues/879) for further discussion. +
+ +

Implementation-defined Limits

+ +The WebAssembly core specification allows an implementation to define limits on the syntactic structure of the module. +While each embedding of WebAssembly may choose to define its own limits, for predictability the standard WebAssembly JavaScript Interface described in this document defines the following exact limits. +An implementation must reject a module that exceeds these limits with a {{CompileError}}. +In practice, an implementation may run out of resources for valid modules below these limits. + +
    +
  • The maximum size of a module is 1073741824 bytes (1 GiB).
  • +
  • The maximum number of types defined in the types section is 1000000.
  • +
  • The maximum number of functions defined in a module is 1000000.
  • +
  • The maximum number of imports declared in a module is 100000.
  • +
  • The maximum number of exports declared in a module is 100000.
  • +
  • The maximum number of globals defined in a module is 1000000.
  • +
  • The maximum number of data segments defined in a module is 100000.
  • + +
  • The maximum number of tables, including declared or imported tables, is 100000.
  • +
  • The maximum size of a table is 10000000.
  • +
  • The maximum number of table entries in any table initialization is 10000000.
  • +
  • The maximum number of memories, including declared or imported memories, is 1.
  • +
  • The initial or maximum number of pages for any memory, declared or imported, is at most 32767.
  • + +
  • The maximum number of parameters to any function is 1000.
  • +
  • The maximum number of return values for any function is 1.
  • +
  • The maximum size of a function body, including locals declarations, is 7654321 bytes.
  • +
  • The maximum number of locals declared in a function, including implicitly declared as parameters, is 50000.
  • + +
+ +

Security and Privacy Considerations

+ +

This section is non-normative.

+ +This document defines a host environment for WebAssembly. It enables a WebAssembly instance to [=import=] JavaScript objects and functions from an [=read the imports|import object=], but otherwise provides no access to the embedding environment. Thus a WebAssembly instance is bounds to the same constraints as JavaScript. From 0d8fab65ed4bf5d90e265f8e54991bbd7d8ccbef Mon Sep 17 00:00:00 2001 From: Ioanna M Dimitriou H <9728696+ioannad@users.noreply.github.com> Date: Mon, 30 Dec 2019 11:19:23 +0100 Subject: [PATCH 061/302] Merge 'document/' directory of 'WebAssembly/reference-types/master' (#91) To work on the `exception-handling` formal spec, this repository should be up to date with the required `reference-types` spec. --- document/Makefile | 296 +--- document/README.md | 25 +- document/appendix-algorithm/index.rst | 6 - document/appendix-names/index.rst | 6 - document/appendix-properties/index.rst | 6 - document/appendix-textual/index.rst | 8 - document/{ => core}/.gitignore | 1 + document/core/LICENSE | 50 + document/core/Makefile | 355 ++++ document/core/README.md | 25 + document/core/appendix/algorithm.rst | 233 +++ document/core/appendix/custom.rst | 145 ++ document/core/appendix/embedding.rst | 616 +++++++ document/core/appendix/implementation.rst | 137 ++ document/core/appendix/index-instructions.rst | 221 +++ document/core/appendix/index-rules.rst | 112 ++ document/core/appendix/index-types.rst | 26 + document/core/appendix/index.rst | 22 + document/core/appendix/properties.rst | 791 +++++++++ document/core/binary/conventions.rst | 118 ++ document/{ => core}/binary/index.rst | 4 +- document/core/binary/instructions.rst | 429 +++++ document/core/binary/modules.rst | 486 ++++++ document/core/binary/types.rst | 175 ++ document/core/binary/values.rst | 148 ++ document/{ => core}/conf.py | 16 +- document/core/exec/conventions.rst | 134 ++ document/{execution => core/exec}/index.rst | 6 +- document/core/exec/instructions.rst | 1485 ++++++++++++++++ document/core/exec/modules.rst | 747 ++++++++ document/core/exec/numerics.rst | 1551 +++++++++++++++++ document/core/exec/runtime.rst | 634 +++++++ document/core/index.bs | 29 + document/core/index.rst | 38 + .../{introduction => core/intro}/index.rst | 2 + .../intro}/introduction.rst | 50 +- .../{introduction => core/intro}/overview.rst | 55 +- document/{ => core}/make.bat | 0 document/{ => core/static}/custom.css | 31 + document/core/static/webassembly.png | Bin 0 -> 43955 bytes document/core/syntax/conventions.rst | 129 ++ document/{ => core}/syntax/index.rst | 2 + document/core/syntax/instructions.rst | 429 +++++ document/core/syntax/modules.rst | 371 ++++ document/core/syntax/types.rst | 266 +++ document/core/syntax/values.rst | 175 ++ document/core/text/conventions.rst | 157 ++ document/core/text/index.rst | 14 + document/core/text/instructions.rst | 532 ++++++ document/core/text/lexical.rst | 126 ++ document/core/text/modules.rst | 657 +++++++ document/core/text/types.rst | 167 ++ document/core/text/values.rst | 257 +++ document/core/util/README.htmldiff.pl | 2 + document/core/util/bikeshed/conf.py | 470 +++++ document/core/util/bikeshed_fixup.py | 61 + document/core/util/katex | 1 + document/core/util/katex_fix.patch | 42 + document/core/util/macros.def | 1076 ++++++++++++ document/{ => core/util}/mathdef.py | 6 +- document/core/util/mathdefbs.py | 126 ++ document/core/util/mathjax2katex.py | 265 +++ document/core/util/pseudo-lexer.py | 32 + .../valid}/conventions.rst | 115 +- document/{validation => core/valid}/index.rst | 3 + document/core/valid/instructions.rst | 1010 +++++++++++ document/core/valid/modules.rst | 587 +++++++ document/core/valid/types.rst | 434 +++++ document/deploy.sh | 32 +- document/index.html | 74 + document/index.rst | 33 - document/instantiation/index.rst | 8 - document/math.def | 249 --- document/placeholder.jpg | Bin 57021 -> 0 bytes document/syntax/conventions.rst | 57 - document/syntax/instrindex.rst | 201 --- document/syntax/instructions.rst | 308 ---- document/syntax/modules.rst | 349 ---- document/syntax/types.rst | 211 --- document/syntax/values.rst | 130 -- document/travis-deploy.sh | 80 + document/util/htmldiff.pl | 588 +++++++ document/validation/instructions.rst | 843 --------- document/validation/modules.rst | 587 ------- document/web-api/Makefile | 44 + document/web-api/index.bs | 233 +++ 86 files changed, 17410 insertions(+), 3348 deletions(-) delete mode 100644 document/appendix-algorithm/index.rst delete mode 100644 document/appendix-names/index.rst delete mode 100644 document/appendix-properties/index.rst delete mode 100644 document/appendix-textual/index.rst rename document/{ => core}/.gitignore (50%) create mode 100644 document/core/LICENSE create mode 100644 document/core/Makefile create mode 100644 document/core/README.md create mode 100644 document/core/appendix/algorithm.rst create mode 100644 document/core/appendix/custom.rst create mode 100644 document/core/appendix/embedding.rst create mode 100644 document/core/appendix/implementation.rst create mode 100644 document/core/appendix/index-instructions.rst create mode 100644 document/core/appendix/index-rules.rst create mode 100644 document/core/appendix/index-types.rst create mode 100644 document/core/appendix/index.rst create mode 100644 document/core/appendix/properties.rst create mode 100644 document/core/binary/conventions.rst rename document/{ => core}/binary/index.rst (86%) create mode 100644 document/core/binary/instructions.rst create mode 100644 document/core/binary/modules.rst create mode 100644 document/core/binary/types.rst create mode 100644 document/core/binary/values.rst rename document/{ => core}/conf.py (97%) create mode 100644 document/core/exec/conventions.rst rename document/{execution => core/exec}/index.rst (64%) create mode 100644 document/core/exec/instructions.rst create mode 100644 document/core/exec/modules.rst create mode 100644 document/core/exec/numerics.rst create mode 100644 document/core/exec/runtime.rst create mode 100644 document/core/index.bs create mode 100644 document/core/index.rst rename document/{introduction => core/intro}/index.rst (87%) rename document/{introduction => core/intro}/introduction.rst (57%) rename document/{introduction => core/intro}/overview.rst (80%) rename document/{ => core}/make.bat (100%) rename document/{ => core/static}/custom.css (54%) create mode 100644 document/core/static/webassembly.png create mode 100644 document/core/syntax/conventions.rst rename document/{ => core}/syntax/index.rst (89%) create mode 100644 document/core/syntax/instructions.rst create mode 100644 document/core/syntax/modules.rst create mode 100644 document/core/syntax/types.rst create mode 100644 document/core/syntax/values.rst create mode 100644 document/core/text/conventions.rst create mode 100644 document/core/text/index.rst create mode 100644 document/core/text/instructions.rst create mode 100644 document/core/text/lexical.rst create mode 100644 document/core/text/modules.rst create mode 100644 document/core/text/types.rst create mode 100644 document/core/text/values.rst create mode 100644 document/core/util/README.htmldiff.pl create mode 100644 document/core/util/bikeshed/conf.py create mode 100755 document/core/util/bikeshed_fixup.py create mode 160000 document/core/util/katex create mode 100644 document/core/util/katex_fix.patch create mode 100644 document/core/util/macros.def rename document/{ => core/util}/mathdef.py (96%) create mode 100644 document/core/util/mathdefbs.py create mode 100755 document/core/util/mathjax2katex.py create mode 100644 document/core/util/pseudo-lexer.py rename document/{validation => core/valid}/conventions.rst (55%) rename document/{validation => core/valid}/index.rst (81%) create mode 100644 document/core/valid/instructions.rst create mode 100644 document/core/valid/modules.rst create mode 100644 document/core/valid/types.rst create mode 100644 document/index.html delete mode 100644 document/index.rst delete mode 100644 document/instantiation/index.rst delete mode 100644 document/math.def delete mode 100644 document/placeholder.jpg delete mode 100644 document/syntax/conventions.rst delete mode 100644 document/syntax/instrindex.rst delete mode 100644 document/syntax/instructions.rst delete mode 100644 document/syntax/modules.rst delete mode 100644 document/syntax/types.rst delete mode 100644 document/syntax/values.rst create mode 100755 document/travis-deploy.sh create mode 100755 document/util/htmldiff.pl delete mode 100644 document/validation/instructions.rst delete mode 100644 document/validation/modules.rst create mode 100644 document/web-api/Makefile create mode 100644 document/web-api/index.bs diff --git a/document/Makefile b/document/Makefile index 5df0df135e..875efc7206 100644 --- a/document/Makefile +++ b/document/Makefile @@ -1,270 +1,76 @@ -# Makefile for Sphinx documentation -# +DIRS = core js-api web-api +FILES = index.html +BUILDDIR = _build -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = a4 -BUILDDIR = _build -STATICDIR = _static -DOWNLOADDIR = _download -GHPAGESDIR = ../docs -NAME = WebAssembly +# Global targets. -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: usage -usage: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " pdf to make standalone PDF file" - @echo " all to make both" - @echo " publish to make all and push to gh-pages" - @echo " help to see more options" +.PHONY: all +all: $(BUILDDIR) root $(DIRS) -.PHONY: help -help: - @echo "Usage: \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " pdf to make standalone PDF file" - @echo " all to make both" - @echo " publish to make all and push to gh-pages" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " applehelp to make an Apple Help Book" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " epub3 to make an epub3" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " xml to make Docutils-native XML files" - @echo " pseudoxml to make pseudoxml-XML files for display purposes" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - @echo " coverage to run coverage check of the documentation (if enabled)" - @echo " dummy to check syntax errors of document sources" - -.PHONY: publish -publish: all deploy +$(BUILDDIR): + mkdir -p $@ .PHONY: deploy deploy: - GIT_DEPLOY_DIR=$(BUILDDIR)/html sh deploy.sh - -.PHONY: all -all: pdf html - -.PHONY: pdf -pdf: latexpdf - mkdir -p $(BUILDDIR)/html/$(DOWNLOADDIR) - ln -f $(BUILDDIR)/latex/$(NAME).pdf $(BUILDDIR)/html/$(DOWNLOADDIR)/$(NAME).pdf + GIT_DEPLOY_DIR=$(BUILDDIR) bash deploy.sh +.PHONY: publish +publish: all deploy .PHONY: clean -clean: +clean: $(DIRS:%=clean-%) rm -rf $(BUILDDIR) - rm -rf $(STATICDIR) - -.PHONY: html -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - for file in `ls $(BUILDDIR)/html/*.html`; \ - do \ - sed s:BASEDIR:.:g <$$file >$$file.out; \ - mv -f $$file.out $$file; \ - done - for file in `ls $(BUILDDIR)/html/*/*.html`; \ - do \ - sed s:BASEDIR:..:g <$$file >$$file.out; \ - sed 's;MathJax.Hub.Config({TeX: {MAXBUFFER: 10*1024}})$$file; \ - rm -f $$file.out; \ - done - @echo - @echo "Build finished. The HTML pages are in `pwd`/$(BUILDDIR)/html." -.PHONY: dirhtml -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." +.PHONY: diff +diff: $(DIRS:%=diff-%) -.PHONY: singlehtml -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." -.PHONY: pickle -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." +# Directory-specific targets. -.PHONY: json -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." +.PHONY: root +root: $(BUILDDIR) + touch $(BUILDDIR)/.nojekyll + cp -f $(FILES) $(BUILDDIR)/ -.PHONY: htmlhelp -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." +.PHONY: $(DIRS) +$(DIRS): %: $(BUILDDIR) $(DIRS:%=build-%) $(DIRS:%=dir-%) -.PHONY: qthelp -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/WebAssembly.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/WebAssembly.qhc" +.PHONY: $(DIRS:%=build-%) +$(DIRS:%=build-%): build-%: + (cd $(@:build-%=%); make BUILDDIR=$(BUILDDIR) all) -.PHONY: applehelp -applehelp: - $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp - @echo - @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." - @echo "N.B. You won't be able to view it unless you put it in" \ - "~/Library/Documentation/Help or install it in your application" \ - "bundle." +.PHONY: $(DIRS:%=dir-%) +$(DIRS:%=dir-%): dir-%: + mkdir -p $(BUILDDIR)/$(@:dir-%=%) + rm -rf $(BUILDDIR)/$(@:dir-%=%)/* + cp -R $(@:dir-%=%)/$(BUILDDIR)/html/* $(BUILDDIR)/$(@:dir-%=%)/ -.PHONY: devhelp -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/WebAssembly" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/WebAssembly" - @echo "# devhelp" +.PHONY: $(DIRS:%=deploy-%) +$(DIRS:%=deploy-%): deploy-%: + GIT_DEPLOY_DIR=$(BUILDDIR) GIT_DEPLOY_SUBDIR=$(@:deploy-%=%) bash deploy.sh -.PHONY: epub -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." +.PHONY: $(DIRS:%=publish-%) +$(DIRS:%=publish-%): publish-%: % deploy-% -.PHONY: epub3 -epub3: - $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 - @echo - @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." +.PHONY: $(DIRS:%=clean-%) +$(DIRS:%=clean-%): clean-%: + (cd $(@:clean-%=%); make BUILDDIR=$(BUILDDIR) clean) + rm -rf $(BUILDDIR)/$(@:clean-%=%) -.PHONY: latex -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." +.PHONY: $(DIRS:%=diff-%) +$(DIRS:%=diff-%): diff-%: + (cd $(@:diff-%=%); make BUILDDIR=$(BUILDDIR) diff) -.PHONY: latexpdf -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." -.PHONY: latexpdfja -latexpdfja: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through platex and dvipdfmx..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." +# Help. -.PHONY: text -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -.PHONY: man -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -.PHONY: texinfo -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -.PHONY: info -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -.PHONY: gettext -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -.PHONY: changes -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -.PHONY: linkcheck -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -.PHONY: doctest -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -.PHONY: coverage -coverage: - $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage - @echo "Testing of coverage in the sources finished, look at the " \ - "results in $(BUILDDIR)/coverage/python.txt." - -.PHONY: xml -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - @echo - @echo "Build finished. The XML files are in $(BUILDDIR)/xml." - -.PHONY: pseudoxml -pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml - @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." +.PHONY: help +help: + @echo "Please use \`make ' where is one of" + @echo " all to build all documents" + @echo " publish to make all and push to gh-pages" + @echo " to build a specific subdirectory" + @echo " publish- to build and push a specific subdirectory" -.PHONY: dummy -dummy: - $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy - @echo - @echo "Build finished. Dummy builder generates no files." +.PHONY: usage +usage: help diff --git a/document/README.md b/document/README.md index 310e5d3e01..e8312f429b 100644 --- a/document/README.md +++ b/document/README.md @@ -1,20 +1,23 @@ -# WebAssembly Specification +# WebAssembly Specifications -This is (meant to become) the official WebAssembly "language" specification. +This directory contains the source code for the WebAssembly spec documents, as served from the [webassembly.github.io/spec](https://webassembly.github.io/spec) pages. +It uses [Sphinx](http://www.sphinx-doc.org/) and [Bikeshed](https://github.com/tabatkins/bikeshed). -It uses [Sphinx](http://www.sphinx-doc.org/). To install that: +To install Sphinx: ``` pip install sphinx ``` -To make HTML (result in `_build/html`): -``` -make html -``` -To make PDF (result in `_build/latex`, requires LaTeX): + +To install Bikeshed, see the instructions [here](https://tabatkins.github.io/bikeshed/#installing). + + +To build everything locally (result appears in `_build/`): ``` -make pdf +make all ``` -To make all: + +To build everything and update [webassembly.github.io/spec](https://webassembly.github.io/spec) with it: ``` -make all +make publish ``` +Please make sure to only use that once a change has approval. diff --git a/document/appendix-algorithm/index.rst b/document/appendix-algorithm/index.rst deleted file mode 100644 index 883daeb7db..0000000000 --- a/document/appendix-algorithm/index.rst +++ /dev/null @@ -1,6 +0,0 @@ -Appendix: Validation Algorithm ------------------------------- - -.. todo:: - - Describe algorithm, state correctness properties (soundness, completeness) diff --git a/document/appendix-names/index.rst b/document/appendix-names/index.rst deleted file mode 100644 index 6c8fe7a20b..0000000000 --- a/document/appendix-names/index.rst +++ /dev/null @@ -1,6 +0,0 @@ -Appendix: Name Section ----------------------- - -.. todo:: - - Describe diff --git a/document/appendix-properties/index.rst b/document/appendix-properties/index.rst deleted file mode 100644 index d43f7ccf99..0000000000 --- a/document/appendix-properties/index.rst +++ /dev/null @@ -1,6 +0,0 @@ -Appendix: Formal Properties ---------------------------- - -.. todo:: - - Describe and sketch proof (progress, preservation, uniqueness) diff --git a/document/appendix-textual/index.rst b/document/appendix-textual/index.rst deleted file mode 100644 index e7ea647eb8..0000000000 --- a/document/appendix-textual/index.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. text-format: - -Appendix: Text Format ---------------------- - -.. todo:: - - Describe diff --git a/document/.gitignore b/document/core/.gitignore similarity index 50% rename from document/.gitignore rename to document/core/.gitignore index 09f98591a9..b932ec283e 100644 --- a/document/.gitignore +++ b/document/core/.gitignore @@ -1,2 +1,3 @@ _build _static +document/*.pyc diff --git a/document/core/LICENSE b/document/core/LICENSE new file mode 100644 index 0000000000..795b406e4e --- /dev/null +++ b/document/core/LICENSE @@ -0,0 +1,50 @@ +W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE + +This work is being provided by the copyright holders under the following +license. + + +LICENSE + +By obtaining and/or copying this work, you (the licensee) agree that you have +read, understood, and will comply with the following terms and conditions. + +Permission to copy, modify, and distribute this work, with or without +modification, for any purpose and without fee or royalty is hereby granted, +provided that you include the following on ALL copies of the work or portions +thereof, including modifications: + +* The full text of this NOTICE in a location viewable to users of the + redistributed or derivative work. + +* Any pre-existing intellectual property disclaimers, notices, or terms and + conditions. If none exist, the W3C Software and Document Short Notice + (https://www.w3.org/Consortium/Legal/copyright-software-short-notice) should + be included. + +* Notice of any changes or modifications, through a copyright statement on the + new code or document such as "This software or document includes material + copied from or derived from [title and URI of the W3C document]. Copyright © [YEAR] W3C® (MIT, ERCIM, Keio, Beihang)." + + +DISCLAIMERS + +THIS WORK IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS +OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF +MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE +SOFTWARE OR DOCUMENT WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, +TRADEMARKS OR OTHER RIGHTS. + +COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENT. + +The name and trademarks of copyright holders may NOT be used in advertising or +publicity pertaining to the work without specific, written prior permission. +Title to copyright in this work will at all times remain with copyright +holders. + + +NOTES + +This version: +http://www.w3.org/Consortium/Legal/2015/copyright-software-and-document diff --git a/document/core/Makefile b/document/core/Makefile new file mode 100644 index 0000000000..6a06fed0be --- /dev/null +++ b/document/core/Makefile @@ -0,0 +1,355 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = a4 +BUILDDIR = _build +STATICDIR = _static +DOWNLOADDIR = _download +NAME = WebAssembly + +# Hack until we have moved to more recent Sphinx. +OLDMATHJAX = https://cdn.mathjax.org/mathjax/latest/MathJax.js +NEWMATHJAX = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: usage +usage: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " pdf to make standalone PDF file" + @echo " bikeshed to make a bikeshed wrapped single large HTML file" + @echo " diff to make a diff of the bikeshed HTML file with the latest TR" + @echo " WD-tar generate tar file for updating the Working Draft" + @echo " WD-echidna publish the Working Draft tar file via Echidna" + @echo " all to make all 3" + @echo " publish to make all and push to gh-pages" + @echo " help to see more options" + +.PHONY: help +help: + @echo "Usage: \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " pdf to make standalone PDF file" + @echo " bikeshed to make a bikeshed wrapped single large HTML file" + @echo " all to make all 3" + @echo " publish to make all and push to gh-pages" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " epub3 to make an epub3" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + @echo " dummy to check syntax errors of document sources" + +.PHONY: deploy +deploy: + (cd ..; make dir-core deploy-core) + +.PHONY: publish +publish: clean all deploy + +.PHONY: publish-main +publish-main: clean main bikeshed-keep deploy + +.PHONY: all +all: pdf html bikeshed + +.PHONY: main +main: pdf html + +# Dirty hack to avoid rebuilding the Bikeshed version for every push. +.PHONY: bikeshed-keep +bikeshed-keep: + test -e $(BUILDDIR)/html/bikeshed || \ + wget -r -nH --cut-dirs=2 -P $(BUILDDIR)/html --no-check-certificate \ + https://webassembly.github.io/spec/core/bikeshed || \ + echo Downloaded Bikeshed. + + +.PHONY: pdf +pdf: latexpdf + mkdir -p $(BUILDDIR)/html/$(DOWNLOADDIR) + ln -f $(BUILDDIR)/latex/$(NAME).pdf $(BUILDDIR)/html/$(DOWNLOADDIR)/$(NAME).pdf + + +.PHONY: clean +clean: + rm -rf $(BUILDDIR) + rm -rf $(STATICDIR) + +.PHONY: html +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + for file in `ls $(BUILDDIR)/html/*.html`; \ + do \ + sed s:BASEDIR:.:g <$$file >$$file.out; \ + mv -f $$file.out $$file; \ + sed s~$(OLDMATHJAX)~$(NEWMATHJAX)~g <$$file >$$file.out; \ + mv -f $$file.out $$file; \ + done + for file in `ls $(BUILDDIR)/html/*/*.html`; \ + do \ + sed s:BASEDIR:..:g <$$file >$$file.out; \ + sed 's;MathJax.Hub.Config({TeX: {MAXBUFFER: 30*1024}})$$file; \ + rm -f $$file.out; \ + sed s~$(OLDMATHJAX)~$(NEWMATHJAX)~g <$$file >$$file.out; \ + mv -f $$file.out $$file; \ + done + @echo + @echo "Build finished. The HTML pages are in `pwd`/$(BUILDDIR)/html/." + +.PHONY: dirhtml +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +.PHONY: singlehtml +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +.PHONY: bikeshed +bikeshed: + $(SPHINXBUILD) -b singlehtml -c util/bikeshed \ + $(ALLSPHINXOPTS) $(BUILDDIR)/bikeshed_singlehtml + python util/bikeshed_fixup.py $(BUILDDIR)/bikeshed_singlehtml/index.html \ + >$(BUILDDIR)/bikeshed_singlehtml/index_fixed.html + mkdir -p $(BUILDDIR)/bikeshed_mathjax/ + bikeshed spec index.bs $(BUILDDIR)/bikeshed_mathjax/index.html + mkdir -p $(BUILDDIR)/html/bikeshed/ + (cd util/katex/ && yarn && yarn build && npm install --only=prod) + python util/mathjax2katex.py $(BUILDDIR)/bikeshed_mathjax/index.html \ + >$(BUILDDIR)/html/bikeshed/index.html + mkdir -p $(BUILDDIR)/html/bikeshed/katex/dist/ + cp -r util/katex/dist/* $(BUILDDIR)/html/bikeshed/katex/dist/ + patch -p0 $(BUILDDIR)/html/bikeshed/katex/dist/katex.css \ + < util/katex_fix.patch + cp $(BUILDDIR)/bikeshed_singlehtml/_static/pygments.css \ + $(BUILDDIR)/html/bikeshed/ + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/html/bikeshed/." + +.PHONY: WD-tar +WD-tar: bikeshed + @echo "Building tar file..." + tar cvf \ + $(BUILDDIR)/WD.tar \ + --transform='s|$(BUILDDIR)/html/bikeshed/||' \ + --transform='s|index.html|Overview.html|' \ + $(BUILDDIR)/html/bikeshed/index.html \ + $(BUILDDIR)/html/bikeshed/pygments.css \ + $(BUILDDIR)/html/bikeshed/katex/dist/katex.css \ + $(BUILDDIR)/html/bikeshed/katex/dist/fonts + @echo "Built $(BUILDDIR)/WD.tar." + +.PHONY: WD-echidna +WD-echidna: WD-tar + @if [ -z $(W3C_USERNAME) ] || \ + [ -z $(W3C_PASSWORD) ] || \ + [ -z $(DECISION_URL) ] ; then \ + echo "Must provide W3C_USERNAME, W3C_PASSWORD, and DECISION_URL environment variables"; \ + exit 1; \ + fi + curl 'https://labs.w3.org/echidna/api/request' \ + --user '$(W3C_USERNAME):$(W3C_PASSWORD)' \ + -F "tar=@$(BUILDDIR)/WD.tar" \ + -F "decision=$(DECISION_URL)" | tee $(BUILDDIR)/WD-echidna-id.txt + @echo + @echo "Published working draft. Check its status at https://labs.w3.org/echidna/api/status?id=`cat $(BUILDDIR)/WD-echidna-id.txt`" + +.PHONY: diff +diff: bikeshed + @echo "Downloading the old single-file html spec..." + curl `grep "^TR" index.bs | cut -d' ' -f2` -o $(BUILDDIR)/html/bikeshed/old.html + @echo "Done." + @echo "Diffing new against old (go get a coffee)..." + perl ../util/htmldiff.pl $(BUILDDIR)/html/bikeshed/old.html $(BUILDDIR)/html/bikeshed/index.html $(BUILDDIR)/html/bikeshed/diff.html + @echo "Done. The diff is at $(BUILDDIR)/html/bikeshed/diff.html" + +.PHONY: pickle +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +.PHONY: json +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +.PHONY: htmlhelp +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +.PHONY: qthelp +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/WebAssembly.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/WebAssembly.qhc" + +.PHONY: applehelp +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +.PHONY: devhelp +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/WebAssembly" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/WebAssembly" + @echo "# devhelp" + +.PHONY: epub +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +.PHONY: epub3 +epub3: + $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 + @echo + @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." + +.PHONY: latex +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +.PHONY: latexpdf +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex LATEXMKOPTS=" $(BUILDDIR)/latex/LOG 2>&1 || cat $(BUILDDIR)/latex/LOG + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: latexpdfja +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: text +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +.PHONY: man +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +.PHONY: texinfo +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +.PHONY: info +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +.PHONY: gettext +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +.PHONY: changes +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +.PHONY: linkcheck +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +.PHONY: doctest +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +.PHONY: coverage +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +.PHONY: xml +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +.PHONY: pseudoxml +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." + +.PHONY: dummy +dummy: + $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy + @echo + @echo "Build finished. Dummy builder generates no files." diff --git a/document/core/README.md b/document/core/README.md new file mode 100644 index 0000000000..299b7a3a11 --- /dev/null +++ b/document/core/README.md @@ -0,0 +1,25 @@ +# WebAssembly Core Specification + +This is the official WebAssembly "language" specification. + +It uses [Sphinx](http://www.sphinx-doc.org/). To install that: +``` +pip install sphinx +``` +To make HTML (result in `_build/html`): +``` +make html +``` +To make PDF (result in `_build/latex`, requires LaTeX): +``` +make pdf +``` +To make all: +``` +make all +``` +Finally, to make all and update webassembly.github.io/spec with it: +``` +make publish +``` +Please make sure to only use that once a change has approval. diff --git a/document/core/appendix/algorithm.rst b/document/core/appendix/algorithm.rst new file mode 100644 index 0000000000..19ec29a0d3 --- /dev/null +++ b/document/core/appendix/algorithm.rst @@ -0,0 +1,233 @@ +.. index:: validation, algorithm, instruction, module, binary format, opcode +.. _algo-valid: + +Validation Algorithm +-------------------- + +The specification of WebAssembly :ref:`validation ` is purely *declarative*. +It describes the constraints that must be met by a :ref:`module ` or :ref:`instruction ` sequence to be valid. + +This section sketches the skeleton of a sound and complete *algorithm* for effectively validating code, i.e., sequences of :ref:`instructions `. +(Other aspects of validation are straightforward to implement.) + +In fact, the algorithm is expressed over the flat sequence of opcodes as occurring in the :ref:`binary format `, and performs only a single pass over it. +Consequently, it can be integrated directly into a decoder. + +The algorithm is expressed in typed pseudo code whose semantics is intended to be self-explanatory. + + +.. index:: value type, stack, label, frame, instruction + +Data Structures +~~~~~~~~~~~~~~~ + +Types are representable as an enumeration. +A simple subtyping check can be defined on these types. + +.. code-block:: pseudo + + type val_type = I32 | I64 | F32 | F64 | Anyref | Funcref | Nullref | Bot + + func is_num(t : val_type) : bool = + return t = I32 || t = I64 || t = F32 || t = F64 || t = Bot + + func is_ref(t : val_type) : bool = + return t = Anyref || t = Funcref || t = Nullref || t = Bot + + func matches(t1 : val_type, t2 : val_type) : bool = + return t1 = t2 || t1 = Bot || + (t1 = Nullref && is_ref(t2)) || (is_ref(t1) && t2 = Anyref) + +The algorithm uses two separate stacks: the *value stack* and the *control stack*. +The former tracks the :ref:`types ` of operand values on the :ref:`stack `, +the latter surrounding :ref:`structured control instructions ` and their associated :ref:`blocks `. + +.. code-block:: pseudo + + type val_stack = stack(val_type) + + type ctrl_stack = stack(ctrl_frame) + type ctrl_frame = { + label_types : list(val_type) + end_types : list(val_type) + height : nat + unreachable : bool + } + +For each value, the value stack records its :ref:`value type `. + +For each entered block, the control stack records a *control frame* with the type of the associated :ref:`label ` (used to type-check branches), the result type of the block (used to check its result), the height of the operand stack at the start of the block (used to check that operands do not underflow the current block), and a flag recording whether the remainder of the block is unreachable (used to handle :ref:`stack-polymorphic ` typing after branches). + +.. note:: + In the presentation of this algorithm, multiple values are supported for the :ref:`result types ` classifying blocks and labels. + With the current version of WebAssembly, the :code:`list` could be simplified to an optional value. + +For the purpose of presenting the algorithm, the operand and control stacks are simply maintained as global variables: + +.. code-block:: pseudo + + var vals : val_stack + var ctrls : ctrl_stack + +However, these variables are not manipulated directly by the main checking function, but through a set of auxiliary functions: + +.. code-block:: pseudo + + func push_val(type : val_type) = + vals.push(type) + + func pop_val() : val_type = + if (vals.size() = ctrls[0].height && ctrls[0].unreachable) return Bot + error_if(vals.size() = ctrls[0].height) + return vals.pop() + + func pop_val(expect : val_type) : val_type = + let actual = pop_val() + error_if(not matches(actual, expect)) + return actual + + func push_vals(types : list(val_type)) = foreach (t in types) push_val(t) + func pop_vals(types : list(val_type)) : list(val_type) = + var popped := [] + foreach (t in reverse(types)) popped.append(pop_val(t)) + return popped + +Pushing an operand value simply pushes the respective type to the value stack. + +Popping an operand value checks that the value stack does not underflow the current block and then removes one type. +But first, a special case is handled where the block contains no known values, but has been marked as unreachable. +That can occur after an unconditional branch, when the stack is typed :ref:`polymorphically `. +In that case, the :code:`Bot` type is returned, because that is a *principal* choice trivially satisfying all use constraints. + +A second function for popping an operand value takes an expected type, which the actual operand type is checked against. +The types may differ by subtyping, including the case where the actual type is :code:`Bot`, and thereby matches unconditionally. +The function returns the actual type popped from the stack. + +Finally, there are accumulative functions for pushing or popping multiple operand types. + +.. note:: + The notation :code:`stack[i]` is meant to index the stack from the top, + so that, e.g., :code:`ctrls[0]` accesses the element pushed last. + + +The control stack is likewise manipulated through auxiliary functions: + +.. code-block:: pseudo + + func push_ctrl(label : list(val_type), out : list(val_type)) = +  let frame = ctrl_frame(label, out, vals.size(), false) +   ctrls.push(frame) + + func pop_ctrl() : list(val_type) = +  error_if(ctrls.is_empty()) +  let frame = ctrls[0] +   pop_vals(frame.end_types) +   error_if(vals.size() =/= frame.height) + ctrls.pop() +   return frame.end_types + + func unreachable() = +   vals.resize(ctrls[0].height) +   ctrls[0].unreachable := true + +Pushing a control frame takes the types of the label and result values. +It allocates a new frame record recording them along with the current height of the operand stack and marks the block as reachable. + +Popping a frame first checks that the control stack is not empty. +It then verifies that the operand stack contains the right types of values expected at the end of the exited block and pops them off the operand stack. +Afterwards, it checks that the stack has shrunk back to its initial height. + +Finally, the current frame can be marked as unreachable. +In that case, all existing operand types are purged from the value stack, in order to allow for the :ref:`stack-polymorphism ` logic in :code:`pop_val` to take effect. + +.. note:: + Even with the unreachable flag set, consecutive operands are still pushed to and popped from the operand stack. + That is necessary to detect invalid :ref:`examples ` like :math:`(\UNREACHABLE~(\I32.\CONST)~\I64.\ADD)`. + However, a polymorphic stack cannot underflow, but instead generates :code:`Bot` types as needed. + + +.. index:: opcode + +Validation of Instruction Sequences +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following function shows the validation of a number of representative instructions that manipulate the stack. +Other instructions are checked in a similar manner. + +.. note:: + Various instructions not shown here will additionally require the presence of a validation :ref:`context ` for checking uses of :ref:`indices `. + That is an easy addition and therefore omitted from this presentation. + +.. code-block:: pseudo + + func validate(opcode) = + switch (opcode) + case (i32.add) + pop_val(I32) + pop_val(I32) + push_val(I32) + + case (drop) + pop_val() + + case (select) + pop_val(I32) + let t1 = pop_val() + let t2 = pop_val() + error_if(not (is_num(t1) && is_num(t2))) + error_if(t1 =/= t2 && t1 =/= Bot && t2 =/= Bot) + push_val(if (t1 = Bot) t2 else t1) + + case (select t) + pop_val(I32) + pop_val(t) + pop_val(t) + push_val(t) + +    case (unreachable) +       unreachable() + + case (block t*) + push_ctrl([t*], [t*]) + + case (loop t*) + push_ctrl([], [t*]) + + case (if t*) + pop_val(I32) + push_ctrl([t*], [t*]) + + case (end) + let results = pop_ctrl() + push_vals(results) + + case (else) + let results = pop_ctrl() + push_ctrl(results, results) + + case (br n) +      error_if(ctrls.size() < n) +       pop_vals(ctrls[n].label_types) +       unreachable() + + case (br_if n) +      error_if(ctrls.size() < n) + pop_val(I32) +       pop_vals(ctrls[n].label_types) +       push_vals(ctrls[n].label_types) + +    case (br_table n* m) + pop_val(I32) +       error_if(ctrls.size() < m) + let arity = ctrls[m].label_types.size() +       foreach (n in n*) +         error_if(ctrls.size() < n) +         error_if(ctrls[n].label_types.size() =/= arity) + push_vals(pop_vals(ctrls[n].label_types)) + pop_vals(ctrls[m].label_types) +       unreachable() + +.. note:: + It is an invariant under the current WebAssembly instruction set that an operand of :code:`Unknown` type is never duplicated on the stack. + This would change if the language were extended with stack instructions like :code:`dup`. + Under such an extension, the above algorithm would need to be refined by replacing the :code:`Unknown` type with proper *type variables* to ensure that all uses are consistent. diff --git a/document/core/appendix/custom.rst b/document/core/appendix/custom.rst new file mode 100644 index 0000000000..bea81d61c5 --- /dev/null +++ b/document/core/appendix/custom.rst @@ -0,0 +1,145 @@ +.. index:: custom section, section, binary format + +Custom Sections +--------------- + +This appendix defines dedicated :ref:`custom sections ` for WebAssembly's :ref:`binary format `. +Such sections do not contribute to, or otherwise affect, the WebAssembly semantics, and like any custom section they may be ignored by an implementation. +However, they provide useful meta data that implementations can make use of to improve user experience or take compilation hints. + +Currently, only one dedicated custom section is defined, the :ref:`name section`. + + +.. index:: ! name section, name, Unicode UTF-8 +.. _binary-namesec: + +Name Section +~~~~~~~~~~~~ + +The *name section* is a :ref:`custom section ` whose name string is itself :math:`\text{name}`. +The name section should appear only once in a module, and only after the :ref:`data section `. + +The purpose of this section is to attach printable names to definitions in a module, which e.g. can be used by a debugger or when parts of the module are to be rendered in :ref:`text form `. + +.. note:: + All :ref:`names ` are represented in |Unicode|_ encoded in UTF-8. + Names need not be unique. + + +.. _binary-namesubsection: + +Subsections +........... + +The :ref:`data ` of a name section consists of a sequence of *subsections*. +Each subsection consists of a + +* a one-byte subsection *id*, +* the |U32| *size* of the contents, in bytes, +* the actual *contents*, whose structure is depended on the subsection id. + +.. math:: + \begin{array}{llcll} + \production{name section} & \Bnamesec &::=& + \Bsection_0(\Bnamedata) \\ + \production{name data} & \Bnamedata &::=& + n{:}\Bname & (\iff n = \text{name}) \\ &&& + \Bmodulenamesubsec^? \\ &&& + \Bfuncnamesubsec^? \\ &&& + \Blocalnamesubsec^? \\ + \production{name subsection} & \Bnamesubsection_N(\B{B}) &::=& + N{:}\Bbyte~~\X{size}{:}\Bu32~~\B{B} + & (\iff \X{size} = ||\B{B}||) \\ + \end{array} + +The following subsection ids are used: + +== =========================================== +Id Subsection +== =========================================== + 0 :ref:`module name ` + 1 :ref:`function names ` + 2 :ref:`local names ` +== =========================================== + +Each subsection may occur at most once, and in order of increasing id. + + +.. index:: ! name map, index, index space +.. _binary-indirectnamemap: +.. _binary-namemap: + +Name Maps +......... + +A *name map* assigns :ref:`names ` to :ref:`indices ` in a given :ref:`index space `. +It consists of a :ref:`vector ` of index/name pairs in order of increasing index value. +Each index must be unique, but the assigned names need not be. + +.. math:: + \begin{array}{llclll} + \production{name map} & \Bnamemap &::=& + \Bvec(\Bnameassoc) \\ + \production{name association} & \Bnameassoc &::=& + \Bidx~\Bname \\ + \end{array} + +An *indirect name map* assigns :ref:`names ` to a two-dimensional :ref:`index space `, where secondary indices are *grouped* by primary indices. +It consists of a vector of primary index/name map pairs in order of increasing index value, where each name map in turn maps secondary indices to names. +Each primary index must be unique, and likewise each secondary index per individual name map. + +.. math:: + \begin{array}{llclll} + \production{indirect name map} & \Bindirectnamemap &::=& + \Bvec(\Bindirectnameassoc) \\ + \production{indirect name association} & \Bindirectnameassoc &::=& + \Bidx~\Bnamemap \\ + \end{array} + + +.. index:: module +.. _binary-modulenamesec: + +Module Names +............ + +The *module name subsection* has the id 0. +It simply consists of a single :ref:`name ` that is assigned to the module itself. + +.. math:: + \begin{array}{llclll} + \production{module name subsection} & \Bmodulenamesubsec &::=& + \Bnamesubsection_0(\Bname) \\ + \end{array} + + +.. index:: function, function index +.. _binary-funcnamesec: + +Function Names +.............. + +The *function name subsection* has the id 1. +It consists of a :ref:`name map ` assigning function names to :ref:`function indices `. + +.. math:: + \begin{array}{llclll} + \production{function name subsection} & \Bfuncnamesubsec &::=& + \Bnamesubsection_1(\Bnamemap) \\ + \end{array} + + +.. index:: function, local, function index, local index +.. _binary-localnamesec: + +Local Names +........... + +The *local name subsection* has the id 2. +It consists of an :ref:`indirect name map ` assigning local names to :ref:`local indices ` grouped by :ref:`function indices `. + +.. math:: + \begin{array}{llclll} + \production{local name subsection} & \Blocalnamesubsec &::=& + \Bnamesubsection_2(\Bindirectnamemap) \\ + \end{array} diff --git a/document/core/appendix/embedding.rst b/document/core/appendix/embedding.rst new file mode 100644 index 0000000000..db83ae26be --- /dev/null +++ b/document/core/appendix/embedding.rst @@ -0,0 +1,616 @@ +.. index:: ! embedding, embedder, implementation, host +.. _embed: + +Embedding +--------- + +A WebAssembly implementation will typically be *embedded* into a *host* environment. +An *embedder* implements the connection between such a host environment and the WebAssembly semantics as defined in the main body of this specification. +An embedder is expected to interact with the semantics in well-defined ways. + +This section defines a suitable interface to the WebAssembly semantics in the form of entry points through which an embedder can access it. +The interface is intended to be complete, in the sense that an embedder does not need to reference other functional parts of the WebAssembly specification directly. + +.. note:: + On the other hand, an embedder does not need to provide the host environment with access to all functionality defined in this interface. + For example, an implementation may not support :ref:`parsing ` of the :ref:`text format `. + +Types +~~~~~ + +In the description of the embedder interface, syntactic classes from the :ref:`abstract syntax ` and the :ref:`runtime's abstract machine ` are used as names for variables that range over the possible objects from that class. +Hence, these syntactic classes can also be interpreted as types. + +For numeric parameters, notation like :math:`n:\u32` is used to specify a symbolic name in addition to the respective value range. + + +.. _embed-error: + +Errors +~~~~~~ + +Failure of an interface operation is indicated by an auxiliary syntactic class: + +.. math:: + \begin{array}{llll} + \production{(error)} & \error &::=& \ERROR \\ + \end{array} + +In addition to the error conditions specified explicitly in this section, implementations may also return errors when specific :ref:`implementation limitations ` are reached. + +.. note:: + Errors are abstract and unspecific with this definition. + Implementations can refine it to carry suitable classifications and diagnostic messages. + + +Pre- and Post-Conditions +~~~~~~~~~~~~~~~~~~~~~~~~ + +Some operations state *pre-conditions* about their arguments or *post-conditions* about their results. +It is the embedder's responsibility to meet the pre-conditions. +If it does, the post conditions are guaranteed by the semantics. + +In addition to pre- and post-conditions explicitly stated with each operation, the specification adopts the following conventions for :ref:`runtime objects ` (:math:`store`, :math:`\moduleinst`, :math:`\externval`, :ref:`addresses `): + +* Every runtime object passed as a parameter must be :ref:`valid ` per an implicit pre-condition. + +* Every runtime object returned as a result is :ref:`valid ` per an implicit post-condition. + +.. note:: + As long as an embedder treats runtime objects as abstract and only creates and manipulates them through the interface defined here, all implicit pre-conditions are automatically met. + + + +.. index:: allocation, store +.. _embed-store: + +Store +~~~~~ + +.. _embed-store-init: + +:math:`\F{store\_init}() : \store` +.................................. + +1. Return the empty :ref:`store `. + +.. math:: + \begin{array}{lclll} + \F{store\_init}() &=& \{ \SFUNCS~\epsilon,~ \SMEMS~\epsilon,~ \STABLES~\epsilon,~ \SGLOBALS~\epsilon \} \\ + \end{array} + + + +.. index:: module +.. _embed-module: + +Modules +~~~~~~~ + +.. index:: binary format +.. _embed-module-decode: + +:math:`\F{module\_decode}(\byte^\ast) : \module ~|~ \error` +........................................................... + +1. If there exists a derivation for the :ref:`byte ` sequence :math:`\byte^\ast` as a :math:`\Bmodule` according to the :ref:`binary grammar for modules `, yielding a :ref:`module ` :math:`m`, then return :math:`m`. + +2. Else, return :math:`\ERROR`. + +.. math:: + \begin{array}{lclll} + \F{module\_decode}(b^\ast) &=& m && (\iff \Bmodule \stackrel\ast\Longrightarrow m{:}b^\ast) \\ + \F{module\_decode}(b^\ast) &=& \ERROR && (\otherwise) \\ + \end{array} + + +.. index:: text format +.. _embed-module-parse: + +:math:`\F{module\_parse}(\char^\ast) : \module ~|~ \error` +.......................................................... + +1. If there exists a derivation for the :ref:`source ` :math:`\char^\ast` as a :math:`\Tmodule` according to the :ref:`text grammar for modules `, yielding a :ref:`module ` :math:`m`, then return :math:`m`. + +2. Else, return :math:`\ERROR`. + +.. math:: + \begin{array}{lclll} + \F{module\_parse}(c^\ast) &=& m && (\iff \Tmodule \stackrel\ast\Longrightarrow m{:}c^\ast) \\ + \F{module\_parse}(c^\ast) &=& \ERROR && (\otherwise) \\ + \end{array} + + +.. index:: validation +.. _embed-module-validate: + +:math:`\F{module\_validate}(\module) : \error^?` +................................................ + +1. If :math:`\module` is :ref:`valid `, then return nothing. + +2. Else, return :math:`\ERROR`. + +.. math:: + \begin{array}{lclll} + \F{module\_validate}(m) &=& \epsilon && (\iff {} \vdashmodule m : \externtype^\ast \to {\externtype'}^\ast) \\ + \F{module\_validate}(m) &=& \ERROR && (\otherwise) \\ + \end{array} + + +.. index:: instantiation, module instance +.. _embed-module-instantiate: + +:math:`\F{module\_instantiate}(\store, \module, \externval^\ast) : (\store, \moduleinst ~|~ \error)` +.................................................................................................... + +1. Try :ref:`instantiating ` :math:`\module` in :math:`\store` with :ref:`external values ` :math:`\externval^\ast` as imports: + + a. If it succeeds with a :ref:`module instance ` :math:`\moduleinst`, then let :math:`\X{result}` be :math:`\moduleinst`. + + b. Else, let :math:`\X{result}` be :math:`\ERROR`. + +2. Return the new store paired with :math:`\X{result}`. + +.. math:: + \begin{array}{lclll} + \F{module\_instantiate}(S, m, \X{ev}^\ast) &=& (S', F.\AMODULE) && (\iff \instantiate(S, m, \X{ev}^\ast) \stepto^\ast S'; F; \epsilon) \\ + \F{module\_instantiate}(S, m, \X{ev}^\ast) &=& (S', \ERROR) && (\iff \instantiate(S, m, \X{ev}^\ast) \stepto^\ast S'; F; \TRAP) \\ + \end{array} + +.. note:: + The store may be modified even in case of an error. + + +.. index:: import +.. _embed-module-imports: + +:math:`\F{module\_imports}(\module) : (\name, \name, \externtype)^\ast` +....................................................................... + +1. Pre-condition: :math:`\module` is :ref:`valid ` with external import types :math:`\externtype^\ast` and external export types :math:`{\externtype'}^\ast`. + +2. Let :math:`\import^\ast` be the :ref:`imports ` :math:`\module.\MIMPORTS`. + +3. Assert: the length of :math:`\import^\ast` equals the length of :math:`\externtype^\ast`. + +4. For each :math:`\import_i` in :math:`\import^\ast` and corresponding :math:`\externtype_i` in :math:`\externtype^\ast`, do: + + a. Let :math:`\X{result}_i` be the triple :math:`(\import_i.\IMODULE, \import_i.\INAME, \externtype_i)`. + +5. Return the concatenation of all :math:`\X{result}_i`, in index order. + +6. Post-condition: each :math:`\externtype_i` is :ref:`valid `. + +.. math:: + ~ \\ + \begin{array}{lclll} + \F{module\_imports}(m) &=& (\X{im}.\IMODULE, \X{im}.\INAME, \externtype)^\ast \\ + && \qquad (\iff \X{im}^\ast = m.\MIMPORTS \wedge {} \vdashmodule m : \externtype^\ast \to {\externtype'}^\ast) \\ + \end{array} + + +.. index:: export +.. _embed-module-exports: + +:math:`\F{module\_exports}(\module) : (\name, \externtype)^\ast` +................................................................ + +1. Pre-condition: :math:`\module` is :ref:`valid ` with external import types :math:`\externtype^\ast` and external export types :math:`{\externtype'}^\ast`. + +2. Let :math:`\export^\ast` be the :ref:`exports ` :math:`\module.\MEXPORTS`. + +3. Assert: the length of :math:`\export^\ast` equals the length of :math:`{\externtype'}^\ast`. + +4. For each :math:`\export_i` in :math:`\export^\ast` and corresponding :math:`\externtype'_i` in :math:`{\externtype'}^\ast`, do: + + a. Let :math:`\X{result}_i` be the pair :math:`(\export_i.\ENAME, \externtype'_i)`. + +5. Return the concatenation of all :math:`\X{result}_i`, in index order. + +6. Post-condition: each :math:`\externtype'_i` is :ref:`valid `. + +.. math:: + ~ \\ + \begin{array}{lclll} + \F{module\_exports}(m) &=& (\X{ex}.\ENAME, \externtype')^\ast \\ + && \qquad (\iff \X{ex}^\ast = m.\MEXPORTS \wedge {} \vdashmodule m : \externtype^\ast \to {\externtype'}^\ast) \\ + \end{array} + + +.. index:: module, module instance +.. _embed-instance: + +Module Instances +~~~~~~~~~~~~~~~~ + +.. index:: export, export instance + +.. _embed-instance-export: + +:math:`\F{instance\_export}(\moduleinst, \name) : \externval ~|~ \error` +........................................................................ + +1. Assert: due to :ref:`validity ` of the :ref:`module instance ` :math:`\moduleinst`, all its :ref:`export names ` are different. + +2. If there exists an :math:`\exportinst_i` in :math:`\moduleinst.\MIEXPORTS` such that :ref:`name ` :math:`\exportinst_i.\EINAME` equals :math:`\name`, then: + + a. Return the :ref:`external value ` :math:`\exportinst_i.\EIVALUE`. + +3. Else, return :math:`\ERROR`. + +.. math:: + ~ \\ + \begin{array}{lclll} + \F{instance\_export}(m, \name) &=& m.\MIEXPORTS[i].\EIVALUE && (\iff m.\MEXPORTS[i].\EINAME = \name) \\ + \F{instance\_export}(m, \name) &=& \ERROR && (\otherwise) \\ + \end{array} + + +.. index:: function, host function, function address, function instance, function type, store +.. _embed-func: + +Functions +~~~~~~~~~ + +.. _embed-func-alloc: + +:math:`\F{func\_alloc}(\store, \functype, \hostfunc) : (\store, \funcaddr)` +........................................................................... + +1. Pre-condition: :math:`\functype` is :math:`valid `. + +2. Let :math:`\funcaddr` be the result of :ref:`allocating a host function ` in :math:`\store` with :ref:`function type ` :math:`\functype` and host function code :math:`\hostfunc`. + +3. Return the new store paired with :math:`\funcaddr`. + +.. math:: + \begin{array}{lclll} + \F{func\_alloc}(S, \X{ft}, \X{code}) &=& (S', \X{a}) && (\iff \allochostfunc(S, \X{ft}, \X{code}) = S', \X{a}) \\ + \end{array} + +.. note:: + This operation assumes that :math:`\hostfunc` satisfies the :ref:`pre- and post-conditions ` required for a function instance with type :math:`\functype`. + + Regular (non-host) function instances can only be created indirectly through :ref:`module instantiation `. + + +.. _embed-func-type: + +:math:`\F{func\_type}(\store, \funcaddr) : \functype` +..................................................... + +1. Return :math:`S.\SFUNCS[a].\FITYPE`. + +2. Post-condition: the returned :ref:`function type ` is :ref:`valid `. + +.. math:: + \begin{array}{lclll} + \F{func\_type}(S, a) &=& S.\SFUNCS[a].\FITYPE \\ + \end{array} + + +.. index:: invocation, value, result +.. _embed-func-invoke: + +:math:`\F{func\_invoke}(\store, \funcaddr, \val^\ast) : (\store, \val^\ast ~|~ \error)` +........................................................................................ + +1. Try :ref:`invoking ` the function :math:`\funcaddr` in :math:`\store` with :ref:`values ` :math:`\val^\ast` as arguments: + + a. If it succeeds with :ref:`values ` :math:`{\val'}^\ast` as results, then let :math:`\X{result}` be :math:`{\val'}^\ast`. + + b. Else it has trapped, hence let :math:`\X{result}` be :math:`\ERROR`. + +2. Return the new store paired with :math:`\X{result}`. + +.. math:: + ~ \\ + \begin{array}{lclll} + \F{func\_invoke}(S, a, v^\ast) &=& (S', {v'}^\ast) && (\iff \invoke(S, a, v^\ast) \stepto^\ast S'; F; {v'}^\ast) \\ + \F{func\_invoke}(S, a, v^\ast) &=& (S', \ERROR) && (\iff \invoke(S, a, v^\ast) \stepto^\ast S'; F; \TRAP) \\ + \end{array} + +.. note:: + The store may be modified even in case of an error. + + +.. index:: table, table address, store, table instance, table type, element, function address +.. _embed-table: + +Tables +~~~~~~ + +.. _embed-table-alloc: + +:math:`\F{table\_alloc}(\store, \tabletype) : (\store, \tableaddr, \reff)` +.......................................................................... + +1. Pre-condition: :math:`\tabletype` is :math:`valid `. + +2. Let :math:`\tableaddr` be the result of :ref:`allocating a table ` in :math:`\store` with :ref:`table type ` :math:`\tabletype` and initialization value :math:`\reff`. + +3. Return the new store paired with :math:`\tableaddr`. + +.. math:: + \begin{array}{lclll} + \F{table\_alloc}(S, \X{tt}, r) &=& (S', \X{a}) && (\iff \alloctable(S, \X{tt}, r) = S', \X{a}) \\ + \end{array} + + +.. _embed-table-type: + +:math:`\F{table\_type}(\store, \tableaddr) : \tabletype` +........................................................ + +1. Return :math:`S.\STABLES[a].\TITYPE`. + +2. Post-condition: the returned :ref:`table type ` is :math:`valid `. + +.. math:: + \begin{array}{lclll} + \F{table\_type}(S, a) &=& S.\STABLES[a].\TITYPE \\ + \end{array} + + +.. _embed-table-read: + +:math:`\F{table\_read}(\store, \tableaddr, i:\u32) : \reff ~|~ \error` +...................................................................... + +1. Let :math:`\X{ti}` be the :ref:`table instance ` :math:`\store.\STABLES[\tableaddr]`. + +2. If :math:`i` is larger than or equal to the length of :math:`\X{ti}.\TIELEM`, then return :math:`\ERROR`. + +3. Else, return the :ref:`reference value ` :math:`\X{ti}.\TIELEM[i]`. + +.. math:: + \begin{array}{lclll} + \F{table\_read}(S, a, i) &=& r && (\iff S.\STABLES[a].\TIELEM[i] = r) \\ + \F{table\_read}(S, a, i) &=& \ERROR && (\otherwise) \\ + \end{array} + + +.. _embed-table-write: + +:math:`\F{table\_write}(\store, \tableaddr, i:\u32, \reff) : \store ~|~ \error` +............................................................................... + +1. Let :math:`\X{ti}` be the :ref:`table instance ` :math:`\store.\STABLES[\tableaddr]`. + +2. If :math:`i` is larger than or equal to the length of :math:`\X{ti}.\TIELEM`, then return :math:`\ERROR`. + +3. Replace :math:`\X{ti}.\TIELEM[i]` with the :ref:`reference value ` :math:`\reff`. + +4. Return the updated store. + +.. math:: + \begin{array}{lclll} + \F{table\_write}(S, a, i, r) &=& S' && (\iff S' = S \with \STABLES[a].\TIELEM[i] = r) \\ + \F{table\_write}(S, a, i, r) &=& \ERROR && (\otherwise) \\ + \end{array} + + +.. _embed-table-size: + +:math:`\F{table\_size}(\store, \tableaddr) : \u32` +.................................................. + +1. Return the length of :math:`\store.\STABLES[\tableaddr].\TIELEM`. + +.. math:: + ~ \\ + \begin{array}{lclll} + \F{table\_size}(S, a) &=& n && + (\iff |S.\STABLES[a].\TIELEM| = n) \\ + \end{array} + + + +.. _embed-table-grow: + +:math:`\F{table\_grow}(\store, \tableaddr, n:\u32, \reff) : \store ~|~ \error` +.............................................................................. + +1. Try :ref:`growing ` the :ref:`table instance ` :math:`\store.\STABLES[\tableaddr]` by :math:`n` elements with initialization value :math:`\reff`: + + a. If it succeeds, return the updated store. + + b. Else, return :math:`\ERROR`. + +.. math:: + ~ \\ + \begin{array}{lclll} + \F{table\_grow}(S, a, n, r) &=& S' && + (\iff S' = S \with \STABLES[a] = \growtable(S.\STABLES[a], n, r)) \\ + \F{table\_grow}(S, a, n, r) &=& \ERROR && (\otherwise) \\ + \end{array} + + +.. index:: memory, memory address, store, memory instance, memory type, byte +.. _embed-mem: + +Memories +~~~~~~~~ + +.. _embed-mem-alloc: + +:math:`\F{mem\_alloc}(\store, \memtype) : (\store, \memaddr)` +................................................................ + +1. Pre-condition: :math:`\memtype` is :math:`valid `. + +2. Let :math:`\memaddr` be the result of :ref:`allocating a memory ` in :math:`\store` with :ref:`memory type ` :math:`\memtype`. + +3. Return the new store paired with :math:`\memaddr`. + +.. math:: + \begin{array}{lclll} + \F{mem\_alloc}(S, \X{mt}) &=& (S', \X{a}) && (\iff \allocmem(S, \X{mt}) = S', \X{a}) \\ + \end{array} + + +.. _embed-mem-type: + +:math:`\F{mem\_type}(\store, \memaddr) : \memtype` +.................................................. + +1. Return :math:`S.\SMEMS[a].\MITYPE`. + +2. Post-condition: the returned :ref:`memory type ` is :math:`valid `. + +.. math:: + \begin{array}{lclll} + \F{mem\_type}(S, a) &=& S.\SMEMS[a].\MITYPE \\ + \end{array} + + +.. _embed-mem-read: + +:math:`\F{mem\_read}(\store, \memaddr, i:\u32) : \byte ~|~ \error` +.................................................................. + +1. Let :math:`\X{mi}` be the :ref:`memory instance ` :math:`\store.\SMEMS[\memaddr]`. + +2. If :math:`i` is larger than or equal to the length of :math:`\X{mi}.\MIDATA`, then return :math:`\ERROR`. + +3. Else, return the :ref:`byte ` :math:`\X{mi}.\MIDATA[i]`. + +.. math:: + \begin{array}{lclll} + \F{mem\_read}(S, a, i) &=& b && (\iff S.\SMEMS[a].\MIDATA[i] = b) \\ + \F{mem\_read}(S, a, i) &=& \ERROR && (\otherwise) \\ + \end{array} + + +.. _embed-mem-write: + +:math:`\F{mem\_write}(\store, \memaddr, i:\u32, \byte) : \store ~|~ \error` +........................................................................... + +1. Let :math:`\X{mi}` be the :ref:`memory instance ` :math:`\store.\SMEMS[\memaddr]`. + +2. If :math:`\u32` is larger than or equal to the length of :math:`\X{mi}.\MIDATA`, then return :math:`\ERROR`. + +3. Replace :math:`\X{mi}.\MIDATA[i]` with :math:`\byte`. + +4. Return the updated store. + +.. math:: + \begin{array}{lclll} + \F{mem\_write}(S, a, i, b) &=& S' && (\iff S' = S \with \SMEMS[a].\MIDATA[i] = b) \\ + \F{mem\_write}(S, a, i, b) &=& \ERROR && (\otherwise) \\ + \end{array} + + +.. _embed-mem-size: + +:math:`\F{mem\_size}(\store, \memaddr) : \u32` +.............................................. + +1. Return the length of :math:`\store.\SMEMS[\memaddr].\MIDATA` divided by the :ref:`page size `. + +.. math:: + ~ \\ + \begin{array}{lclll} + \F{mem\_size}(S, a) &=& n && + (\iff |S.\SMEMS[a].\MIDATA| = n \cdot 64\,\F{Ki}) \\ + \end{array} + + + +.. _embed-mem-grow: + +:math:`\F{mem\_grow}(\store, \memaddr, n:\u32) : \store ~|~ \error` +................................................................... + +1. Try :ref:`growing ` the :ref:`memory instance ` :math:`\store.\SMEMS[\memaddr]` by :math:`n` :ref:`pages `: + + a. If it succeeds, return the updated store. + + b. Else, return :math:`\ERROR`. + +.. math:: + ~ \\ + \begin{array}{lclll} + \F{mem\_grow}(S, a, n) &=& S' && + (\iff S' = S \with \SMEMS[a] = \growmem(S.\SMEMS[a], n)) \\ + \F{mem\_grow}(S, a, n) &=& \ERROR && (\otherwise) \\ + \end{array} + + + +.. index:: global, global address, store, global instance, global type, value +.. _embed-global: + +Globals +~~~~~~~ + +.. _embed-global-alloc: + +:math:`\F{global\_alloc}(\store, \globaltype, \val) : (\store, \globaladdr)` +............................................................................ + +1. Pre-condition: :math:`\globaltype` is :math:`valid `. + +2. Let :math:`\globaladdr` be the result of :ref:`allocating a global ` in :math:`\store` with :ref:`global type ` :math:`\globaltype` and initialization value :math:`\val`. + +3. Return the new store paired with :math:`\globaladdr`. + +.. math:: + \begin{array}{lclll} + \F{global\_alloc}(S, \X{gt}, v) &=& (S', \X{a}) && (\iff \allocglobal(S, \X{gt}, v) = S', \X{a}) \\ + \end{array} + + +.. _embed-global-type: + +:math:`\F{global\_type}(\store, \globaladdr) : \globaltype` +........................................................... + +1. Return :math:`S.\SGLOBALS[a].\GITYPE`. + +2. Post-condition: the returned :ref:`global type ` is :math:`valid `. + +.. math:: + \begin{array}{lclll} + \F{global\_type}(S, a) &=& S.\SGLOBALS[a].\GITYPE \\ + \end{array} + + +.. _embed-global-read: + +:math:`\F{global\_read}(\store, \globaladdr) : \val` +.................................................... + +1. Let :math:`\X{gi}` be the :ref:`global instance ` :math:`\store.\SGLOBALS[\globaladdr]`. + +2. Return the :ref:`value ` :math:`\X{gi}.\GIVALUE`. + +.. math:: + \begin{array}{lclll} + \F{global\_read}(S, a) &=& v && (\iff S.\SGLOBALS[a].\GIVALUE = v) \\ + \end{array} + + +.. _embed-global-write: + +:math:`\F{global\_write}(\store, \globaladdr, \val) : \store ~|~ \error` +........................................................................ + +1. Let :math:`\X{gi}` be the :ref:`global instance ` :math:`\store.\SGLOBALS[\globaladdr]`. + +2. Let :math:`\mut~t` be the structure of the :ref:`global type ` :math:`\X{gi}.\GITYPE`. + +3. If :math:`\mut` is not :math:`\MVAR`, then return :math:`\ERROR`. + +4. Replace :math:`\X{gi}.\GIVALUE` with the :ref:`value ` :math:`\val`. + +5. Return the updated store. + +.. math:: + ~ \\ + \begin{array}{lclll} + \F{global\_write}(S, a, v) &=& S' && (\iff S.\SGLOBALS[a].\GITYPE = \MVAR~t \wedge S' = S \with \SGLOBALS[a].\GIVALUE = v) \\ + \F{global\_write}(S, a, v) &=& \ERROR && (\otherwise) \\ + \end{array} diff --git a/document/core/appendix/implementation.rst b/document/core/appendix/implementation.rst new file mode 100644 index 0000000000..df2885ccc8 --- /dev/null +++ b/document/core/appendix/implementation.rst @@ -0,0 +1,137 @@ +.. index:: ! implementation limitations, implementation +.. _impl: + +Implementation Limitations +-------------------------- + +Implementations typically impose additional restrictions on a number of aspects of a WebAssembly module or execution. +These may stem from: + +* physical resource limits, +* constraints imposed by the embedder or its environment, +* limitations of selected implementation strategies. + +This section lists allowed limitations. +Where restrictions take the form of numeric limits, no minimum requirements are given, +nor are the limits assumed to be concrete, fixed numbers. +However, it is expected that all implementations have "reasonably" large limits to enable common applications. + +.. note:: + A conforming implementation is not allowed to leave out individual *features*. + However, designated subsets of WebAssembly may be specified in the future. + + +Syntactic Limits +~~~~~~~~~~~~~~~~ + +.. index:: abstract syntax, module, type, function, table, memory, global, element, data, import, export, parameter, result, local, structured control instruction, instruction, name, Unicode, character +.. _impl-syntax: + +Structure +......... + +An implementation may impose restrictions on the following dimensions of a module: + +* the number of :ref:`types ` in a :ref:`module ` +* the number of :ref:`functions ` in a :ref:`module `, including imports +* the number of :ref:`tables ` in a :ref:`module `, including imports +* the number of :ref:`memories ` in a :ref:`module `, including imports +* the number of :ref:`globals ` in a :ref:`module `, including imports +* the number of :ref:`element segments ` in a :ref:`module ` +* the number of :ref:`data segments ` in a :ref:`module ` +* the number of :ref:`imports ` to a :ref:`module ` +* the number of :ref:`exports ` from a :ref:`module ` +* the number of parameters in a :ref:`function type ` +* the number of results in a :ref:`function type ` +* the number of :ref:`locals ` in a :ref:`function ` +* the size of a :ref:`function ` body +* the size of a :ref:`structured control instruction ` +* the number of :ref:`structured control instructions ` in a :ref:`function ` +* the nesting depth of :ref:`structured control instructions ` +* the number of :ref:`label indices ` in a |brtable| instruction +* the length of an :ref:`element segment ` +* the length of a :ref:`data segment ` +* the length of a :ref:`name ` +* the range of :ref:`characters ` in a :ref:`name ` + +If the limits of an implementation are exceeded for a given module, +then the implementation may reject the :ref:`validation `, compilation, or :ref:`instantiation ` of that module with an embedder-specific error. + +.. note:: + The last item allows :ref:`embedders ` that operate in limited environments without support for + |Unicode|_ to limit the + names of :ref:`imports ` and :ref:`exports ` + to common subsets like |ASCII|_. + + +.. index:: binary format, module, section, function, code +.. _impl-binary: + +Binary Format +............. + +For a module given in :ref:`binary format `, additional limitations may be imposed on the following dimensions: + +* the size of a :ref:`module ` +* the size of any :ref:`section ` +* the size of an individual function's :ref:`code ` +* the number of :ref:`sections ` + + +.. index:: text format, source text, token, identifier, character, unicode +.. _impl-text: + +Text Format +........... + +For a module given in :ref:`text format `, additional limitations may be imposed on the following dimensions: + +* the size of the :ref:`source text ` +* the size of any syntactic element +* the size of an individual :ref:`token ` +* the nesting depth of :ref:`folded instructions ` +* the length of symbolic :ref:`identifiers ` +* the range of literal :ref:`characters ` allowed in the :ref:`source text ` + + +.. index:: validation, function +.. _impl-valid: + +Validation +~~~~~~~~~~ + +An implementation may defer :ref:`validation ` of individual :ref:`functions ` until they are first :ref:`invoked `. + +If a function turns out to be invalid, then the invocation, and every consecutive call to the same function, results in a :ref:`trap `. + +.. note:: + This is to allow implementations to use interpretation or just-in-time compilation for functions. + The function must still be fully validated before execution of its body begins. + + +.. index:: execution, module instance, function instance, table instance, memory instance, global instance, allocation, frame, label, value +.. _impl-exec: + +Execution +~~~~~~~~~ + +Restrictions on the following dimensions may be imposed during :ref:`execution ` of a WebAssembly program: + +* the number of allocated :ref:`module instances ` +* the number of allocated :ref:`function instances ` +* the number of allocated :ref:`table instances ` +* the number of allocated :ref:`memory instances ` +* the number of allocated :ref:`global instances ` +* the size of a :ref:`table instance ` +* the size of a :ref:`memory instance ` +* the number of :ref:`frames ` on the :ref:`stack ` +* the number of :ref:`labels ` on the :ref:`stack ` +* the number of :ref:`values ` on the :ref:`stack ` + +If the runtime limits of an implementation are exceeded during execution of a computation, +then it may terminate that computation and report an embedder-specific error to the invoking code. + +Some of the above limits may already be verified during instantiation, in which case an implementation may report exceedance in the same manner as for :ref:`syntactic limits `. + +.. note:: + Concrete limits are usually not fixed but may be dependent on specifics, interdependent, vary over time, or depend on other implementation- or embedder-specific situations or events. diff --git a/document/core/appendix/index-instructions.rst b/document/core/appendix/index-instructions.rst new file mode 100644 index 0000000000..394a98e504 --- /dev/null +++ b/document/core/appendix/index-instructions.rst @@ -0,0 +1,221 @@ +.. index:: instruction +.. _index-instr: + +Index of Instructions +--------------------- + +====================================== ================ ========================================== ======================================== =============================================================== +Instruction Binary Opcode Type Validation Execution +====================================== ================ ========================================== ======================================== =============================================================== +:math:`\UNREACHABLE` :math:`\hex{00}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\NOP` :math:`\hex{01}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` +:math:`\BLOCK~[t^?]` :math:`\hex{02}` :math:`[] \to [t^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\LOOP~[t^?]` :math:`\hex{03}` :math:`[] \to [t^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\IF~[t^?]` :math:`\hex{04}` :math:`[\I32] \to [t^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\ELSE` :math:`\hex{05}` +(reserved) :math:`\hex{06}` +(reserved) :math:`\hex{07}` +(reserved) :math:`\hex{08}` +(reserved) :math:`\hex{09}` +(reserved) :math:`\hex{0A}` +:math:`\END` :math:`\hex{0B}` +:math:`\BR~l` :math:`\hex{0C}` :math:`[t_1^\ast~t^?] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\BRIF~l` :math:`\hex{0D}` :math:`[t^?~\I32] \to [t^?]` :ref:`validation ` :ref:`execution ` +:math:`\BRTABLE~l^\ast~l` :math:`\hex{0E}` :math:`[t_1^\ast~t^?~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\RETURN` :math:`\hex{0F}` :math:`[t_1^\ast~t^?] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\CALL~x` :math:`\hex{10}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\CALLINDIRECT~x` :math:`\hex{11}` :math:`[t_1^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{12}` +(reserved) :math:`\hex{13}` +(reserved) :math:`\hex{14}` +(reserved) :math:`\hex{15}` +(reserved) :math:`\hex{16}` +(reserved) :math:`\hex{17}` +(reserved) :math:`\hex{18}` +(reserved) :math:`\hex{19}` +:math:`\DROP` :math:`\hex{1A}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` +:math:`\SELECT` :math:`\hex{1B}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\SELECT~t` :math:`\hex{1C}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{1D}` +(reserved) :math:`\hex{1E}` +(reserved) :math:`\hex{1F}` +:math:`\LOCALGET~x` :math:`\hex{20}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\LOCALSET~x` :math:`\hex{21}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` +:math:`\LOCALTEE~x` :math:`\hex{22}` :math:`[t] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\GLOBALGET~x` :math:`\hex{23}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\GLOBALSET~x` :math:`\hex{24}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLEGET~x` :math:`\hex{25}` :math:`[\I32] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\TABLESET~x` :math:`\hex{26}` :math:`[\I32~t] \to []` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{27}` +:math:`\I32.\LOAD~\memarg` :math:`\hex{28}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD~\memarg` :math:`\hex{29}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\F32.\LOAD~\memarg` :math:`\hex{2A}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution ` +:math:`\F64.\LOAD~\memarg` :math:`\hex{2B}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{8\_s}~\memarg` :math:`\hex{2C}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{8\_u}~\memarg` :math:`\hex{2D}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{16\_s}~\memarg` :math:`\hex{2E}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{16\_u}~\memarg` :math:`\hex{2F}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{8\_s}~\memarg` :math:`\hex{30}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{8\_u}~\memarg` :math:`\hex{31}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{16\_s}~\memarg` :math:`\hex{32}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{16\_u}~\memarg` :math:`\hex{33}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{32\_s}~\memarg` :math:`\hex{34}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{32\_u}~\memarg` :math:`\hex{35}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\STORE~\memarg` :math:`\hex{36}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE~\memarg` :math:`\hex{37}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\F32.\STORE~\memarg` :math:`\hex{38}` :math:`[\I32~\F32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\F64.\STORE~\memarg` :math:`\hex{39}` :math:`[\I32~\F64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I32.\STORE\K{8}~\memarg` :math:`\hex{3A}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I32.\STORE\K{16}~\memarg` :math:`\hex{3B}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE\K{8}~\memarg` :math:`\hex{3C}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE\K{16}~\memarg` :math:`\hex{3D}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE\K{32}~\memarg` :math:`\hex{3E}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYSIZE` :math:`\hex{3F}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYGROW` :math:`\hex{40}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\CONST~\i32` :math:`\hex{41}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\CONST~\i64` :math:`\hex{42}` :math:`[] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\F32.\CONST~\f32` :math:`\hex{43}` :math:`[] \to [\F32]` :ref:`validation ` :ref:`execution ` +:math:`\F64.\CONST~\f64` :math:`\hex{44}` :math:`[] \to [\F64]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\EQZ` :math:`\hex{45}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\EQ` :math:`\hex{46}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\NE` :math:`\hex{47}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LT\K{\_s}` :math:`\hex{48}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LT\K{\_u}` :math:`\hex{49}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GT\K{\_s}` :math:`\hex{4A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GT\K{\_u}` :math:`\hex{4B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LE\K{\_s}` :math:`\hex{4C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LE\K{\_u}` :math:`\hex{4D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GE\K{\_s}` :math:`\hex{4E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GE\K{\_u}` :math:`\hex{4F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EQZ` :math:`\hex{50}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EQ` :math:`\hex{51}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\NE` :math:`\hex{52}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LT\K{\_s}` :math:`\hex{53}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LT\K{\_u}` :math:`\hex{54}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GT\K{\_s}` :math:`\hex{55}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GT\K{\_u}` :math:`\hex{56}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LE\K{\_s}` :math:`\hex{57}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LE\K{\_u}` :math:`\hex{58}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GE\K{\_s}` :math:`\hex{59}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GE\K{\_u}` :math:`\hex{5A}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\EQ` :math:`\hex{5B}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\NE` :math:`\hex{5C}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\LT` :math:`\hex{5D}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\GT` :math:`\hex{5E}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\LE` :math:`\hex{5F}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\GE` :math:`\hex{60}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\EQ` :math:`\hex{61}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\NE` :math:`\hex{62}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\LT` :math:`\hex{63}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\GT` :math:`\hex{64}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\LE` :math:`\hex{65}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\GE` :math:`\hex{66}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\CLZ` :math:`\hex{67}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\CTZ` :math:`\hex{68}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\POPCNT` :math:`\hex{69}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\ADD` :math:`\hex{6A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SUB` :math:`\hex{6B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\MUL` :math:`\hex{6C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\DIV\K{\_s}` :math:`\hex{6D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\DIV\K{\_u}` :math:`\hex{6E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\REM\K{\_s}` :math:`\hex{6F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\REM\K{\_u}` :math:`\hex{70}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\AND` :math:`\hex{71}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\OR` :math:`\hex{72}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\XOR` :math:`\hex{73}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SHL` :math:`\hex{74}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SHR\K{\_s}` :math:`\hex{75}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SHR\K{\_u}` :math:`\hex{76}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\ROTL` :math:`\hex{77}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\ROTR` :math:`\hex{78}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\CLZ` :math:`\hex{79}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\CTZ` :math:`\hex{7A}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\POPCNT` :math:`\hex{7B}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\ADD` :math:`\hex{7C}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SUB` :math:`\hex{7D}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\MUL` :math:`\hex{7E}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\DIV\K{\_s}` :math:`\hex{7F}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\DIV\K{\_u}` :math:`\hex{80}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\REM\K{\_s}` :math:`\hex{81}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\REM\K{\_u}` :math:`\hex{82}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\AND` :math:`\hex{83}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\OR` :math:`\hex{84}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\XOR` :math:`\hex{85}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SHL` :math:`\hex{86}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SHR\K{\_s}` :math:`\hex{87}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SHR\K{\_u}` :math:`\hex{88}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\ROTL` :math:`\hex{89}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\ROTR` :math:`\hex{8A}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\ABS` :math:`\hex{8B}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\NEG` :math:`\hex{8C}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CEIL` :math:`\hex{8D}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\FLOOR` :math:`\hex{8E}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\TRUNC` :math:`\hex{8F}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\NEAREST` :math:`\hex{90}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\SQRT` :math:`\hex{91}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\ADD` :math:`\hex{92}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\SUB` :math:`\hex{93}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\MUL` :math:`\hex{94}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\DIV` :math:`\hex{95}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\FMIN` :math:`\hex{96}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\FMAX` :math:`\hex{97}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\COPYSIGN` :math:`\hex{98}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\ABS` :math:`\hex{99}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\NEG` :math:`\hex{9A}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CEIL` :math:`\hex{9B}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\FLOOR` :math:`\hex{9C}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\TRUNC` :math:`\hex{9D}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\NEAREST` :math:`\hex{9E}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\SQRT` :math:`\hex{9F}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\ADD` :math:`\hex{A0}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\SUB` :math:`\hex{A1}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\MUL` :math:`\hex{A2}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\DIV` :math:`\hex{A3}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\FMIN` :math:`\hex{A4}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\FMAX` :math:`\hex{A5}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\COPYSIGN` :math:`\hex{A6}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\WRAP\K{\_}\I64` :math:`\hex{A7}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{A8}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{A9}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{AA}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{AB}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{\_}\I32\K{\_s}` :math:`\hex{AC}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{\_}\I32\K{\_u}` :math:`\hex{AD}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{AE}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{AF}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{B0}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{B1}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B2}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B3}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B4}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{B5}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\DEMOTE\K{\_}\F64` :math:`\hex{B6}` :math:`[\F64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B7}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B8}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B9}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{BA}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\PROMOTE\K{\_}\F32` :math:`\hex{BB}` :math:`[\F32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\REINTERPRET\K{\_}\F32` :math:`\hex{BC}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\REINTERPRET\K{\_}\F64` :math:`\hex{BD}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\REINTERPRET\K{\_}\I32` :math:`\hex{BE}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\REINTERPRET\K{\_}\I64` :math:`\hex{BF}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +(reserved) :math:`\hex{C0}` +(reserved) :math:`\hex{C1}` +(reserved) :math:`\hex{C2}` +(reserved) :math:`\hex{C3}` +(reserved) :math:`\hex{C4}` +(reserved) :math:`\hex{C5}` +(reserved) :math:`\hex{C6}` +(reserved) :math:`\hex{C7}` +(reserved) :math:`\hex{C8}` +(reserved) :math:`\hex{C9}` +(reserved) :math:`\hex{CA}` +(reserved) :math:`\hex{CB}` +(reserved) :math:`\hex{CC}` +(reserved) :math:`\hex{CD}` +(reserved) :math:`\hex{CE}` +(reserved) :math:`\hex{CF}` +:math:`\REFNULL` :math:`\hex{D0}` :math:`[] \to [\NULLREF]` :ref:`validation ` :ref:`execution ` +:math:`\REFISNULL` :math:`\hex{D1}` :math:`[\ANYREF] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\REFFUNC~x` :math:`\hex{D2}` :math:`[] \to [\FUNCREF]` :ref:`validation ` :ref:`execution ` +====================================== ================ ========================================== ======================================== =============================================================== diff --git a/document/core/appendix/index-rules.rst b/document/core/appendix/index-rules.rst new file mode 100644 index 0000000000..fe1fb3f2ff --- /dev/null +++ b/document/core/appendix/index-rules.rst @@ -0,0 +1,112 @@ +.. _index-rules: + +Index of Semantic Rules +----------------------- + + +.. index:: validation +.. _index-valid: + +Typing of Static Constructs +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +=============================================== =============================================================================== +Construct Judgement +=============================================== =============================================================================== +:ref:`Limits ` :math:`\vdashlimits \limits : k` +:ref:`Function type ` :math:`\vdashfunctype \functype \ok` +:ref:`Table type ` :math:`\vdashtabletype \tabletype \ok` +:ref:`Memory type ` :math:`\vdashmemtype \memtype \ok` +:ref:`Global type ` :math:`\vdashglobaltype \globaltype \ok` +:ref:`External type ` :math:`\vdashexterntype \externtype \ok` +:ref:`Instruction ` :math:`S;C \vdashinstr \instr : \functype` +:ref:`Instruction sequence ` :math:`S;C \vdashinstrseq \instr^\ast : \functype` +:ref:`Expression ` :math:`C \vdashexpr \expr : \resulttype` +:ref:`Function ` :math:`C \vdashfunc \func : \functype` +:ref:`Table ` :math:`C \vdashtable \table : \tabletype` +:ref:`Memory ` :math:`C \vdashmem \mem : \memtype` +:ref:`Global ` :math:`C \vdashglobal \global : \globaltype` +:ref:`Element segment ` :math:`C \vdashelem \elem \ok` +:ref:`Data segment ` :math:`C \vdashdata \data \ok` +:ref:`Start function ` :math:`C \vdashstart \start \ok` +:ref:`Export ` :math:`C \vdashexport \export : \externtype` +:ref:`Export description ` :math:`C \vdashexportdesc \exportdesc : \externtype` +:ref:`Import ` :math:`C \vdashimport \import : \externtype` +:ref:`Import description ` :math:`C \vdashimportdesc \importdesc : \externtype` +:ref:`Module ` :math:`\vdashmodule \module : \externtype^\ast \to \externtype^\ast` +=============================================== =============================================================================== + + +.. index:: runtime + +Typing of Runtime Constructs +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +=============================================== =============================================================================== +Construct Judgement +=============================================== =============================================================================== +:ref:`Value ` :math:`S \vdashval \val : \valtype` +:ref:`Result ` :math:`S \vdashresult \result : \resulttype` +:ref:`External value ` :math:`S \vdashexternval \externval : \externtype` +:ref:`Function instance ` :math:`S \vdashfuncinst \funcinst : \functype` +:ref:`Table instance ` :math:`S \vdashtableinst \tableinst : \tabletype` +:ref:`Memory instance ` :math:`S \vdashmeminst \meminst : \memtype` +:ref:`Global instance ` :math:`S \vdashglobalinst \globalinst : \globaltype` +:ref:`Export instance ` :math:`S \vdashexportinst \exportinst \ok` +:ref:`Module instance ` :math:`S \vdashmoduleinst \moduleinst : C` +:ref:`Store ` :math:`\vdashstore \store \ok` +:ref:`Configuration ` :math:`\vdashconfig \config \ok` +:ref:`Thread ` :math:`S;\resulttype^? \vdashthread \thread : \resulttype` +:ref:`Frame ` :math:`S \vdashframe \frame : C` +=============================================== =============================================================================== + + +Constantness +~~~~~~~~~~~~ + +=============================================== =============================================================================== +Construct Judgement +=============================================== =============================================================================== +:ref:`Constant expression ` :math:`C \vdashexprconst \expr \const` +:ref:`Constant instruction ` :math:`C \vdashinstrconst \instr \const` +=============================================== =============================================================================== + + +Matching +~~~~~~~~ + +=============================================== =============================================================================== +Construct Judgement +=============================================== =============================================================================== +:ref:`Number type ` :math:`\vdashnumtypematch \numtype_1 \matchesvaltype \numtype_2` +:ref:`Reference type ` :math:`\vdashreftypematch \reftype_1 \matchesvaltype \reftype_2` +:ref:`Value type ` :math:`\vdashvaltypematch \valtype_1 \matchesvaltype \valtype_2` +:ref:`Result type ` :math:`\vdashresulttypematch [t_1^?] \matchesresulttype [t_2^?]` +:ref:`External type ` :math:`\vdashexterntypematch \externtype_1 \matchesexterntype \externtype_2` +:ref:`Limits ` :math:`\vdashlimitsmatch \limits_1 \matcheslimits \limits_2` +=============================================== =============================================================================== + + +Store Extension +~~~~~~~~~~~~~~~ + +=============================================== =============================================================================== +Construct Judgement +=============================================== =============================================================================== +:ref:`Function instance ` :math:`\vdashfuncinstextends \funcinst_1 \extendsto \funcinst_2` +:ref:`Table instance ` :math:`\vdashtableinstextends \tableinst_1 \extendsto \tableinst_2` +:ref:`Memory instance ` :math:`\vdashmeminstextends \meminst_1 \extendsto \meminst_2` +:ref:`Global instance ` :math:`\vdashglobalinstextends \globalinst_1 \extendsto \globalinst_2` +:ref:`Store ` :math:`\vdashstoreextends \store_1 \extendsto \store_2` +=============================================== =============================================================================== + + +Execution +~~~~~~~~~ + +=============================================== =============================================================================== +Construct Judgement +=============================================== =============================================================================== +:ref:`Instruction ` :math:`S;F;\instr^\ast \stepto S';F';{\instr'}^\ast` +:ref:`Expression ` :math:`S;F;\expr \stepto S';F';\expr'` +=============================================== =============================================================================== diff --git a/document/core/appendix/index-types.rst b/document/core/appendix/index-types.rst new file mode 100644 index 0000000000..37f33c7b23 --- /dev/null +++ b/document/core/appendix/index-types.rst @@ -0,0 +1,26 @@ +.. index:: type +.. _index-type: + +Index of Types +-------------- + +======================================== =========================================== =============================================================================== +Category Constructor Binary Opcode +======================================== =========================================== =============================================================================== +:ref:`Type index ` :math:`x` (positive number as |Bs32| or |Bu32|) +:ref:`Number type ` |I32| :math:`\hex{7F}` (-1 as |Bs7|) +:ref:`Number type ` |I64| :math:`\hex{7E}` (-2 as |Bs7|) +:ref:`Number type ` |F32| :math:`\hex{7D}` (-3 as |Bs7|) +:ref:`Number type ` |F64| :math:`\hex{7C}` (-4 as |Bs7|) +(reserved) :math:`\hex{7B}` .. :math:`\hex{71}` +:ref:`Reference type ` |FUNCREF| :math:`\hex{70}` (-16 as |Bs7|) +:ref:`Reference type ` |ANYREF| :math:`\hex{6F}` (-17 as |Bs7|) +:ref:`Reference type ` |NULLREF| :math:`\hex{6E}` (-18 as |Bs7|) +(reserved) :math:`\hex{6D}` .. :math:`\hex{61}` +:ref:`Function type ` :math:`[\valtype^\ast] \to [\valtype^\ast]` :math:`\hex{60}` (-32 as |Bs7|) +(reserved) :math:`\hex{5F}` .. :math:`\hex{41}` +:ref:`Result type ` :math:`[\epsilon]` :math:`\hex{40}` (-64 as |Bs7|) +:ref:`Table type ` :math:`\limits~\reftype` (none) +:ref:`Memory type ` :math:`\limits` (none) +:ref:`Global type ` :math:`\mut~\valtype` (none) +======================================== =========================================== =============================================================================== diff --git a/document/core/appendix/index.rst b/document/core/appendix/index.rst new file mode 100644 index 0000000000..789d2140ea --- /dev/null +++ b/document/core/appendix/index.rst @@ -0,0 +1,22 @@ +.. _appendix: + +Appendix +======== + +.. toctree:: + :maxdepth: 2 + + embedding + implementation + algorithm + custom + properties + +.. only:: singlehtml + + .. toctree:: + + index-types + index-instructions + index-rules + diff --git a/document/core/appendix/properties.rst b/document/core/appendix/properties.rst new file mode 100644 index 0000000000..490e2c5545 --- /dev/null +++ b/document/core/appendix/properties.rst @@ -0,0 +1,791 @@ +.. index:: ! soundness, type system +.. _soundness: + +Soundness +--------- + +The :ref:`type system ` of WebAssembly is *sound*, implying both *type safety* and *memory safety* with respect to the WebAssembly semantics. For example: + +* All types declared and derived during validation are respected at run time; + e.g., every :ref:`local ` or :ref:`global ` variable will only contain type-correct values, every :ref:`instruction ` will only be applied to operands of the expected type, and every :ref:`function ` :ref:`invocation ` always evaluates to a result of the right type (if it does not :ref:`trap ` or diverge). + +* No memory location will be read or written except those explicitly defined by the program, i.e., as a :ref:`local `, a :ref:`global `, an element in a :ref:`table `, or a location within a linear :ref:`memory `. + +* There is no undefined behavior, + i.e., the :ref:`execution rules ` cover all possible cases that can occur in a :ref:`valid ` program, and the rules are mutually consistent. + +Soundness also is instrumental in ensuring additional properties, most notably, *encapsulation* of function and module scopes: no :ref:`locals ` can be accessed outside their own function and no :ref:`module ` components can be accessed outside their own module unless they are explicitly :ref:`exported ` or :ref:`imported `. + +The typing rules defining WebAssembly :ref:`validation ` only cover the *static* components of a WebAssembly program. +In order to state and prove soundness precisely, the typing rules must be extended to the *dynamic* components of the abstract :ref:`runtime `, that is, the :ref:`store `, :ref:`configurations `, and :ref:`administrative instructions `. [#cite-pldi2017]_ + + +.. index:: value, value type, result, result type, trap +.. _valid-result: + +Results +~~~~~~~ + +:ref:`Results ` can be classified by :ref:`result types ` as follows. + +:ref:`Results ` :math:`\val^\ast` +................................................ + +* For each :ref:`value ` :math:`\val_i` in :math:`\val^\ast`: + + * The value :math:`\val_i` is :ref:`valid ` with some :ref:`value type ` :math:`t_i`. + +* Let :math:`t^\ast` be the concatenation of all :math:`t_i`. + +* Then the result is valid with :ref:`result type ` :math:`[t^\ast]`. + +.. math:: + \frac{ + (S \vdashval \val : t)^\ast + }{ + S \vdashresult \val^\ast : [t^\ast] + } + + +:ref:`Results ` :math:`\TRAP` +............................................ + +* The result is valid with :ref:`result type ` :math:`[t^\ast]`, for any sequence :math:`t^\ast` of :ref:`value types `. + +.. math:: + \frac{ + }{ + S \vdashresult \TRAP : [t^\ast] + } + + +.. _module-context: +.. _valid-store: + +Store Validity +~~~~~~~~~~~~~~ + +The following typing rules specify when a runtime :ref:`store ` :math:`S` is *valid*. +A valid store must consist of +:ref:`function `, :ref:`table `, :ref:`memory `, :ref:`global `, and :ref:`module ` instances that are themselves valid, relative to :math:`S`. + +To that end, each kind of instance is classified by a respective :ref:`function `, :ref:`table `, :ref:`memory `, or :ref:`global ` type. +Module instances are classified by *module contexts*, which are regular :ref:`contexts ` repurposed as module types describing the :ref:`index spaces ` defined by a module. + + + +.. index:: store, function instance, table instance, memory instance, global instance, function type, table type, memory type, global type + +:ref:`Store ` :math:`S` +..................................... + +* Each :ref:`function instance ` :math:`\funcinst_i` in :math:`S.\SFUNCS` must be :ref:`valid ` with some :ref:`function type ` :math:`\functype_i`. + +* Each :ref:`table instance ` :math:`\tableinst_i` in :math:`S.\STABLES` must be :ref:`valid ` with some :ref:`table type ` :math:`\tabletype_i`. + +* Each :ref:`memory instance ` :math:`\meminst_i` in :math:`S.\SMEMS` must be :ref:`valid ` with some :ref:`memory type ` :math:`\memtype_i`. + +* Each :ref:`global instance ` :math:`\globalinst_i` in :math:`S.\SGLOBALS` must be :ref:`valid ` with some :ref:`global type ` :math:`\globaltype_i`. + +* Then the store is valid. + +.. math:: + ~\\[-1ex] + \frac{ + \begin{array}{@{}c@{}} + (S \vdashfuncinst \funcinst : \functype)^\ast + \qquad + (S \vdashtableinst \tableinst : \tabletype)^\ast + \\ + (S \vdashmeminst \meminst : \memtype)^\ast + \qquad + (S \vdashglobalinst \globalinst : \globaltype)^\ast + \\ + S = \{ + \SFUNCS~\funcinst^\ast, + \STABLES~\tableinst^\ast, + \SMEMS~\meminst^\ast, + \SGLOBALS~\globalinst^\ast \} + \end{array} + }{ + \vdashstore S \ok + } + + +.. index:: function type, function instance +.. _valid-funcinst: + +:ref:`Function Instances ` :math:`\{\FITYPE~\functype, \FIMODULE~\moduleinst, \FICODE~\func\}` +....................................................................................................................... + +* The :ref:`function type ` :math:`\functype` must be :ref:`valid `. + +* The :ref:`module instance ` :math:`\moduleinst` must be :ref:`valid ` with some :ref:`context ` :math:`C`. + +* Under :ref:`context ` :math:`C`, the :ref:`function ` :math:`\func` must be :ref:`valid ` with :ref:`function type ` :math:`\functype`. + +* Then the function instance is valid with :ref:`function type ` :math:`\functype`. + +.. math:: + \frac{ + \vdashfunctype \functype \ok + \qquad + S \vdashmoduleinst \moduleinst : C + \qquad + C \vdashfunc \func : \functype + }{ + S \vdashfuncinst \{\FITYPE~\functype, \FIMODULE~\moduleinst, \FICODE~\func\} : \functype + } + + +.. index:: function type, function instance, host function +.. _valid-hostfuncinst: + +:ref:`Host Function Instances ` :math:`\{\FITYPE~\functype, \FIHOSTCODE~\X{hf}\}` +.................................................................................................. + +* The :ref:`function type ` :math:`\functype` must be :ref:`valid `. + +* Let :math:`[t_1^\ast] \to [t_2^\ast]` be the :ref:`function type ` :math:`\functype`. + +* For every :ref:`valid ` :ref:`store ` :math:`S_1` :ref:`extending ` :math:`S` and every sequence :math:`\val^\ast` of :ref:`values ` whose :ref:`types ` coincide with :math:`t_1^\ast`: + + * :ref:`Executing ` :math:`\X{hf}` in store :math:`S_1` with arguments :math:`\val^\ast` has a non-empty set of possible outcomes. + + * For every element :math:`R` of this set: + + * Either :math:`R` must be :math:`\bot` (i.e., divergence). + + * Or :math:`R` consists of a :ref:`valid ` :ref:`store ` :math:`S_2` :ref:`extending ` :math:`S_1` and a :ref:`result ` :math:`\result` whose :ref:`type ` coincides with :math:`[t_2^\ast]`. + +* Then the function instance is valid with :ref:`function type ` :math:`\functype`. + +.. math:: + \frac{ + \begin{array}[b]{@{}l@{}} + \vdashfunctype [t_1^\ast] \to [t_2^\ast] \ok \\ + \end{array} + \quad + \begin{array}[b]{@{}l@{}} + \forall S_1, \val^\ast,~ + {\vdashstore S_1 \ok} \wedge + {\vdashstoreextends S \extendsto S_1} \wedge + {S_1 \vdashresult \val^\ast : [t_1^\ast]} + \Longrightarrow {} \\ \qquad + \X{hf}(S_1; \val^\ast) \supset \emptyset \wedge {} \\ \qquad + \forall R \in \X{hf}(S_1; \val^\ast),~ + R = \bot \vee {} \\ \qquad\qquad + \exists S_2, \result,~ + {\vdashstore S_2 \ok} \wedge + {\vdashstoreextends S_1 \extendsto S_2} \wedge + {S_2 \vdashresult \result : [t_2^\ast]} \wedge + R = (S_2; \result) + \end{array} + }{ + S \vdashfuncinst \{\FITYPE~[t_1^\ast] \to [t_2^\ast], \FIHOSTCODE~\X{hf}\} : [t_1^\ast] \to [t_2^\ast] + } + +.. note:: + This rule states that, if appropriate pre-conditions about store and arguments are satisfied, then executing the host function must satisfy appropriate post-conditions about store and results. + The post-conditions match the ones in the :ref:`execution rule ` for invoking host functions. + + Any store under which the function is invoked is assumed to be an extension of the current store. + That way, the function itself is able to make sufficient assumptions about future stores. + + +.. index:: table type, table instance, limits, function address +.. _valid-tableinst: + +:ref:`Table Instances ` :math:`\{ \TITYPE~(\limits~t), \TIELEM~\reff^\ast \}` +............................................................................................... + +* The :ref:`table type ` :math:`\limits~t` must be :ref:`valid `. + +* The length of :math:`\reff^\ast` must equal :math:`\limits.\LMIN`. + +* For each :ref:`reference ` :math:`\reff_i` in the table elements :math:`\reff^n`: + + * The :ref:`reference ` :math:`\reff_i` must be :ref:`valid ` with some :ref:`reference type ` :math:`t'_i`. + + * The :ref:`reference type ` :math:`t'_i` must :ref:`match ` the :ref:`reference type ` :math:`t`. + +* Then the table instance is valid with :ref:`table type ` :math:`\limits~t`. + +.. math:: + \frac{ + \vdashtabletype \limits~t \ok + \qquad + n = \limits.\LMIN + \qquad + (S \vdash \reff : t')^n + \qquad + (\vdashreftypematch t' \matchesvaltype t)^n + }{ + S \vdashtableinst \{ \TITYPE~(\limits~t), \TIELEM~\reff^n \} : \limits~t + } + + +.. index:: memory type, memory instance, limits, byte +.. _valid-meminst: + +:ref:`Memory Instances ` :math:`\{ \MITYPE~\limits, \MIDATA~b^\ast \}` +...................................................................................... + +* The :ref:`memory type ` :math:`\{\LMIN~n, \LMAX~m^?\}` must be :ref:`valid `. + +* The length of :math:`b^\ast` must equal :math:`\limits.\LMIN` multiplied by the :ref:`page size ` :math:`64\,\F{Ki}`. + +* Then the memory instance is valid with :ref:`memory type ` :math:`\limits`. + +.. math:: + \frac{ + \vdashmemtype \limits \ok + \qquad + n = \limits.\LMIN \cdot 64\,\F{Ki} + }{ + S \vdashmeminst \{ \MITYPE~\limits, \MIDATA~b^n \} : \limits + } + + +.. index:: global type, global instance, value, mutability +.. _valid-globalinst: + +:ref:`Global Instances ` :math:`\{ \GITYPE~(\mut~t), \GIVALUE~\val \}` +......................................................................................... + +* The :ref:`global type ` :math:`\mut~t` must be :ref:`valid `. + +* The :ref:`value ` :math:`\val` must be :ref:`valid ` with some :ref:`value type ` :math:`t'`. + +* The :ref:`value type ` :math:`t'` must :ref:`match ` the :ref:`value type ` :math:`t`. + +* Then the global instance is valid with :ref:`global type ` :math:`\mut~t`. + +.. math:: + \frac{ + \vdashglobaltype \mut~t \ok + \qquad + S \vdashval \val : t' + \qquad + \vdashvaltypematch t' \matchesvaltype t + }{ + S \vdashglobalinst \{ \GITYPE~(\mut~t), \GIVALUE~\val \} : \mut~t + } + + +.. index:: external type, export instance, name, external value +.. _valid-exportinst: + +:ref:`Export Instances ` :math:`\{ \EINAME~\name, \EIVALUE~\externval \}` +....................................................................................................... + +* The :ref:`external value ` :math:`\externval` must be :ref:`valid ` with some :ref:`external type ` :math:`\externtype`. + +* Then the export instance is valid. + +.. math:: + \frac{ + S \vdashexternval \externval : \externtype + }{ + S \vdashexportinst \{ \EINAME~\name, \EIVALUE~\externval \} \ok + } + + +.. index:: module instance, context +.. _valid-moduleinst: + +:ref:`Module Instances ` :math:`\moduleinst` +............................................................... + +* Each :ref:`function type ` :math:`\functype_i` in :math:`\moduleinst.\MITYPES` must be :ref:`valid `. + +* For each :ref:`function address ` :math:`\funcaddr_i` in :math:`\moduleinst.\MIFUNCS`, the :ref:`external value ` :math:`\EVFUNC~\funcaddr_i` must be :ref:`valid ` with some :ref:`external type ` :math:`\ETFUNC~\functype'_i`. + +* For each :ref:`table address ` :math:`\tableaddr_i` in :math:`\moduleinst.\MITABLES`, the :ref:`external value ` :math:`\EVTABLE~\tableaddr_i` must be :ref:`valid ` with some :ref:`external type ` :math:`\ETTABLE~\tabletype_i`. + +* For each :ref:`memory address ` :math:`\memaddr_i` in :math:`\moduleinst.\MIMEMS`, the :ref:`external value ` :math:`\EVMEM~\memaddr_i` must be :ref:`valid ` with some :ref:`external type ` :math:`\ETMEM~\memtype_i`. + +* For each :ref:`global address ` :math:`\globaladdr_i` in :math:`\moduleinst.\MIGLOBALS`, the :ref:`external value ` :math:`\EVGLOBAL~\globaladdr_i` must be :ref:`valid ` with some :ref:`external type ` :math:`\ETGLOBAL~\globaltype_i`. + +* Each :ref:`export instance ` :math:`\exportinst_i` in :math:`\moduleinst.\MIEXPORTS` must be :ref:`valid `. + +* For each :ref:`export instance ` :math:`\exportinst_i` in :math:`\moduleinst.\MIEXPORTS`, the :ref:`name ` :math:`\exportinst_i.\EINAME` must be different from any other name occurring in :math:`\moduleinst.\MIEXPORTS`. + +* Let :math:`{\functype'}^\ast` be the concatenation of all :math:`\functype'_i` in order. + +* Let :math:`\tabletype^\ast` be the concatenation of all :math:`\tabletype_i` in order. + +* Let :math:`\memtype^\ast` be the concatenation of all :math:`\memtype_i` in order. + +* Let :math:`\globaltype^\ast` be the concatenation of all :math:`\globaltype_i` in order. + +* Then the module instance is valid with :ref:`context ` :math:`\{\CTYPES~\functype^\ast, \CFUNCS~{\functype'}^\ast, \CTABLES~\tabletype^\ast, \CMEMS~\memtype^\ast, \CGLOBALS~\globaltype^\ast\}`. + +.. math:: + ~\\[-1ex] + \frac{ + \begin{array}{@{}c@{}} + (\vdashfunctype \functype \ok)^\ast + \\ + (S \vdashexternval \EVFUNC~\funcaddr : \ETFUNC~\functype')^\ast + \qquad + (S \vdashexternval \EVTABLE~\tableaddr : \ETTABLE~\tabletype)^\ast + \\ + (S \vdashexternval \EVMEM~\memaddr : \ETMEM~\memtype)^\ast + \qquad + (S \vdashexternval \EVGLOBAL~\globaladdr : \ETGLOBAL~\globaltype)^\ast + \\ + (S \vdashexportinst \exportinst \ok)^\ast + \qquad + (\exportinst.\EINAME)^\ast ~\mbox{disjoint} + \end{array} + }{ + S \vdashmoduleinst \{ + \begin{array}[t]{@{}l@{~}l@{}} + \MITYPES & \functype^\ast, \\ + \MIFUNCS & \funcaddr^\ast, \\ + \MITABLES & \tableaddr^\ast, \\ + \MIMEMS & \memaddr^\ast, \\ + \MIGLOBALS & \globaladdr^\ast \\ + \MIEXPORTS & \exportinst^\ast ~\} : \{ + \begin{array}[t]{@{}l@{~}l@{}} + \CTYPES & \functype^\ast, \\ + \CFUNCS & {\functype'}^\ast, \\ + \CTABLES & \tabletype^\ast, \\ + \CMEMS & \memtype^\ast, \\ + \CGLOBALS & \globaltype^\ast ~\} + \end{array} + \end{array} + } + + +.. index:: configuration, administrative instruction, store, frame +.. _frame-context: +.. _valid-config: + +Configuration Validity +~~~~~~~~~~~~~~~~~~~~~~ + +To relate the WebAssembly :ref:`type system ` to its :ref:`execution semantics `, the :ref:`typing rules for instructions ` must be extended to :ref:`configurations ` :math:`S;T`, +which relates the :ref:`store ` to execution :ref:`threads `. + +Configurations and threads are classified by their :ref:`result type `. +In addition to the store :math:`S`, threads are typed under a *return type* :math:`\resulttype^?`, which controls whether and with which type a |return| instruction is allowed. +This type is absent (:math:`\epsilon`) except for instruction sequences inside an administrative |FRAME| instruction. + +Finally, :ref:`frames ` are classified with *frame contexts*, which extend the :ref:`module contexts ` of a frame's associated :ref:`module instance ` with the :ref:`locals ` that the frame contains. + + +.. index:: result type, thread + +:ref:`Configurations ` :math:`S;T` +................................................. + +* The :ref:`store ` :math:`S` must be :ref:`valid `. + +* Under no allowed return type, + the :ref:`thread ` :math:`T` must be :ref:`valid ` with some :ref:`result type ` :math:`[t^?]`. + +* Then the configuration is valid with the :ref:`result type ` :math:`[t^?]`. + +.. math:: + \frac{ + \vdashstore S \ok + \qquad + S; \epsilon \vdashthread T : [t^?] + }{ + \vdashconfig S; T : [t^?] + } + + +.. index:: thread, frame, instruction, result type, context +.. _valid-thread: + +:ref:`Threads ` :math:`F;\instr^\ast` +.................................................... + +* Let :math:`\resulttype^?` be the current allowed return type. + +* The :ref:`frame ` :math:`F` must be :ref:`valid ` with a :ref:`context ` :math:`C`. + +* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with |CRETURN| set to :math:`\resulttype^?`. + +* Under context :math:`C'`, + the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with some type :math:`[] \to [t^?]`. + +* Then the thread is valid with the :ref:`result type ` :math:`[t^?]`. + +.. math:: + \frac{ + S \vdashframe F : C + \qquad + S; C,\CRETURN~\resulttype^? \vdashinstrseq \instr^\ast : [] \to [t^?] + }{ + S; \resulttype^? \vdashthread F; \instr^\ast : [t^?] + } + + +.. index:: frame, local, module instance, value, value type, context +.. _valid-frame: + +:ref:`Frames ` :math:`\{\ALOCALS~\val^\ast, \AMODULE~\moduleinst\}` +................................................................................. + +* The :ref:`module instance ` :math:`\moduleinst` must be :ref:`valid ` with some :ref:`module context ` :math:`C`. + +* Each :ref:`value ` :math:`\val_i` in :math:`\val^\ast` must be :ref:`valid ` with some :ref:`value type ` :math:`t_i`. + +* Let :math:`t^\ast` the concatenation of all :math:`t_i` in order. + +* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`value types ` :math:`t^\ast` prepended to the |CLOCALS| vector. + +* Then the frame is valid with :ref:`frame context ` :math:`C'`. + +.. math:: + \frac{ + S \vdashmoduleinst \moduleinst : C + \qquad + (S \vdashval \val : t)^\ast + }{ + S \vdashframe \{\ALOCALS~\val^\ast, \AMODULE~\moduleinst\} : (C, \CLOCALS~t^\ast) + } + + +.. index:: administrative instruction, value type, context, store +.. _valid-instr-admin: + +Administrative Instructions +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Typing rules for :ref:`administrative instructions ` are specified as follows. +In addition to the :ref:`context ` :math:`C`, typing of these instructions is defined under a given :ref:`store ` :math:`S`. +To that end, all previous typing judgements :math:`C \vdash \X{prop}` are generalized to include the store, as in :math:`S; C \vdash \X{prop}`, by implicitly adding :math:`S` to all rules -- :math:`S` is never modified by the pre-existing rules, but it is accessed in the extra rules for :ref:`administrative instructions ` given below. + + +.. index:: trap + +:math:`\TRAP` +............. + +* The instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`, for any sequences of :ref:`value types ` :math:`t_1^\ast` and :math:`t_2^\ast`. + +.. math:: + \frac{ + }{ + S; C \vdashadmininstr \TRAP : [t_1^\ast] \to [t_2^\ast] + } + + +.. index:: host address + +:math:`\REFHOST~\hostaddr` +.......................... + +* The instruction is valid with type :math:`[] \to [\ANYREF]`. + +.. math:: + \frac{ + }{ + S; C \vdashadmininstr \REFHOST~\hostaddr : [] \to [\ANYREF] + } + + +.. index:: function address, extern value, extern type, function type + +:math:`\REFFUNCADDR~\funcaddr` +.............................. + +* The :ref:`external function value ` :math:`\EVFUNC~\funcaddr` must be :ref:`valid ` with :ref:`external function type ` :math:`\ETFUNC \functype`. + +* Then the instruction is valid with type :math:`[] \to [\FUNCREF]`. + +.. math:: + \frac{ + S \vdashexternval \EVFUNC~\funcaddr : \ETFUNC~\functype + }{ + S; C \vdashadmininstr \REFFUNCADDR~\funcaddr : [] \to [\FUNCREF] + } + + +.. index:: function address, extern value, extern type, function type + +:math:`\INVOKE~\funcaddr` +......................... + +* The :ref:`external function value ` :math:`\EVFUNC~\funcaddr` must be :ref:`valid ` with :ref:`external function type ` :math:`\ETFUNC ([t_1^\ast] \to [t_2^\ast])`. + +* Then the instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`. + +.. math:: + \frac{ + S \vdashexternval \EVFUNC~\funcaddr : \ETFUNC~[t_1^\ast] \to [t_2^\ast] + }{ + S; C \vdashadmininstr \INVOKE~\funcaddr : [t_1^\ast] \to [t_2^\ast] + } + + +.. index:: element, table, table address, module instance, function index + +:math:`\INITELEM~\tableaddr~o~x^n` +.................................. + +* The :ref:`external table value ` :math:`\EVTABLE~\tableaddr` must be :ref:`valid ` with some :ref:`external table type ` :math:`\ETTABLE~(\limits~\FUNCREF)`. + +* The index :math:`o + n` must be smaller than or equal to :math:`\limits.\LMIN`. + +* The :ref:`module instance ` :math:`\moduleinst` must be :ref:`valid ` with some :ref:`context ` :math:`C`. + +* Each :ref:`function index ` :math:`x_i` in :math:`x^n` must be defined in the context :math:`C`. + +* Then the instruction is valid. + +.. math:: + \frac{ + S \vdashexternval \EVTABLE~\tableaddr : \ETTABLE~\limits~\FUNCREF + \qquad + o + n \leq \limits.\LMIN + \qquad + (C.\CFUNCS[x] = \functype)^n + }{ + S; C \vdashadmininstr \INITELEM~\tableaddr~o~x^n \ok + } + + +.. index:: data, memory, memory address, byte + +:math:`\INITDATA~\memaddr~o~b^n` +................................ + +* The :ref:`external memory value ` :math:`\EVMEM~\memaddr` must be :ref:`valid ` with some :ref:`external memory type ` :math:`\ETMEM~\limits`. + +* The index :math:`o + n` must be smaller than or equal to :math:`\limits.\LMIN` divided by the :ref:`page size ` :math:`64\,\F{Ki}`. + +* Then the instruction is valid. + +.. math:: + \frac{ + S \vdashexternval \EVMEM~\memaddr : \ETMEM~\limits + \qquad + o + n \leq \limits.\LMIN \cdot 64\,\F{Ki} + }{ + S; C \vdashadmininstr \INITDATA~\memaddr~o~b^n \ok + } + + +.. index:: label, instruction, result type + +:math:`\LABEL_n\{\instr_0^\ast\}~\instr^\ast~\END` +.................................................. + +* The instruction sequence :math:`\instr_0^\ast` must be :ref:`valid ` with some type :math:`[t_1^n] \to [t_2^?]`. + +* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`result type ` :math:`[t_1^n]` prepended to the |CLABELS| vector. + +* Under context :math:`C'`, + the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[] \to [t_2^?]`. + +* Then the compound instruction is valid with type :math:`[] \to [t_2^?]`. + +.. math:: + \frac{ + S; C \vdashinstrseq \instr_0^\ast : [t_1^n] \to [t_2^?] + \qquad + S; C,\CLABELS\,[t_1^n] \vdashinstrseq \instr^\ast : [] \to [t_2^?] + }{ + S; C \vdashadmininstr \LABEL_n\{\instr_0^\ast\}~\instr^\ast~\END : [] \to [t_2^?] + } + + +.. index:: frame, instruction, result type + +:math:`\FRAME_n\{F\}~\instr^\ast~\END` +........................................... + +* Under the return type :math:`[t^n]`, + the :ref:`thread ` :math:`F; \instr^\ast` must be :ref:`valid ` with :ref:`result type ` :math:`[t^n]`. + +* Then the compound instruction is valid with type :math:`[] \to [t^n]`. + +.. math:: + \frac{ + S; [t^n] \vdashinstrseq F; \instr^\ast : [t^n] + }{ + S; C \vdashadmininstr \FRAME_n\{F\}~\instr^\ast~\END : [] \to [t^n] + } + + +.. index:: ! store extension, store +.. _extend: + +Store Extension +~~~~~~~~~~~~~~~ + +Programs can mutate the :ref:`store ` and its contained instances. +Any such modification must respect certain invariants, such as not removing allocated instances or changing immutable definitions. +While these invariants are inherent to the execution semantics of WebAssembly :ref:`instructions ` and :ref:`modules `, +:ref:`host functions ` do not automatically adhere to them. Consequently, the required invariants must be stated as explicit constraints on the :ref:`invocation ` of host functions. +Soundness only holds when the :ref:`embedder ` ensures these constraints. + +The necessary constraints are codified by the notion of store *extension*: +a store state :math:`S'` extends state :math:`S`, written :math:`S \extendsto S'`, when the following rules hold. + +.. note:: + Extension does not imply that the new store is valid, which is defined separately :ref:`above `. + + +.. index:: store, function instance, table instance, memory instance, global instance +.. _extend-store: + +:ref:`Store ` :math:`S` +..................................... + +* The length of :math:`S.\SFUNCS` must not shrink. + +* The length of :math:`S.\STABLES` must not shrink. + +* The length of :math:`S.\SMEMS` must not shrink. + +* The length of :math:`S.\SGLOBALS` must not shrink. + +* For each :ref:`function instance ` :math:`\funcinst_i` in the original :math:`S.\SFUNCS`, the new function instance must be an :ref:`extension ` of the old. + +* For each :ref:`table instance ` :math:`\tableinst_i` in the original :math:`S.\STABLES`, the new table instance must be an :ref:`extension ` of the old. + +* For each :ref:`memory instance ` :math:`\meminst_i` in the original :math:`S.\SMEMS`, the new memory instance must be an :ref:`extension ` of the old. + +* For each :ref:`global instance ` :math:`\globalinst_i` in the original :math:`S.\SGLOBALS`, the new global instance must be an :ref:`extension ` of the old. + +.. math:: + \frac{ + \begin{array}{@{}ccc@{}} + S_1.\SFUNCS = \funcinst_1^\ast & + S_2.\SFUNCS = {\funcinst'_1}^\ast~\funcinst_2^\ast & + (\funcinst_1 \extendsto \funcinst'_1)^\ast \\ + S_1.\STABLES = \tableinst_1^\ast & + S_2.\STABLES = {\tableinst'_1}^\ast~\tableinst_2^\ast & + (\tableinst_1 \extendsto \tableinst'_1)^\ast \\ + S_1.\SMEMS = \meminst_1^\ast & + S_2.\SMEMS = {\meminst'_1}^\ast~\meminst_2^\ast & + (\meminst_1 \extendsto \meminst'_1)^\ast \\ + S_1.\SGLOBALS = \globalinst_1^\ast & + S_2.\SGLOBALS = {\globalinst'_1}^\ast~\globalinst_2^\ast & + (\globalinst_1 \extendsto \globalinst'_1)^\ast \\ + \end{array} + }{ + \vdashstoreextends S_1 \extendsto S_2 + } + + +.. index:: function instance +.. _extend-funcinst: + +:ref:`Function Instance ` :math:`\funcinst` +............................................................ + +* A function instance must remain unchanged. + +.. math:: + \frac{ + }{ + \vdashfuncinstextends \funcinst \extendsto \funcinst + } + + +.. index:: table instance +.. _extend-tableinst: + +:ref:`Table Instance ` :math:`\tableinst` +........................................................... + +* The :ref:`table type ` :math:`\tableinst.\TITYPE` must remain unchanged. + +* The length of :math:`\tableinst.\TIELEM` must not shrink. + +.. math:: + \frac{ + n_1 \leq n_2 + }{ + \vdashtableinstextends \{\TITYPE~\X{tt}, \TIELEM~(\X{fa}_1^?)^{n_1}\} \extendsto \{\TITYPE~\X{tt}, \TIELEM~(\X{fa}_2^?)^{n_2}\} + } + + +.. index:: memory instance +.. _extend-meminst: + +:ref:`Memory Instance ` :math:`\meminst` +........................................................ + +* The :ref:`memory type ` :math:`\meminst.\MITYPE` must remain unchanged. + +* The length of :math:`\meminst.\MIDATA` must not shrink. + +.. math:: + \frac{ + n_1 \leq n_2 + }{ + \vdashmeminstextends \{\MITYPE~\X{mt}, \MIDATA~b_1^{n_1}\} \extendsto \{\MITYPE~\X{mt}, \MIDATA~b_2^{n_2}\} + } + + +.. index:: global instance, value, mutability +.. _extend-globalinst: + +:ref:`Global Instance ` :math:`\globalinst` +.............................................................. + +* The :ref:`global type ` :math:`\globalinst.\GITYPE` must remain unchanged. + +* Let :math:`\mut~t` be the structure of :math:`\globalinst.\GITYPE`. + +* If :math:`\mut` is |MCONST|, then the :ref:`value ` :math:`\globalinst.\GIVALUE` must remain unchanged. + +.. math:: + \frac{ + \mut = \MVAR \vee \val_1 = \val_2 + }{ + \vdashglobalinstextends \{\GITYPE~(\mut~t), \GIVALUE~\val_1\} \extendsto \{\GITYPE~(\mut~t), \GIVALUE~\val_2\} + } + + + +.. index:: ! preservation, ! progress, soundness, configuration, thread, terminal configuration, instantiation, invocation, validity, module +.. _soundness-statement: + +Theorems +~~~~~~~~ + +Given the definition of :ref:`valid configurations `, +the standard soundness theorems hold. [#cite-cpp2018]_ + +**Theorem (Preservation).** +If a :ref:`configuration ` :math:`S;T` is :ref:`valid ` with :ref:`result type ` :math:`[t^\ast]` (i.e., :math:`\vdashconfig S;T : [t^\ast]`), +and steps to :math:`S';T'` (i.e., :math:`S;T \stepto S';T'`), +then :math:`S';T'` is a valid configuration with the same result type (i.e., :math:`\vdashconfig S';T' : [t^\ast]`). +Furthermore, :math:`S'` is an :ref:`extension ` of :math:`S` (i.e., :math:`\vdashstoreextends S \extendsto S'`). + +A *terminal* :ref:`thread ` is one whose sequence of :ref:`instructions ` is a :ref:`result `. +A terminal configuration is a configuration whose thread is terminal. + +**Theorem (Progress).** +If a :ref:`configuration ` :math:`S;T` is :ref:`valid ` (i.e., :math:`\vdashconfig S;T : [t^\ast]` for some :ref:`result type ` :math:`[t^\ast]`), +then either it is terminal, +or it can step to some configuration :math:`S';T'` (i.e., :math:`S;T \stepto S';T'`). + +From Preservation and Progress the soundness of the WebAssembly type system follows directly. + +**Corollary (Soundness).** +If a :ref:`configuration ` :math:`S;T` is :ref:`valid ` (i.e., :math:`\vdashconfig S;T : [t^\ast]` for some :ref:`result type ` :math:`[t^\ast]`), +then it either diverges or takes a finite number of steps to reach a terminal configuration :math:`S';T'` (i.e., :math:`S;T \stepto^\ast S';T'`) that is valid with the same result type (i.e., :math:`\vdashconfig S';T' : [t^\ast]`) +and where :math:`S'` is an :ref:`extension ` of :math:`S` (i.e., :math:`\vdashstoreextends S \extendsto S'`). + +In other words, every thread in a valid configuration either runs forever, traps, or terminates with a result that has the expected type. +Consequently, given a :ref:`valid store `, no computation defined by :ref:`instantiation ` or :ref:`invocation ` of a valid module can "crash" or otherwise (mis)behave in ways not covered by the :ref:`execution ` semantics given in this specification. + + +.. [#cite-pldi2017] + The formalization and theorems are derived from the following article: + Andreas Haas, Andreas Rossberg, Derek Schuff, Ben Titzer, Dan Gohman, Luke Wagner, Alon Zakai, JF Bastien, Michael Holman. |PLDI2017|_. Proceedings of the 38th ACM SIGPLAN Conference on Programming Language Design and Implementation (PLDI 2017). ACM 2017. + +.. [#cite-cpp2018] + A machine-verified version of the formalization and soundness proof is described in the following article: + Conrad Watt. |CPP2018|_. Proceedings of the 7th ACM SIGPLAN Conference on Certified Programs and Proofs (CPP 2018). ACM 2018. diff --git a/document/core/binary/conventions.rst b/document/core/binary/conventions.rst new file mode 100644 index 0000000000..8d38399773 --- /dev/null +++ b/document/core/binary/conventions.rst @@ -0,0 +1,118 @@ +.. index:: ! binary format, module, byte, file extension, abstract syntax + +Conventions +----------- + +The binary format for WebAssembly :ref:`modules ` is a dense linear *encoding* of their :ref:`abstract syntax `. +[#compression]_ + +The format is defined by an *attribute grammar* whose only terminal symbols are :ref:`bytes `. +A byte sequence is a well-formed encoding of a module if and only if it is generated by the grammar. + +Each production of this grammar has exactly one synthesized attribute: the abstract syntax that the respective byte sequence encodes. +Thus, the attribute grammar implicitly defines a *decoding* function +(i.e., a parsing function for the binary format). + +Except for a few exceptions, the binary grammar closely mirrors the grammar of the abstract syntax. + +.. note:: + Some phrases of abstract syntax have multiple possible encodings in the binary format. + For example, numbers may be encoded as if they had optional leading zeros. + Implementations of decoders must support all possible alternatives; + implementations of encoders can pick any allowed encoding. + +The recommended extension for files containing WebAssembly modules in binary format is ":math:`\T{.wasm}`" +and the recommended |MediaType|_ is ":math:`\T{application/wasm}`". + +.. [#compression] + Additional encoding layers -- for example, introducing compression -- may be defined on top of the basic representation defined here. + However, such layers are outside the scope of the current specification. + + +.. index:: grammar notation, notation, byte + single: binary format; grammar + pair: binary format; notation +.. _binary-grammar: + +Grammar +~~~~~~~ + +The following conventions are adopted in defining grammar rules for the binary format. +They mirror the conventions used for :ref:`abstract syntax `. +In order to distinguish symbols of the binary syntax from symbols of the abstract syntax, :math:`\mathtt{typewriter}` font is adopted for the former. + +* Terminal symbols are :ref:`bytes ` expressed in hexadecimal notation: :math:`\hex{0F}`. + +* Nonterminal symbols are written in typewriter font: :math:`\B{valtype}, \B{instr}`. + +* :math:`B^n` is a sequence of :math:`n\geq 0` iterations of :math:`B`. + +* :math:`B^\ast` is a possibly empty sequence of iterations of :math:`B`. + (This is a shorthand for :math:`B^n` used where :math:`n` is not relevant.) + +* :math:`B^?` is an optional occurrence of :math:`B`. + (This is a shorthand for :math:`B^n` where :math:`n \leq 1`.) + +* :math:`x{:}B` denotes the same language as the nonterminal :math:`B`, but also binds the variable :math:`x` to the attribute synthesized for :math:`B`. + +* Productions are written :math:`\B{sym} ::= B_1 \Rightarrow A_1 ~|~ \dots ~|~ B_n \Rightarrow A_n`, where each :math:`A_i` is the attribute that is synthesized for :math:`\B{sym}` in the given case, usually from attribute variables bound in :math:`B_i`. + +* Some productions are augmented by side conditions in parentheses, which restrict the applicability of the production. They provide a shorthand for a combinatorial expansion of the production into many separate cases. + +.. note:: + For example, the :ref:`binary grammar ` for :ref:`value types ` is given as follows: + + .. math:: + \begin{array}{llcll@{\qquad\qquad}l} + \production{value types} & \Bvaltype &::=& + \hex{7F} &\Rightarrow& \I32 \\ &&|& + \hex{7E} &\Rightarrow& \I64 \\ &&|& + \hex{7D} &\Rightarrow& \F32 \\ &&|& + \hex{7C} &\Rightarrow& \F64 \\ + \end{array} + + Consequently, the byte :math:`\hex{7F}` encodes the type |I32|, + :math:`\hex{7E}` encodes the type |I64|, and so forth. + No other byte value is allowed as the encoding of a value type. + + The :ref:`binary grammar ` for :ref:`limits ` is defined as follows: + + .. math:: + \begin{array}{llclll} + \production{limits} & \Blimits &::=& + \hex{00}~~n{:}\Bu32 &\Rightarrow& \{ \LMIN~n, \LMAX~\epsilon \} \\ &&|& + \hex{01}~~n{:}\Bu32~~m{:}\Bu32 &\Rightarrow& \{ \LMIN~n, \LMAX~m \} \\ + \end{array} + + That is, a limits pair is encoded as either the byte :math:`\hex{00}` followed by the encoding of a |U32| value, + or the byte :math:`\hex{01}` followed by two such encodings. + The variables :math:`n` and :math:`m` name the attributes of the respective |Bu32| nonterminals, which in this case are the actual :ref:`unsigned integers ` those decode into. + The attribute of the complete production then is the abstract syntax for the limit, expressed in terms of the former values. + + +.. _binary-notation: + +Auxiliary Notation +~~~~~~~~~~~~~~~~~~ + +When dealing with binary encodings the following notation is also used: + +* :math:`\epsilon` denotes the empty byte sequence. + +* :math:`||B||` is the length of the byte sequence generated from the production :math:`B` in a derivation. + + +.. index:: vector + pair: binary format; vector +.. _binary-vec: + +Vectors +~~~~~~~ + +:ref:`Vectors ` are encoded with their |Bu32| length followed by the encoding of their element sequence. + +.. math:: + \begin{array}{llclll@{\qquad\qquad}l} + \production{vector} & \Bvec(\B{B}) &::=& + n{:}\Bu32~~(x{:}\B{B})^n &\Rightarrow& x^n \\ + \end{array} diff --git a/document/binary/index.rst b/document/core/binary/index.rst similarity index 86% rename from document/binary/index.rst rename to document/core/binary/index.rst index ce1879ddeb..b47e6647a9 100644 --- a/document/binary/index.rst +++ b/document/core/binary/index.rst @@ -1,4 +1,4 @@ -.. _binary-format: +.. _binary: Binary Format ============= @@ -9,5 +9,5 @@ Binary Format conventions values types - modules instructions + modules diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst new file mode 100644 index 0000000000..27deed05f5 --- /dev/null +++ b/document/core/binary/instructions.rst @@ -0,0 +1,429 @@ +.. index:: instruction, ! opcode +.. _binary-instr: + +Instructions +------------ + +:ref:`Instructions ` are encoded by *opcodes*. +Each opcode is represented by a single byte, +and is followed by the instruction's immediate arguments, where present. +The only exception are :ref:`structured control instructions `, which consist of several opcodes bracketing their nested instruction sequences. + +.. note:: + Gaps in the byte code ranges for encoding instructions are reserved for future extensions. + + +.. index:: control instructions, structured control, label, block, branch, result type, label index, function index, type index, vector, polymorphism + pair: binary format; instruction +.. _binary-instr-control: + +Control Instructions +~~~~~~~~~~~~~~~~~~~~ + +:ref:`Control instructions ` have varying encodings. For structured instructions, the instruction sequences forming nested blocks are terminated with explicit opcodes for |END| and |ELSE|. + +.. _binary-nop: +.. _binary-unreachable: +.. _binary-block: +.. _binary-loop: +.. _binary-if: +.. _binary-br: +.. _binary-br_if: +.. _binary-br_table: +.. _binary-return: +.. _binary-call: +.. _binary-call_indirect: + +.. math:: + \begin{array}{llclll} + \production{instruction} & \Binstr &::=& + \hex{00} &\Rightarrow& \UNREACHABLE \\ &&|& + \hex{01} &\Rightarrow& \NOP \\ &&|& + \hex{02}~~\X{rt}{:}\Bblocktype~~(\X{in}{:}\Binstr)^\ast~~\hex{0B} + &\Rightarrow& \BLOCK~\X{rt}~\X{in}^\ast~\END \\ &&|& + \hex{03}~~\X{rt}{:}\Bblocktype~~(\X{in}{:}\Binstr)^\ast~~\hex{0B} + &\Rightarrow& \LOOP~\X{rt}~\X{in}^\ast~\END \\ &&|& + \hex{04}~~\X{rt}{:}\Bblocktype~~(\X{in}{:}\Binstr)^\ast~~\hex{0B} + &\Rightarrow& \IF~\X{rt}~\X{in}^\ast~\ELSE~\epsilon~\END \\ &&|& + \hex{04}~~\X{rt}{:}\Bblocktype~~(\X{in}_1{:}\Binstr)^\ast~~ + \hex{05}~~(\X{in}_2{:}\Binstr)^\ast~~\hex{0B} + &\Rightarrow& \IF~\X{rt}~\X{in}_1^\ast~\ELSE~\X{in}_2^\ast~\END \\ &&|& + \hex{0C}~~l{:}\Blabelidx &\Rightarrow& \BR~l \\ &&|& + \hex{0D}~~l{:}\Blabelidx &\Rightarrow& \BRIF~l \\ &&|& + \hex{0E}~~l^\ast{:}\Bvec(\Blabelidx)~~l_N{:}\Blabelidx + &\Rightarrow& \BRTABLE~l^\ast~l_N \\ &&|& + \hex{0F} &\Rightarrow& \RETURN \\ &&|& + \hex{10}~~x{:}\Bfuncidx &\Rightarrow& \CALL~x \\ &&|& + \hex{11}~~y{:}\Btypeidx~~x{:}\Btableidx &\Rightarrow& \CALLINDIRECT~x~y \\ + \end{array} + +.. note:: + The |ELSE| opcode :math:`\hex{05}` in the encoding of an |IF| instruction can be omitted if the following instruction sequence is empty. + + +.. index:: reference instruction + pair: binary format; instruction +.. _binary-instr-ref: + +Reference Instructions +~~~~~~~~~~~~~~~~~~~~~~ + +:ref:`Reference instructions ` are represented by single byte codes. + +.. _binary-ref.null: +.. _binary-ref.isnull: + +.. math:: + \begin{array}{llclll} + \production{instruction} & \Binstr &::=& \dots \\ &&|& + \hex{D0} &\Rightarrow& \REFNULL \\ &&|& + \hex{D1} &\Rightarrow& \REFISNULL \\ &&|& + \hex{D2}~~x{:}\Bfuncidx &\Rightarrow& \REFFUNC~x \\ + \end{array} + +.. note:: + These opcode assignments are preliminary. + + +.. index:: parametric instruction, value type, polymorphism + pair: binary format; instruction +.. _binary-instr-parametric: + +Parametric Instructions +~~~~~~~~~~~~~~~~~~~~~~~ + +:ref:`Parametric instructions ` are represented by single byte codes, possibly followed by a type annotation. + +.. _binary-drop: +.. _binary-select: + +.. math:: + \begin{array}{llclll} + \production{instruction} & \Binstr &::=& \dots \\ &&|& + \hex{1A} &\Rightarrow& \DROP \\ &&|& + \hex{1B} &\Rightarrow& \SELECT \\ &&|& + \hex{1C}~~t^\ast{:}\Bvec(\Bvaltype) &\Rightarrow& \SELECT~t^\ast \\ + \end{array} + + +.. index:: variable instructions, local index, global index + pair: binary format; instruction +.. _binary-instr-variable: + +Variable Instructions +~~~~~~~~~~~~~~~~~~~~~ + +:ref:`Variable instructions ` are represented by byte codes followed by the encoding of the respective :ref:`index `. + +.. _binary-local.get: +.. _binary-local.set: +.. _binary-local.tee: +.. _binary-global.get: +.. _binary-global.set: + +.. math:: + \begin{array}{llclll} + \production{instruction} & \Binstr &::=& \dots \\ &&|& + \hex{20}~~x{:}\Blocalidx &\Rightarrow& \LOCALGET~x \\ &&|& + \hex{21}~~x{:}\Blocalidx &\Rightarrow& \LOCALSET~x \\ &&|& + \hex{22}~~x{:}\Blocalidx &\Rightarrow& \LOCALTEE~x \\ &&|& + \hex{23}~~x{:}\Bglobalidx &\Rightarrow& \GLOBALGET~x \\ &&|& + \hex{24}~~x{:}\Bglobalidx &\Rightarrow& \GLOBALSET~x \\ + \end{array} + + +.. index:: table instruction, table index + pair: binary format; instruction +.. _binary-instr-table: + +Table Instructions +~~~~~~~~~~~~~~~~~~ + +:ref:`Table instructions ` are represented by either single byte or two byte codes. + +.. _binary-table.get: +.. _binary-table.set: +.. _binary-table.size: +.. _binary-table.grow: +.. _binary-table.fill: + +.. math:: + \begin{array}{llclll} + \production{instruction} & \Binstr &::=& \dots \\ &&|& + \hex{25}~~x{:}\Btableidx &\Rightarrow& \TABLEGET~x \\ &&|& + \hex{26}~~x{:}\Btableidx &\Rightarrow& \TABLESET~x \\ &&|& + \hex{FC}~\hex{0F}~~x{:}\Btableidx &\Rightarrow& \TABLEGROW~x \\ &&|& + \hex{FC}~\hex{10}~~x{:}\Btableidx &\Rightarrow& \TABLESIZE~x \\ &&|& + \hex{FC}~\hex{11}~~x{:}\Btableidx &\Rightarrow& \TABLEFILL~x \\ + \end{array} + + +.. index:: memory instruction, memory index + pair: binary format; instruction +.. _binary-instr-memory: + +Memory Instructions +~~~~~~~~~~~~~~~~~~~ + +Each variant of :ref:`memory instruction ` is encoded with a different byte code. Loads and stores are followed by the encoding of their |memarg| immediate. + +.. _binary-memarg: +.. _binary-load: +.. _binary-loadn: +.. _binary-store: +.. _binary-storen: +.. _binary-memory.size: +.. _binary-memory.grow: + +.. math:: + \begin{array}{llclll} + \production{memory argument} & \Bmemarg &::=& + a{:}\Bu32~~o{:}\Bu32 &\Rightarrow& \{ \ALIGN~a,~\OFFSET~o \} \\ + \production{instruction} & \Binstr &::=& \dots \\ &&|& + \hex{28}~~m{:}\Bmemarg &\Rightarrow& \I32.\LOAD~m \\ &&|& + \hex{29}~~m{:}\Bmemarg &\Rightarrow& \I64.\LOAD~m \\ &&|& + \hex{2A}~~m{:}\Bmemarg &\Rightarrow& \F32.\LOAD~m \\ &&|& + \hex{2B}~~m{:}\Bmemarg &\Rightarrow& \F64.\LOAD~m \\ &&|& + \hex{2C}~~m{:}\Bmemarg &\Rightarrow& \I32.\LOAD\K{8\_s}~m \\ &&|& + \hex{2D}~~m{:}\Bmemarg &\Rightarrow& \I32.\LOAD\K{8\_u}~m \\ &&|& + \hex{2E}~~m{:}\Bmemarg &\Rightarrow& \I32.\LOAD\K{16\_s}~m \\ &&|& + \hex{2F}~~m{:}\Bmemarg &\Rightarrow& \I32.\LOAD\K{16\_u}~m \\ &&|& + \hex{30}~~m{:}\Bmemarg &\Rightarrow& \I64.\LOAD\K{8\_s}~m \\ &&|& + \hex{31}~~m{:}\Bmemarg &\Rightarrow& \I64.\LOAD\K{8\_u}~m \\ &&|& + \hex{32}~~m{:}\Bmemarg &\Rightarrow& \I64.\LOAD\K{16\_s}~m \\ &&|& + \hex{33}~~m{:}\Bmemarg &\Rightarrow& \I64.\LOAD\K{16\_u}~m \\ &&|& + \hex{34}~~m{:}\Bmemarg &\Rightarrow& \I64.\LOAD\K{32\_s}~m \\ &&|& + \hex{35}~~m{:}\Bmemarg &\Rightarrow& \I64.\LOAD\K{32\_u}~m \\ &&|& + \hex{36}~~m{:}\Bmemarg &\Rightarrow& \I32.\STORE~m \\ &&|& + \hex{37}~~m{:}\Bmemarg &\Rightarrow& \I64.\STORE~m \\ &&|& + \hex{38}~~m{:}\Bmemarg &\Rightarrow& \F32.\STORE~m \\ &&|& + \hex{39}~~m{:}\Bmemarg &\Rightarrow& \F64.\STORE~m \\ &&|& + \hex{3A}~~m{:}\Bmemarg &\Rightarrow& \I32.\STORE\K{8}~m \\ &&|& + \hex{3B}~~m{:}\Bmemarg &\Rightarrow& \I32.\STORE\K{16}~m \\ &&|& + \hex{3C}~~m{:}\Bmemarg &\Rightarrow& \I64.\STORE\K{8}~m \\ &&|& + \hex{3D}~~m{:}\Bmemarg &\Rightarrow& \I64.\STORE\K{16}~m \\ &&|& + \hex{3E}~~m{:}\Bmemarg &\Rightarrow& \I64.\STORE\K{32}~m \\ &&|& + \hex{3F}~~\hex{00} &\Rightarrow& \MEMORYSIZE \\ &&|& + \hex{40}~~\hex{00} &\Rightarrow& \MEMORYGROW \\ + \end{array} + +.. note:: + In future versions of WebAssembly, the additional zero bytes occurring in the encoding of the |MEMORYSIZE| and |MEMORYGROW| instructions may be used to index additional memories. + + +.. index:: numeric instruction + pair: binary format; instruction +.. _binary-instr-numeric: + +Numeric Instructions +~~~~~~~~~~~~~~~~~~~~ + +All variants of :ref:`numeric instructions ` are represented by separate byte codes. + +The |CONST| instructions are followed by the respective literal. + +.. _binary-const: + +.. math:: + \begin{array}{llclll} + \production{instruction} & \Binstr &::=& \dots \\&&|& + \hex{41}~~n{:}\Bi32 &\Rightarrow& \I32.\CONST~n \\ &&|& + \hex{42}~~n{:}\Bi64 &\Rightarrow& \I64.\CONST~n \\ &&|& + \hex{43}~~z{:}\Bf32 &\Rightarrow& \F32.\CONST~z \\ &&|& + \hex{44}~~z{:}\Bf64 &\Rightarrow& \F64.\CONST~z \\ + \end{array} + +All other numeric instructions are plain opcodes without any immediates. + +.. _binary-testop: +.. _binary-relop: + +.. math:: + \begin{array}{llclll} + \production{instruction} & \Binstr &::=& \dots && \phantom{thisshouldbeenough} \\&&|& + \hex{45} &\Rightarrow& \I32.\EQZ \\ &&|& + \hex{46} &\Rightarrow& \I32.\EQ \\ &&|& + \hex{47} &\Rightarrow& \I32.\NE \\ &&|& + \hex{48} &\Rightarrow& \I32.\LT\K{\_s} \\ &&|& + \hex{49} &\Rightarrow& \I32.\LT\K{\_u} \\ &&|& + \hex{4A} &\Rightarrow& \I32.\GT\K{\_s} \\ &&|& + \hex{4B} &\Rightarrow& \I32.\GT\K{\_u} \\ &&|& + \hex{4C} &\Rightarrow& \I32.\LE\K{\_s} \\ &&|& + \hex{4D} &\Rightarrow& \I32.\LE\K{\_u} \\ &&|& + \hex{4E} &\Rightarrow& \I32.\GE\K{\_s} \\ &&|& + \hex{4F} &\Rightarrow& \I32.\GE\K{\_u} \\ + \end{array} + +.. math:: + \begin{array}{llclll} + \phantom{\production{instruction}} & \phantom{\Binstr} &\phantom{::=}& \phantom{\dots} && \phantom{thisshouldbeenough} \\[-2ex] &&|& + \hex{50} &\Rightarrow& \I64.\EQZ \\ &&|& + \hex{51} &\Rightarrow& \I64.\EQ \\ &&|& + \hex{52} &\Rightarrow& \I64.\NE \\ &&|& + \hex{53} &\Rightarrow& \I64.\LT\K{\_s} \\ &&|& + \hex{54} &\Rightarrow& \I64.\LT\K{\_u} \\ &&|& + \hex{55} &\Rightarrow& \I64.\GT\K{\_s} \\ &&|& + \hex{56} &\Rightarrow& \I64.\GT\K{\_u} \\ &&|& + \hex{57} &\Rightarrow& \I64.\LE\K{\_s} \\ &&|& + \hex{58} &\Rightarrow& \I64.\LE\K{\_u} \\ &&|& + \hex{59} &\Rightarrow& \I64.\GE\K{\_s} \\ &&|& + \hex{5A} &\Rightarrow& \I64.\GE\K{\_u} \\ + \end{array} + +.. math:: + \begin{array}{llclll} + \phantom{\production{instruction}} & \phantom{\Binstr} &\phantom{::=}& \phantom{\dots} && \phantom{thisshouldbeenough} \\[-2ex] &&|& + \hex{5B} &\Rightarrow& \F32.\EQ \\ &&|& + \hex{5C} &\Rightarrow& \F32.\NE \\ &&|& + \hex{5D} &\Rightarrow& \F32.\LT \\ &&|& + \hex{5E} &\Rightarrow& \F32.\GT \\ &&|& + \hex{5F} &\Rightarrow& \F32.\LE \\ &&|& + \hex{60} &\Rightarrow& \F32.\GE \\ + \end{array} + +.. math:: + \begin{array}{llclll} + \phantom{\production{instruction}} & \phantom{\Binstr} &\phantom{::=}& \phantom{\dots} && \phantom{thisshouldbeenough} \\[-2ex] &&|& + \hex{61} &\Rightarrow& \F64.\EQ \\ &&|& + \hex{62} &\Rightarrow& \F64.\NE \\ &&|& + \hex{63} &\Rightarrow& \F64.\LT \\ &&|& + \hex{64} &\Rightarrow& \F64.\GT \\ &&|& + \hex{65} &\Rightarrow& \F64.\LE \\ &&|& + \hex{66} &\Rightarrow& \F64.\GE \\ + \end{array} + +.. _binary-unop: +.. _binary-binop: + +.. math:: + \begin{array}{llclll} + \phantom{\production{instruction}} & \phantom{\Binstr} &\phantom{::=}& \phantom{\dots} && \phantom{thisshouldbeenough} \\[-2ex] &&|& + \hex{67} &\Rightarrow& \I32.\CLZ \\ &&|& + \hex{68} &\Rightarrow& \I32.\CTZ \\ &&|& + \hex{69} &\Rightarrow& \I32.\POPCNT \\ &&|& + \hex{6A} &\Rightarrow& \I32.\ADD \\ &&|& + \hex{6B} &\Rightarrow& \I32.\SUB \\ &&|& + \hex{6C} &\Rightarrow& \I32.\MUL \\ &&|& + \hex{6D} &\Rightarrow& \I32.\DIV\K{\_s} \\ &&|& + \hex{6E} &\Rightarrow& \I32.\DIV\K{\_u} \\ &&|& + \hex{6F} &\Rightarrow& \I32.\REM\K{\_s} \\ &&|& + \hex{70} &\Rightarrow& \I32.\REM\K{\_u} \\ &&|& + \hex{71} &\Rightarrow& \I32.\AND \\ &&|& + \hex{72} &\Rightarrow& \I32.\OR \\ &&|& + \hex{73} &\Rightarrow& \I32.\XOR \\ &&|& + \hex{74} &\Rightarrow& \I32.\SHL \\ &&|& + \hex{75} &\Rightarrow& \I32.\SHR\K{\_s} \\ &&|& + \hex{76} &\Rightarrow& \I32.\SHR\K{\_u} \\ &&|& + \hex{77} &\Rightarrow& \I32.\ROTL \\ &&|& + \hex{78} &\Rightarrow& \I32.\ROTR \\ + \end{array} + +.. math:: + \begin{array}{llclll} + \phantom{\production{instruction}} & \phantom{\Binstr} &\phantom{::=}& \phantom{\dots} && \phantom{thisshouldbeenough} \\[-2ex] &&|& + \hex{79} &\Rightarrow& \I64.\CLZ \\ &&|& + \hex{7A} &\Rightarrow& \I64.\CTZ \\ &&|& + \hex{7B} &\Rightarrow& \I64.\POPCNT \\ &&|& + \hex{7C} &\Rightarrow& \I64.\ADD \\ &&|& + \hex{7D} &\Rightarrow& \I64.\SUB \\ &&|& + \hex{7E} &\Rightarrow& \I64.\MUL \\ &&|& + \hex{7F} &\Rightarrow& \I64.\DIV\K{\_s} \\ &&|& + \hex{80} &\Rightarrow& \I64.\DIV\K{\_u} \\ &&|& + \hex{81} &\Rightarrow& \I64.\REM\K{\_s} \\ &&|& + \hex{82} &\Rightarrow& \I64.\REM\K{\_u} \\ &&|& + \hex{83} &\Rightarrow& \I64.\AND \\ &&|& + \hex{84} &\Rightarrow& \I64.\OR \\ &&|& + \hex{85} &\Rightarrow& \I64.\XOR \\ &&|& + \hex{86} &\Rightarrow& \I64.\SHL \\ &&|& + \hex{87} &\Rightarrow& \I64.\SHR\K{\_s} \\ &&|& + \hex{88} &\Rightarrow& \I64.\SHR\K{\_u} \\ &&|& + \hex{89} &\Rightarrow& \I64.\ROTL \\ &&|& + \hex{8A} &\Rightarrow& \I64.\ROTR \\ + \end{array} + +.. math:: + \begin{array}{llclll} + \phantom{\production{instruction}} & \phantom{\Binstr} &\phantom{::=}& \phantom{\dots} && \phantom{thisshouldbeenough} \\[-2ex] &&|& + \hex{8B} &\Rightarrow& \F32.\ABS \\ &&|& + \hex{8C} &\Rightarrow& \F32.\NEG \\ &&|& + \hex{8D} &\Rightarrow& \F32.\CEIL \\ &&|& + \hex{8E} &\Rightarrow& \F32.\FLOOR \\ &&|& + \hex{8F} &\Rightarrow& \F32.\TRUNC \\ &&|& + \hex{90} &\Rightarrow& \F32.\NEAREST \\ &&|& + \hex{91} &\Rightarrow& \F32.\SQRT \\ &&|& + \hex{92} &\Rightarrow& \F32.\ADD \\ &&|& + \hex{93} &\Rightarrow& \F32.\SUB \\ &&|& + \hex{94} &\Rightarrow& \F32.\MUL \\ &&|& + \hex{95} &\Rightarrow& \F32.\DIV \\ &&|& + \hex{96} &\Rightarrow& \F32.\FMIN \\ &&|& + \hex{97} &\Rightarrow& \F32.\FMAX \\ &&|& + \hex{98} &\Rightarrow& \F32.\COPYSIGN \\ + \end{array} + +.. math:: + \begin{array}{llclll} + \phantom{\production{instruction}} & \phantom{\Binstr} &\phantom{::=}& \phantom{\dots} && \phantom{thisshouldbeenough} \\[-2ex] &&|& + \hex{99} &\Rightarrow& \F64.\ABS \\ &&|& + \hex{9A} &\Rightarrow& \F64.\NEG \\ &&|& + \hex{9B} &\Rightarrow& \F64.\CEIL \\ &&|& + \hex{9C} &\Rightarrow& \F64.\FLOOR \\ &&|& + \hex{9D} &\Rightarrow& \F64.\TRUNC \\ &&|& + \hex{9E} &\Rightarrow& \F64.\NEAREST \\ &&|& + \hex{9F} &\Rightarrow& \F64.\SQRT \\ &&|& + \hex{A0} &\Rightarrow& \F64.\ADD \\ &&|& + \hex{A1} &\Rightarrow& \F64.\SUB \\ &&|& + \hex{A2} &\Rightarrow& \F64.\MUL \\ &&|& + \hex{A3} &\Rightarrow& \F64.\DIV \\ &&|& + \hex{A4} &\Rightarrow& \F64.\FMIN \\ &&|& + \hex{A5} &\Rightarrow& \F64.\FMAX \\ &&|& + \hex{A6} &\Rightarrow& \F64.\COPYSIGN \\ + \end{array} + +.. _binary-cvtop: + +.. math:: + \begin{array}{llclll} + \phantom{\production{instruction}} & \phantom{\Binstr} &\phantom{::=}& \phantom{\dots} && \phantom{thisshouldbeenough} \\[-2ex] &&|& + \hex{A7} &\Rightarrow& \I32.\WRAP\K{\_}\I64 \\ &&|& + \hex{A8} &\Rightarrow& \I32.\TRUNC\K{\_}\F32\K{\_s} \\ &&|& + \hex{A9} &\Rightarrow& \I32.\TRUNC\K{\_}\F32\K{\_u} \\ &&|& + \hex{AA} &\Rightarrow& \I32.\TRUNC\K{\_}\F64\K{\_s} \\ &&|& + \hex{AB} &\Rightarrow& \I32.\TRUNC\K{\_}\F64\K{\_u} \\ &&|& + \hex{AC} &\Rightarrow& \I64.\EXTEND\K{\_}\I32\K{\_s} \\ &&|& + \hex{AD} &\Rightarrow& \I64.\EXTEND\K{\_}\I32\K{\_u} \\ &&|& + \hex{AE} &\Rightarrow& \I64.\TRUNC\K{\_}\F32\K{\_s} \\ &&|& + \hex{AF} &\Rightarrow& \I64.\TRUNC\K{\_}\F32\K{\_u} \\ &&|& + \hex{B0} &\Rightarrow& \I64.\TRUNC\K{\_}\F64\K{\_s} \\ &&|& + \hex{B1} &\Rightarrow& \I64.\TRUNC\K{\_}\F64\K{\_u} \\ &&|& + \hex{B2} &\Rightarrow& \F32.\CONVERT\K{\_}\I32\K{\_s} \\ &&|& + \hex{B3} &\Rightarrow& \F32.\CONVERT\K{\_}\I32\K{\_u} \\ &&|& + \hex{B4} &\Rightarrow& \F32.\CONVERT\K{\_}\I64\K{\_s} \\ &&|& + \hex{B5} &\Rightarrow& \F32.\CONVERT\K{\_}\I64\K{\_u} \\ &&|& + \hex{B6} &\Rightarrow& \F32.\DEMOTE\K{\_}\F64 \\ &&|& + \hex{B7} &\Rightarrow& \F64.\CONVERT\K{\_}\I32\K{\_s} \\ &&|& + \hex{B8} &\Rightarrow& \F64.\CONVERT\K{\_}\I32\K{\_u} \\ &&|& + \hex{B9} &\Rightarrow& \F64.\CONVERT\K{\_}\I64\K{\_s} \\ &&|& + \hex{BA} &\Rightarrow& \F64.\CONVERT\K{\_}\I64\K{\_u} \\ &&|& + \hex{BB} &\Rightarrow& \F64.\PROMOTE\K{\_}\F32 \\ &&|& + \hex{BC} &\Rightarrow& \I32.\REINTERPRET\K{\_}\F32 \\ &&|& + \hex{BD} &\Rightarrow& \I64.\REINTERPRET\K{\_}\F64 \\ &&|& + \hex{BE} &\Rightarrow& \F32.\REINTERPRET\K{\_}\I32 \\ &&|& + \hex{BF} &\Rightarrow& \F64.\REINTERPRET\K{\_}\I64 \\ + \end{array} + + +.. index:: expression + pair: binary format; expression + single: expression; constant +.. _binary-expr: + +Expressions +~~~~~~~~~~~ + +:ref:`Expressions ` are encoded by their instruction sequence terminated with an explicit :math:`\hex{0B}` opcode for |END|. + +.. math:: + \begin{array}{llclll} + \production{expression} & \Bexpr &::=& + (\X{in}{:}\Binstr)^\ast~~\hex{0B} &\Rightarrow& \X{in}^\ast~\END \\ + \end{array} diff --git a/document/core/binary/modules.rst b/document/core/binary/modules.rst new file mode 100644 index 0000000000..f7c36c9f21 --- /dev/null +++ b/document/core/binary/modules.rst @@ -0,0 +1,486 @@ +Modules +------- + +The binary encoding of modules is organized into *sections*. +Most sections correspond to one component of a :ref:`module ` record, +except that :ref:`function definitions ` are split into two sections, separating their type declarations in the :ref:`function section ` from their bodies in the :ref:`code section `. + +.. note:: + This separation enables *parallel* and *streaming* compilation of the functions in a module. + + +.. index:: index, type index, function index, table index, memory index, global index, local index, label index + pair: binary format; type index + pair: binary format; function index + pair: binary format; table index + pair: binary format; memory index + pair: binary format; global index + pair: binary format; local index + pair: binary format; label index +.. _binary-typeidx: +.. _binary-funcidx: +.. _binary-tableidx: +.. _binary-memidx: +.. _binary-globalidx: +.. _binary-localidx: +.. _binary-labelidx: +.. _binary-index: + +Indices +~~~~~~~ + +All :ref:`indices ` are encoded with their respective value. + +.. math:: + \begin{array}{llclll} + \production{type index} & \Btypeidx &::=& x{:}\Bu32 &\Rightarrow& x \\ + \production{function index} & \Bfuncidx &::=& x{:}\Bu32 &\Rightarrow& x \\ + \production{table index} & \Btableidx &::=& x{:}\Bu32 &\Rightarrow& x \\ + \production{memory index} & \Bmemidx &::=& x{:}\Bu32 &\Rightarrow& x \\ + \production{global index} & \Bglobalidx &::=& x{:}\Bu32 &\Rightarrow& x \\ + \production{local index} & \Blocalidx &::=& x{:}\Bu32 &\Rightarrow& x \\ + \production{label index} & \Blabelidx &::=& l{:}\Bu32 &\Rightarrow& l \\ + \end{array} + + +.. index:: ! section + pair: binary format; section +.. _binary-section: + +Sections +~~~~~~~~ + +Each section consists of + +* a one-byte section *id*, +* the |U32| *size* of the contents, in bytes, +* the actual *contents*, whose structure is depended on the section id. + +Every section is optional; an omitted section is equivalent to the section being present with empty contents. + +The following parameterized grammar rule defines the generic structure of a section with id :math:`N` and contents described by the grammar :math:`\B{B}`. + +.. math:: + \begin{array}{llclll@{\qquad}l} + \production{section} & \Bsection_N(\B{B}) &::=& + N{:}\Bbyte~~\X{size}{:}\Bu32~~\X{cont}{:}\B{B} + &\Rightarrow& \X{cont} & (\iff \X{size} = ||\B{B}||) \\ &&|& + \epsilon &\Rightarrow& \epsilon + \end{array} + +For most sections, the contents :math:`\B{B}` encodes a :ref:`vector `. +In these cases, the empty result :math:`\epsilon` is interpreted as the empty vector. + +.. note:: + Other than for unknown :ref:`custom sections `, + the :math:`\X{size}` is not required for decoding, but can be used to skip sections when navigating through a binary. + The module is malformed if the size does not match the length of the binary contents :math:`\B{B}`. + +The following section ids are used: + +== ======================================== +Id Section +== ======================================== + 0 :ref:`custom section ` + 1 :ref:`type section ` + 2 :ref:`import section ` + 3 :ref:`function section ` + 4 :ref:`table section ` + 5 :ref:`memory section ` + 6 :ref:`global section ` + 7 :ref:`export section ` + 8 :ref:`start section ` + 9 :ref:`element section ` +10 :ref:`code section ` +11 :ref:`data section ` +== ======================================== + + +.. index:: ! custom section + pair: binary format; custom section + single: section; custom +.. _binary-customsec: + +Custom Section +~~~~~~~~~~~~~~ + +*Custom sections* have the id 0. +They are intended to be used for debugging information or third-party extensions, and are ignored by the WebAssembly semantics. +Their contents consist of a :ref:`name ` further identifying the custom section, followed by an uninterpreted sequence of bytes for custom use. + +.. math:: + \begin{array}{llclll} + \production{custom section} & \Bcustomsec &::=& + \Bsection_0(\Bcustom) \\ + \production{custom data} & \Bcustom &::=& + \Bname~~\Bbyte^\ast \\ + \end{array} + +.. note:: + If an implementation interprets the contents of a custom section, then errors in that contents, or the placement of the section, must not invalidate the module. + + +.. index:: ! type section, type definition + pair: binary format; type section + pair: section; type +.. _binary-typedef: +.. _binary-typesec: + +Type Section +~~~~~~~~~~~~ + +The *type section* has the id 1. +It decodes into a vector of :ref:`function types ` that represent the |MTYPES| component of a :ref:`module `. + +.. math:: + \begin{array}{llclll} + \production{type section} & \Btypesec &::=& + \X{ft}^\ast{:\,}\Bsection_1(\Bvec(\Bfunctype)) &\Rightarrow& \X{ft}^\ast \\ + \end{array} + + +.. index:: ! import section, import, name, function type, table type, memory type, global type + pair: binary format; import + pair: section; import +.. _binary-import: +.. _binary-importdesc: +.. _binary-importsec: + +Import Section +~~~~~~~~~~~~~~ + +The *import section* has the id 2. +It decodes into a vector of :ref:`imports ` that represent the |MIMPORTS| component of a :ref:`module `. + +.. math:: + \begin{array}{llclll} + \production{import section} & \Bimportsec &::=& + \X{im}^\ast{:}\Bsection_2(\Bvec(\Bimport)) &\Rightarrow& \X{im}^\ast \\ + \production{import} & \Bimport &::=& + \X{mod}{:}\Bname~~\X{nm}{:}\Bname~~d{:}\Bimportdesc + &\Rightarrow& \{ \IMODULE~\X{mod}, \INAME~\X{nm}, \IDESC~d \} \\ + \production{import description} & \Bimportdesc &::=& + \hex{00}~~x{:}\Btypeidx &\Rightarrow& \IDFUNC~x \\ &&|& + \hex{01}~~\X{tt}{:}\Btabletype &\Rightarrow& \IDTABLE~\X{tt} \\ &&|& + \hex{02}~~\X{mt}{:}\Bmemtype &\Rightarrow& \IDMEM~\X{mt} \\ &&|& + \hex{03}~~\X{gt}{:}\Bglobaltype &\Rightarrow& \IDGLOBAL~\X{gt} \\ + \end{array} + + +.. index:: ! function section, function, type index, function type + pair: binary format; function + pair: section; function +.. _binary-funcsec: + +Function Section +~~~~~~~~~~~~~~~~ + +The *function section* has the id 3. +It decodes into a vector of :ref:`type indices ` that represent the |FTYPE| fields of the :ref:`functions ` in the |MFUNCS| component of a :ref:`module `. +The |FLOCALS| and |FBODY| fields of the respective functions are encoded separately in the :ref:`code section `. + +.. math:: + \begin{array}{llclll} + \production{function section} & \Bfuncsec &::=& + x^\ast{:}\Bsection_3(\Bvec(\Btypeidx)) &\Rightarrow& x^\ast \\ + \end{array} + + +.. index:: ! table section, table, table type + pair: binary format; table + pair: section; table +.. _binary-table: +.. _binary-tablesec: + +Table Section +~~~~~~~~~~~~~ + +The *table section* has the id 4. +It decodes into a vector of :ref:`tables ` that represent the |MTABLES| component of a :ref:`module `. + +.. math:: + \begin{array}{llclll} + \production{table section} & \Btablesec &::=& + \X{tab}^\ast{:}\Bsection_4(\Bvec(\Btable)) &\Rightarrow& \X{tab}^\ast \\ + \production{table} & \Btable &::=& + \X{tt}{:}\Btabletype &\Rightarrow& \{ \TTYPE~\X{tt} \} \\ + \end{array} + + +.. index:: ! memory section, memory, memory type + pair: binary format; memory + pair: section; memory +.. _binary-mem: +.. _binary-memsec: + +Memory Section +~~~~~~~~~~~~~~ + +The *memory section* has the id 5. +It decodes into a vector of :ref:`memories ` that represent the |MMEMS| component of a :ref:`module `. + +.. math:: + \begin{array}{llclll} + \production{memory section} & \Bmemsec &::=& + \X{mem}^\ast{:}\Bsection_5(\Bvec(\Bmem)) &\Rightarrow& \X{mem}^\ast \\ + \production{memory} & \Bmem &::=& + \X{mt}{:}\Bmemtype &\Rightarrow& \{ \MTYPE~\X{mt} \} \\ + \end{array} + + +.. index:: ! global section, global, global type, expression + pair: binary format; global + pair: section; global +.. _binary-global: +.. _binary-globalsec: + +Global Section +~~~~~~~~~~~~~~ + +The *global section* has the id 6. +It decodes into a vector of :ref:`globals ` that represent the |MGLOBALS| component of a :ref:`module `. + +.. math:: + \begin{array}{llclll} + \production{global section} & \Bglobalsec &::=& + \X{glob}^\ast{:}\Bsection_6(\Bvec(\Bglobal)) &\Rightarrow& \X{glob}^\ast \\ + \production{global} & \Bglobal &::=& + \X{gt}{:}\Bglobaltype~~e{:}\Bexpr + &\Rightarrow& \{ \GTYPE~\X{gt}, \GINIT~e \} \\ + \end{array} + + +.. index:: ! export section, export, name, index, function index, table index, memory index, global index + pair: binary format; export + pair: section; export +.. _binary-export: +.. _binary-exportdesc: +.. _binary-exportsec: + +Export Section +~~~~~~~~~~~~~~ + +The *export section* has the id 7. +It decodes into a vector of :ref:`exports ` that represent the |MEXPORTS| component of a :ref:`module `. + +.. math:: + \begin{array}{llclll} + \production{export section} & \Bexportsec &::=& + \X{ex}^\ast{:}\Bsection_7(\Bvec(\Bexport)) &\Rightarrow& \X{ex}^\ast \\ + \production{export} & \Bexport &::=& + \X{nm}{:}\Bname~~d{:}\Bexportdesc + &\Rightarrow& \{ \ENAME~\X{nm}, \EDESC~d \} \\ + \production{export description} & \Bexportdesc &::=& + \hex{00}~~x{:}\Bfuncidx &\Rightarrow& \EDFUNC~x \\ &&|& + \hex{01}~~x{:}\Btableidx &\Rightarrow& \EDTABLE~x \\ &&|& + \hex{02}~~x{:}\Bmemidx &\Rightarrow& \EDMEM~x \\ &&|& + \hex{03}~~x{:}\Bglobalidx &\Rightarrow& \EDGLOBAL~x \\ + \end{array} + + +.. index:: ! start section, start function, function index + pair: binary format; start function + single: section; start + single: start function; section +.. _binary-start: +.. _binary-startsec: + +Start Section +~~~~~~~~~~~~~ + +The *start section* has the id 8. +It decodes into an optional :ref:`start function ` that represents the |MSTART| component of a :ref:`module `. + +.. math:: + \begin{array}{llclll} + \production{start section} & \Bstartsec &::=& + \X{st}^?{:}\Bsection_8(\Bstart) &\Rightarrow& \X{st}^? \\ + \production{start function} & \Bstart &::=& + x{:}\Bfuncidx &\Rightarrow& \{ \SFUNC~x \} \\ + \end{array} + + +.. index:: ! element section, element, table index, expression, function index + pair: binary format; element + pair: section; element + single: table; element + single: element; segment +.. _binary-elem: +.. _binary-elemsec: + +Element Section +~~~~~~~~~~~~~~~ + +The *element section* has the id 9. +It decodes into a vector of :ref:`element segments ` that represent the |MELEM| component of a :ref:`module `. + +.. math:: + \begin{array}{llclll} + \production{element section} & \Belemsec &::=& + \X{seg}^\ast{:}\Bsection_9(\Bvec(\Belem)) &\Rightarrow& \X{seg} \\ + \production{element segment} & \Belem &::=& + \hex{00}~~e{:}\Bexpr~~y^\ast{:}\Bvec(\Bfuncidx) + &\Rightarrow& \{ \ETABLE~0, \EOFFSET~e, \EINIT~y^\ast \} \\ &&|& + \hex{02}~~x{:}\Btableidx~~e{:}\Bexpr~~\hex{00}~~y^\ast{:}\Bvec(\Bfuncidx) + &\Rightarrow& \{ \ETABLE~x, \EOFFSET~e, \EINIT~y^\ast \} \\ + \end{array} + + +.. index:: ! code section, function, local, type index, function type + pair: binary format; function + pair: binary format; local + pair: section; code +.. _binary-code: +.. _binary-func: +.. _binary-local: +.. _binary-codesec: + +Code Section +~~~~~~~~~~~~ + +The *code section* has the id 10. +It decodes into a vector of *code* entries that are pairs of :ref:`value type ` vectors and :ref:`expressions `. +They represent the |FLOCALS| and |FBODY| field of the :ref:`functions ` in the |MFUNCS| component of a :ref:`module `. +The |FTYPE| fields of the respective functions are encoded separately in the :ref:`function section `. + +The encoding of each code entry consists of + +* the |U32| *size* of the function code in bytes, +* the actual *function code*, which in turn consists of + + * the declaration of *locals*, + * the function *body* as an :ref:`expression `. + +Local declarations are compressed into a vector whose entries consist of + +* a |U32| *count*, +* a :ref:`value type `, + +denoting *count* locals of the same value type. + +.. math:: + \begin{array}{llclll@{\qquad}l} + \production{code section} & \Bcodesec &::=& + \X{code}^\ast{:}\Bsection_{10}(\Bvec(\Bcode)) + &\Rightarrow& \X{code}^\ast \\ + \production{code} & \Bcode &::=& + \X{size}{:}\Bu32~~\X{code}{:}\Bfunc + &\Rightarrow& \X{code} & (\iff \X{size} = ||\Bfunc||) \\ + \production{function} & \Bfunc &::=& + (t^\ast)^\ast{:}\Bvec(\Blocals)~~e{:}\Bexpr + &\Rightarrow& \concat((t^\ast)^\ast), e^\ast + & (\iff |\concat((t^\ast)^\ast)| < 2^{32}) \\ + \production{locals} & \Blocals &::=& + n{:}\Bu32~~t{:}\Bvaltype &\Rightarrow& t^n \\ + \end{array} + +Here, :math:`\X{code}` ranges over pairs :math:`(\valtype^\ast, \expr)`. +The meta function :math:`\concat((t^\ast)^\ast)` concatenates all sequences :math:`t_i^\ast` in :math:`(t^\ast)^\ast`. +Any code for which the length of the resulting sequence is out of bounds of the maximum size of a :ref:`vector ` is malformed. + +.. note:: + Like with :ref:`sections `, the code :math:`\X{size}` is not needed for decoding, but can be used to skip functions when navigating through a binary. + The module is malformed if a size does not match the length of the respective function code. + + +.. index:: ! data section, data, memory, memory index, expression, byte + pair: binary format; data + pair: section; data + single: memory; data + single: data; segment +.. _binary-data: +.. _binary-datasec: + +Data Section +~~~~~~~~~~~~ + +The *data section* has the id 11. +It decodes into a vector of :ref:`data segments ` that represent the |MDATA| component of a :ref:`module `. + +.. math:: + \begin{array}{llclll} + \production{data section} & \Bdatasec &::=& + \X{seg}^\ast{:}\Bsection_{11}(\Bvec(\Bdata)) &\Rightarrow& \X{seg} \\ + \production{data segment} & \Bdata &::=& + x{:}\Bmemidx~~e{:}\Bexpr~~b^\ast{:}\Bvec(\Bbyte) + &\Rightarrow& \{ \DMEM~x, \DOFFSET~e, \DINIT~b^\ast \} \\ + \end{array} + + +.. index:: module, section, type definition, function type, function, table, memory, global, element, data, start function, import, export, context, version + pair: binary format; module +.. _binary-magic: +.. _binary-version: +.. _binary-module: + +Modules +~~~~~~~ + +The encoding of a :ref:`module ` starts with a preamble containing a 4-byte magic number (the string :math:`\text{\backslash0asm}`) and a version field. +The current version of the WebAssembly binary format is 1. + +The preamble is followed by a sequence of :ref:`sections `. +:ref:`Custom sections ` may be inserted at any place in this sequence, +while other sections must occur at most once and in the prescribed order. +All sections can be empty. + +The lengths of vectors produced by the (possibly empty) :ref:`function ` and :ref:`code ` section must match up. + +.. math:: + \begin{array}{llcllll} + \production{magic} & \Bmagic &::=& + \hex{00}~\hex{61}~\hex{73}~\hex{6D} \\ + \production{version} & \Bversion &::=& + \hex{01}~\hex{00}~\hex{00}~\hex{00} \\ + \production{module} & \Bmodule &::=& + \Bmagic \\ &&& + \Bversion \\ &&& + \Bcustomsec^\ast \\ &&& + \functype^\ast{:\,}\Btypesec \\ &&& + \Bcustomsec^\ast \\ &&& + \import^\ast{:\,}\Bimportsec \\ &&& + \Bcustomsec^\ast \\ &&& + \typeidx^n{:\,}\Bfuncsec \\ &&& + \Bcustomsec^\ast \\ &&& + \table^\ast{:\,}\Btablesec \\ &&& + \Bcustomsec^\ast \\ &&& + \mem^\ast{:\,}\Bmemsec \\ &&& + \Bcustomsec^\ast \\ &&& + \global^\ast{:\,}\Bglobalsec \\ &&& + \Bcustomsec^\ast \\ &&& + \export^\ast{:\,}\Bexportsec \\ &&& + \Bcustomsec^\ast \\ &&& + \start^?{:\,}\Bstartsec \\ &&& + \Bcustomsec^\ast \\ &&& + \elem^\ast{:\,}\Belemsec \\ &&& + \Bcustomsec^\ast \\ &&& + \X{code}^n{:\,}\Bcodesec \\ &&& + \Bcustomsec^\ast \\ &&& + \data^\ast{:\,}\Bdatasec \\ &&& + \Bcustomsec^\ast + \quad\Rightarrow\quad \{~ + \begin{array}[t]{@{}l@{}} + \MTYPES~\functype^\ast, \\ + \MFUNCS~\func^n, \\ + \MTABLES~\table^\ast, \\ + \MMEMS~\mem^\ast, \\ + \MGLOBALS~\global^\ast, \\ + \MELEM~\elem^\ast, \\ + \MDATA~\data^\ast, \\ + \MSTART~\start^?, \\ + \MIMPORTS~\import^\ast, \\ + \MEXPORTS~\export^\ast ~\} \\ + \end{array} \\ + \end{array} + +where for each :math:`t_i^\ast, e_i` in :math:`\X{code}^n`, + +.. math:: + \func^n[i] = \{ \FTYPE~\typeidx^n[i], \FLOCALS~t_i^\ast, \FBODY~e_i \} ) \\ + +.. note:: + The version of the WebAssembly binary format may increase in the future + if backward-incompatible changes have to be made to the format. + However, such changes are expected to occur very infrequently, if ever. + The binary format is intended to be forward-compatible, + such that future extensions can be made without incrementing its version. diff --git a/document/core/binary/types.rst b/document/core/binary/types.rst new file mode 100644 index 0000000000..e7a7f8ed9f --- /dev/null +++ b/document/core/binary/types.rst @@ -0,0 +1,175 @@ +.. index:: type + pair: binary format; type +.. _binary-type: + +Types +----- + +.. note:: + In future versions of WebAssembly, value types may include types denoted by :ref:`type indices `. + Thus, the binary format for types corresponds to the encodings of small negative :math:`\xref{binary/values}{binary-sint}{\sN}` values, so that they can coexist with (positive) type indices in the future. + + +.. index:: number type + pair: binary format; number type +.. _binary-numtype: + +Number Types +~~~~~~~~~~~~ + +:ref:`Number types ` are encoded by a single byte. + +.. math:: + \begin{array}{llclll@{\qquad\qquad}l} + \production{number type} & \Bnumtype &::=& + \hex{7F} &\Rightarrow& \I32 \\ &&|& + \hex{7E} &\Rightarrow& \I64 \\ &&|& + \hex{7D} &\Rightarrow& \F32 \\ &&|& + \hex{7C} &\Rightarrow& \F64 \\ + \end{array} + + +.. index:: reference type + pair: binary format; reference type +.. _binary-reftype: + +Reference Types +~~~~~~~~~~~~~~~ + +:ref:`Reference types ` are also encoded by a single byte. + +.. math:: + \begin{array}{llclll@{\qquad\qquad}l} + \production{reference type} & \Breftype &::=& + \hex{70} &\Rightarrow& \FUNCREF \\ &&|& + \hex{6F} &\Rightarrow& \ANYREF \\ &&|& + \hex{6E} &\Rightarrow& \NULLREF \\ + \end{array} + + +.. index:: value type, number type, reference type + pair: binary format; value type +.. _binary-valtype: + +Value Types +~~~~~~~~~~~ + +:ref:`Value types ` are encoded with their respective encoding as a :ref:`number type ` or :ref:`reference type `. + +.. math:: + \begin{array}{llclll@{\qquad\qquad}l} + \production{value type} & \Bvaltype &::=& + t{:}\Bnumtype &\Rightarrow& t \\ &&|& + t{:}\Breftype &\Rightarrow& t \\ + \end{array} + +.. note:: + The type :math:`\BOT` cannot occur in a module. + + +.. index:: result type, value type + pair: binary format; result type +.. _binary-blocktype: +.. _binary-resulttype: + +Result Types +~~~~~~~~~~~~ + +The only :ref:`result types ` occurring in the binary format are the types of blocks. These are encoded in special compressed form, by either the byte :math:`\hex{40}` indicating the empty type or as a single :ref:`value type `. + +.. math:: + \begin{array}{llclll@{\qquad\qquad}l} + \production{result type} & \Bblocktype &::=& + \hex{40} &\Rightarrow& [] \\ &&|& + t{:}\Bvaltype &\Rightarrow& [t] \\ + \end{array} + +.. note:: + In future versions of WebAssembly, this scheme may be extended to support multiple results or more general block types. + + +.. index:: function type, value type, result type + pair: binary format; function type +.. _binary-functype: + +Function Types +~~~~~~~~~~~~~~ + +:ref:`Function types ` are encoded by the byte :math:`\hex{60}` followed by the respective :ref:`vectors ` of parameter and result types. + +.. math:: + \begin{array}{llclll@{\qquad\qquad}l} + \production{function type} & \Bfunctype &::=& + \hex{60}~~t_1^\ast{:\,}\Bvec(\Bvaltype)~~t_2^\ast{:\,}\Bvec(\Bvaltype) + &\Rightarrow& [t_1^\ast] \to [t_2^\ast] \\ + \end{array} + + +.. index:: limits + pair: binary format; limits +.. _binary-limits: + +Limits +~~~~~~ + +:ref:`Limits ` are encoded with a preceding flag indicating whether a maximum is present. + +.. math:: + \begin{array}{llclll} + \production{limits} & \Blimits &::=& + \hex{00}~~n{:}\Bu32 &\Rightarrow& \{ \LMIN~n, \LMAX~\epsilon \} \\ &&|& + \hex{01}~~n{:}\Bu32~~m{:}\Bu32 &\Rightarrow& \{ \LMIN~n, \LMAX~m \} \\ + \end{array} + + +.. index:: memory type, limits, page size + pair: binary format; memory type +.. _binary-memtype: + +Memory Types +~~~~~~~~~~~~ + +:ref:`Memory types ` are encoded with their :ref:`limits `. + +.. math:: + \begin{array}{llclll@{\qquad\qquad}l} + \production{memory type} & \Bmemtype &::=& + \X{lim}{:}\Blimits &\Rightarrow& \X{lim} \\ + \end{array} + + +.. index:: table type, reference type, limits + pair: binary format; table type +.. _binary-tabletype: + +Table Types +~~~~~~~~~~~ + +:ref:`Table types ` are encoded with their :ref:`limits ` and the encoding of their element :ref:`reference type `. + +.. math:: + \begin{array}{llclll} + \production{table type} & \Btabletype &::=& + \X{et}{:}\Breftype~~\X{lim}{:}\Blimits &\Rightarrow& \X{lim}~\X{et} \\ + \end{array} + + +.. index:: global type, mutability, value type + pair: binary format; global type + pair: binary format; mutability +.. _binary-mut: +.. _binary-globaltype: + +Global Types +~~~~~~~~~~~~ + +:ref:`Global types ` are encoded by their :ref:`value type ` and a flag for their :ref:`mutability `. + +.. math:: + \begin{array}{llclll} + \production{global type} & \Bglobaltype &::=& + t{:}\Bvaltype~~m{:}\Bmut &\Rightarrow& m~t \\ + \production{mutability} & \Bmut &::=& + \hex{00} &\Rightarrow& \MCONST \\ &&|& + \hex{01} &\Rightarrow& \MVAR \\ + \end{array} diff --git a/document/core/binary/values.rst b/document/core/binary/values.rst new file mode 100644 index 0000000000..c626862489 --- /dev/null +++ b/document/core/binary/values.rst @@ -0,0 +1,148 @@ +.. index:: value + pair: binary format; value +.. _binary-value: + +Values +------ + + +.. index:: byte + pair: binary format; byte +.. _binary-byte: + +Bytes +~~~~~ + +:ref:`Bytes ` encode themselves. + +.. math:: + \begin{array}{llcll@{\qquad}l} + \production{byte} & \Bbyte &::=& + \hex{00} &\Rightarrow& \hex{00} \\ &&|&& + \dots \\ &&|& + \hex{FF} &\Rightarrow& \hex{FF} \\ + \end{array} + + +.. index:: integer, unsigned integer, signed integer, uninterpreted integer, LEB128, two's complement + pair: binary format; integer + pair: binary format; unsigned integer + pair: binary format; signed integer + pair: binary format; uninterpreted integer +.. _binary-sint: +.. _binary-uint: +.. _binary-int: + +Integers +~~~~~~~~ + +All :ref:`integers ` are encoded using the |LEB128|_ variable-length integer encoding, in either unsigned or signed variant. + +:ref:`Unsigned integers ` are encoded in |UnsignedLEB128|_ format. +As an additional constraint, the total number of bytes encoding a value of type :math:`\uN` must not exceed :math:`\F{ceil}(N/7)` bytes. + +.. math:: + \begin{array}{llclll@{\qquad}l} + \production{unsigned integer} & \BuN &::=& + n{:}\Bbyte &\Rightarrow& n & (\iff n < 2^7 \wedge n < 2^N) \\ &&|& + n{:}\Bbyte~~m{:}\BuX{(N\B{-7})} &\Rightarrow& + 2^7\cdot m + (n-2^7) & (\iff n \geq 2^7 \wedge N > 7) \\ + \end{array} + +:ref:`Signed integers ` are encoded in |SignedLEB128|_ format, which uses a two's complement representation. +As an additional constraint, the total number of bytes encoding a value of type :math:`\sN` must not exceed :math:`\F{ceil}(N/7)` bytes. + +.. math:: + \begin{array}{llclll@{\qquad}l} + \production{signed integer} & \BsN &::=& + n{:}\Bbyte &\Rightarrow& n & (\iff n < 2^6 \wedge n < 2^{N-1}) \\ &&|& + n{:}\Bbyte &\Rightarrow& n-2^7 & (\iff 2^6 \leq n < 2^7 \wedge n \geq 2^7-2^{N-1}) \\ &&|& + n{:}\Bbyte~~m{:}\BsX{(N\B{-7})} &\Rightarrow& + 2^7\cdot m + (n-2^7) & (\iff n \geq 2^7 \wedge N > 7) \\ + \end{array} + +:ref:`Uninterpreted integers ` are encoded as signed integers. + +.. math:: + \begin{array}{llclll@{\qquad\qquad}l} + \production{uninterpreted integer} & \BiN &::=& + n{:}\BsN &\Rightarrow& i & (\iff n = \signed_{\iN}(i)) + \end{array} + +.. note:: + The side conditions :math:`N > 7` in the productions for non-terminal bytes of the :math:`\uX{}` and :math:`\sX{}` encodings restrict the encoding's length. + However, "trailing zeros" are still allowed within these bounds. + For example, :math:`\hex{03}` and :math:`\hex{83}~\hex{00}` are both well-formed encodings for the value :math:`3` as a |u8|. + Similarly, either of :math:`\hex{7e}` and :math:`\hex{FE}~\hex{7F}` and :math:`\hex{FE}~\hex{FF}~\hex{7F}` are well-formed encodings of the value :math:`-2` as a |s16|. + + The side conditions on the value :math:`n` of terminal bytes further enforce that + any unused bits in these bytes must be :math:`0` for positive values and :math:`1` for negative ones. + For example, :math:`\hex{83}~\hex{10}` is malformed as a |u8| encoding. + Similarly, both :math:`\hex{83}~\hex{3E}` and :math:`\hex{FF}~\hex{7B}` are malformed as |s8| encodings. + + +.. index:: floating-point number, little endian + pair: binary format; floating-point number +.. _binary-float: + +Floating-Point +~~~~~~~~~~~~~~ + +:ref:`Floating-point ` values are encoded directly by their |IEEE754|_ (Section 3.4) bit pattern in |LittleEndian|_ byte order: + +.. math:: + \begin{array}{llclll@{\qquad\qquad}l} + \production{floating-point value} & \BfN &::=& + b^\ast{:\,}\Bbyte^{N/8} &\Rightarrow& \bytes_{\fN}^{-1}(b^\ast) \\ + \end{array} + + +.. index:: name, byte, Unicode, ! UTF-8 + pair: binary format; name +.. _binary-utf8: +.. _binary-name: + +Names +~~~~~ + +:ref:`Names ` are encoded as a :ref:`vector ` of bytes containing the |Unicode|_ (Section 3.9) UTF-8 encoding of the name's character sequence. + +.. math:: + \begin{array}{llclllll} + \production{name} & \Bname &::=& + b^\ast{:}\Bvec(\Bbyte) &\Rightarrow& \name + && (\iff \utf8(\name) = b^\ast) \\ + \end{array} + +The auxiliary |utf8| function expressing this encoding is defined as follows: + +.. math:: + \begin{array}{@{}l@{}} + \begin{array}{@{}lcl@{\qquad}l@{}} + \utf8(c^\ast) &=& (\utf8(c))^\ast \\[1ex] + \utf8(c) &=& b & + (\begin{array}[t]{@{}c@{~}l@{}} + \iff & c < \unicode{80} \\ + \wedge & c = b) \\ + \end{array} \\ + \utf8(c) &=& b_1~b_2 & + (\begin{array}[t]{@{}c@{~}l@{}} + \iff & \unicode{80} \leq c < \unicode{800} \\ + \wedge & c = 2^6(b_1-\hex{C0})+(b_2-\hex{80})) \\ + \end{array} \\ + \utf8(c) &=& b_1~b_2~b_3 & + (\begin{array}[t]{@{}c@{~}l@{}} + \iff & \unicode{800} \leq c < \unicode{D800} \vee \unicode{E000} \leq c < \unicode{10000} \\ + \wedge & c = 2^{12}(b_1-\hex{E0})+2^6(b_2-\hex{80})+(b_3-\hex{80})) \\ + \end{array} \\ + \utf8(c) &=& b_1~b_2~b_3~b_4 & + (\begin{array}[t]{@{}c@{~}l@{}} + \iff & \unicode{10000} \leq c < \unicode{110000} \\ + \wedge & c = 2^{18}(b_1-\hex{F0})+2^{12}(b_2-\hex{80})+2^6(b_3-\hex{80})+(b_4-\hex{80})) \\ + \end{array} \\ + \end{array} \\ + \where b_2, b_3, b_4 < \hex{C0} \\ + \end{array} + +.. note:: + Unlike in some other formats, name strings are not 0-terminated. diff --git a/document/conf.py b/document/core/conf.py similarity index 97% rename from document/conf.py rename to document/core/conf.py index 5971bb4a16..d410ee04de 100644 --- a/document/conf.py +++ b/document/core/conf.py @@ -18,7 +18,7 @@ import os import sys pwd = os.path.abspath('.') -sys.path.insert(0, pwd) +sys.path.insert(0, pwd + '/util') # -- General configuration ------------------------------------------------ @@ -36,6 +36,7 @@ 'sphinx.ext.ifconfig', 'sphinx.ext.githubpages', 'mathdef', + 'pseudo-lexer' ] # Add any paths that contain templates here, relative to this directory. @@ -59,7 +60,8 @@ title = u'WebAssembly Specification' copyright = u'2017, WebAssembly Community Group' author = u'WebAssembly Community Group' -logo = 'placeholder.jpg' +editor = u'Andreas Rossberg (editor)' +logo = 'static/webassembly.png' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -136,7 +138,8 @@ # html_theme_options = { 'logo': logo, - 'description': ' ', + 'logo_name': 'WebAssembly', + 'description': 'WebAssembly Specification', 'fixed_sidebar': True, 'sidebar_width': '260px', 'sidebar_collapse': True, @@ -156,6 +159,7 @@ ] } + # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = [] @@ -182,7 +186,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static', 'custom.css'] +html_static_path = ['_static', 'static/custom.css'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied @@ -298,7 +302,7 @@ ( master_doc, name + '.tex', title, - author, + author + '\\\\ \\hfill\\large ' + editor, 'manual' ), ] @@ -472,5 +476,5 @@ # Macros rst_prolog = """ -.. include:: /""" + pwd + """/math.def +.. include:: /""" + pwd + """/util/macros.def """ diff --git a/document/core/exec/conventions.rst b/document/core/exec/conventions.rst new file mode 100644 index 0000000000..807239b044 --- /dev/null +++ b/document/core/exec/conventions.rst @@ -0,0 +1,134 @@ +.. index:: ! execution, stack, store + +Conventions +----------- + +WebAssembly code is *executed* when :ref:`instantiating ` a module or :ref:`invoking ` an :ref:`exported ` function on the resulting module :ref:`instance `. + +Execution behavior is defined in terms of an *abstract machine* that models the *program state*. +It includes a *stack*, which records operand values and control constructs, and an abstract *store* containing global state. + +For each instruction, there is a rule that specifies the effect of its execution on the program state. +Furthermore, there are rules describing the instantiation of a module. +As with :ref:`validation `, all rules are given in two *equivalent* forms: + +1. In *prose*, describing the execution in intuitive form. +2. In *formal notation*, describing the rule in mathematical form. [#cite-pldi2017]_ + +.. note:: + As with validation, the prose and formal rules are equivalent, + so that understanding of the formal notation is *not* required to read this specification. + The formalism offers a more concise description in notation that is used widely in programming languages semantics and is readily amenable to mathematical proof. + + +.. _exec-notation-textual: + +Prose Notation +~~~~~~~~~~~~~~ + +Execution is specified by stylised, step-wise rules for each :ref:`instruction ` of the :ref:`abstract syntax `. +The following conventions are adopted in stating these rules. + +* The execution rules implicitly assume a given :ref:`store ` :math:`S`. + +* The execution rules also assume the presence of an implicit :ref:`stack ` + that is modified by *pushing* or *popping* + :ref:`values `, :ref:`labels `, and :ref:`frames `. + +* Certain rules require the stack to contain at least one frame. + The most recent frame is referred to as the *current* frame. + +* Both the store and the current frame are mutated by *replacing* some of their components. + Such replacement is assumed to apply globally. + +* The execution of an instruction may *trap*, + in which case the entire computation is aborted and no further modifications to the store are performed by it. (Other computations can still be initiated afterwards.) + +* The execution of an instruction may also end in a *jump* to a designated target, + which defines the next instruction to execute. + +* Execution can *enter* and *exit* :ref:`instruction sequences ` that form :ref:`blocks `. + +* :ref:`Instruction sequences ` are implicitly executed in order, unless a trap or jump occurs. + +* In various places the rules contain *assertions* expressing crucial invariants about the program state. + + +.. index:: ! reduction rules, configuration, evaluation context +.. _exec-notation: + +Formal Notation +~~~~~~~~~~~~~~~ + +.. note:: + This section gives a brief explanation of the notation for specifying execution formally. + For the interested reader, a more thorough introduction can be found in respective text books. [#cite-tapl]_ + +The formal execution rules use a standard approach for specifying operational semantics, rendering them into *reduction rules*. +Every rule has the following general form: + +.. math:: + \X{configuration} \quad\stepto\quad \X{configuration} + +A *configuration* is a syntactic description of a program state. +Each rule specifies one *step* of execution. +As long as there is at most one reduction rule applicable to a given configuration, reduction -- and thereby execution -- is *deterministic*. +WebAssembly has only very few exceptions to this, which are noted explicitly in this specification. + +For WebAssembly, a configuration typically is a tuple :math:`(S; F; \instr^\ast)` consisting of the current :ref:`store ` :math:`S`, the :ref:`call frame ` :math:`F` of the current function, and the sequence of :ref:`instructions ` that is to be executed. +(A more precise definition is given :ref:`later `.) + +To avoid unnecessary clutter, the store :math:`S` and the frame :math:`F` are omitted from reduction rules that do not touch them. + +There is no separate representation of the :ref:`stack `. +Instead, it is conveniently represented as part of the configuration's instruction sequence. +In particular, :ref:`values ` are defined to coincide with |CONST| instructions, +and a sequence of |CONST| instructions can be interpreted as an operand "stack" that grows to the right. + +.. note:: + For example, the :ref:`reduction rule ` for the :math:`\I32.\ADD` instruction can be given as follows: + + .. math:: + (\I32.\CONST~n_1)~(\I32.\CONST~n_2)~\I32.\ADD \quad\stepto\quad (\I32.\CONST~(n_1 + n_2) \mod 2^{32}) + + Per this rule, two |CONST| instructions and the |ADD| instruction itself are removed from the instruction stream and replaced with one new |CONST| instruction. + This can be interpreted as popping two value off the stack and pushing the result. + + When no result is produced, an instruction reduces to the empty sequence: + + .. math:: + \NOP \quad\stepto\quad \epsilon + +:ref:`Labels