Skip to content
This repository was archived by the owner on Apr 25, 2025. It is now read-only.

Replace 'event' with 'tag' in explainer #161

Merged
merged 5 commits into from
Jun 18, 2021
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 65 additions & 86 deletions proposals/exception-handling/Exceptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,50 +45,40 @@ instruction. Thrown exceptions are handled as follows:
1. If the call stack is exhausted without any enclosing try blocks, the embedder
defines how to handle the uncaught exception.

### Event handling
### 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.
`tag` that allows the declaration of other forms of typed tags in future.

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.
WebAssembly tags are defined in a new `tag` section of a WebAssembly module. The
tag section is a list of declared tags associated with the module.

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.
Each tag has an `attribute` and a `type`. Currently, the attribute can only
specify that the tag is for an exception. In the future, additional attribute
values may be added when other kinds of tags are added to WebAssembly.

To allow for such a future extension possibility, we reserve a byte in the
binary format of an exception definition, set to 0 to denote an exception
attribute, but for the moment we won't use the term event in the formal spec.
attribute.

### Exceptions

An `exception` is an internal construct in WebAssembly. WebAssembly exceptions
are defined in the event and import sections of a module.
An `exception tag` is a value to distinguish different exceptions, while an
`exception tag index` is a numeric name to refer to an (imported or defined)
exception tag within a module (see [tag index space](#tag-index-space) for
details). Exception tags are defined in the tag and import sections of a module.

The type of an exception is denoted by an index to a function signature defined
in the `type` section. The parameters of the function signature define the list
of values associated with the exception. The result type must be empty.
An `exception` is an internal construct in WebAssembly that represents a runtime
object that can be thrown. A WebAssembly exception is defined by an exception
tag and its runtime arguments.

An `exception tag` is a value to distinguish different exceptions, while an
`exception index` is a numeric name to refer to an (imported or defined)
exception tag within a module (see [exception index
space](#exception-index-space) for details).
The type of an exception tag is denoted by an index to a function signature
defined in the `type` section. The parameters of the function signature define
the list of values associated with the tag. The result type must be empty.

Exception indices are used by:
Exception tag indices are used by:

1. The `throw` instruction which creates a WebAssembly exception with the
corresponding exception tag, and then throws it.
Expand Down Expand Up @@ -138,9 +128,9 @@ are considered _tagged_ catch blocks.

The last catching instruction of a try-catch block can be 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. The
term 'catch block' refers to both `catch` and `catch_all` blocks.
_default_ catch block. The default catch block has no tag index, and is used to
catch all exceptions not caught by any of the tagged catch blocks. The term
'catch block' refers to both `catch` and `catch_all` blocks.

When the program runs `br` within `catch` or `catch_all` blocks, the rest of
the catching blocks will not run and the program control will branch to the
Expand All @@ -154,13 +144,13 @@ targets for branches (`br` and `br_if`) as well.

### 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
The `throw` instruction takes an exception tag 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 off the stack and are used (along with the
corresponding exception tag) to create the corresponding exception. That
exception tag. 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.

When an exception is thrown, the embedder searches for the nearest enclosing try
Expand All @@ -187,7 +177,7 @@ after possible block parameters were popped.
Then in case of a try-catch block, 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.
the arguments of the exception are pushed back onto the stack.

Otherwise, control is transferred to the body of the `catch_all` block, if any.
However, unlike tagged catch blocks, the constructor arguments are not copied
Expand Down Expand Up @@ -358,38 +348,36 @@ document](https://github.com/WebAssembly/spec/blob/master/document/core/text/ins
The following rules are added to *instructions*:

```
try blocktype instruction* (catch instruction*)* (catch_all instruction*)? end |
try blocktype instruction* (catch tag_index instruction*)* (catch_all instruction*)? end |
try blocktype instruction* delegate label |
throw (exception except_index) |
throw tag_index argument* |
rethrow label |
```

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 `catch` 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.
The `tag_index` of the `throw` and `catch` instructions denotes the exception
tag to use when creating/extract from an exception. See [tag index
space](#tag-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
### Tag 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 `tag index space` indexes all imported and internally-defined exception
tags, assigning monotonically-increasing indices based on the order defined in
the import and tag sections. Thus, the index space starts at zero with imported
tags, followed by internally-defined tags in the [tag section](#tag-section).

The exception index space defines the (module) static version of runtime
exception tags. For exception indices that are not imported/exported, the
corresponding exception tag is guaranteed to be unique over all loaded modules.
Exceptions that are imported or exported alias the respective exceptions defined
elsewhere, and use the same tag.
For tag indices that are not imported/exported, the corresponding exception tag
is guaranteed to be unique over all loaded modules. Exceptions that are imported
or exported alias the respective exceptions defined elsewhere, and use the same
tag.

## Changes to the binary model

Expand All @@ -398,48 +386,39 @@ document](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md).

#### Other Types

##### exception_type
##### tag_type

We reserve a bit to denote the exception attribute:

| Name | Value |
|-----------|-------|
| Exception | 0 |

Each exception type has the fields:
Each tag type has the fields:

| Field | Type | Description |
|-------|------|-------------|
| `attribute` | `varuint32` | The attribute of an exception. |
| `attribute` | `varuint32` | The attribute of a tag. |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Obviously a separate issue, but I'm just noticing this while I'm here: I'd conservatively make this a uint8 for the time being, since we do not know yet how exactly this is gonna be used in the future, and a zero uint8 is still forward compatible with varuint32. That's what we did in other places anyway.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can do that as a followup PR. But why uint8 better than varuint32 here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's both more conservative and faster to decode. No reason to bother with allowing multibyte representations of 0 before we even know that we'll need them.

| `type` | `varuint32` | The type index for its corresponding type 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 `Event` [import](#import-section) or
[definition](#event-section)
* `4` indicating a `Tag`
[import](https://github.com/WebAssembly/design/blob/main/BinaryEncoding.md#import-section) or
[definition](#tag-section)

### Module structure

#### High-level structure

A new `event` section is introduced and is named `event`. If included, it must
appear immediately after the memory section.
A new `tag` section is introduced.

##### Exception section
##### Tag section

The `event` section is the named section 'exception'. For ease of validation,
this section comes after the [memory
The `tag` section comes after the [memory
section](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#memory-section)
and before the [global
section](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#global-section).
Expand All @@ -452,42 +431,42 @@ So the list of all sections will be:
| Function | `3` | Function declarations |
| Table | `4` | Indirect function table and other tables |
| Memory | `5` | Memory attributes |
| Event | `13` | Event declarations |
| Tag | `13` | Tag declarations |
| Global | `6` | Global 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:
The tag section declares a list of tag types as follows:

| Field | Type | Description |
|-------|------|-------------|
| count | `varuint32` | count of the number of event to follow |
| type | `event_type*` | The definitions of the event types |
| count | `varuint32` | count of the number of tags to follow |
| type | `tag_type*` | The definitions of the tag types |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is tag_type defined anywhere?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While creating this PR, I found multiple occurrences that we had missed when we had replaced 'exception' with 'event' before, and I tried to replace 'event' with 'tag' in this PR, so I missed those remaining 'exception's.. It was written as exception_type. I changed it to tag_type now.


##### Import section

The import section is extended to include exception definitions by extending an
The import section is extended to include tag definitions by extending an
`import_entry` as follows:

If the `kind` is `Event`:
If the `kind` is `Tag`:

| Field | Type | Description |
|-------|------|-------------|
| `type` | `event_type` | the event being imported |
| `type` | `tag_type` | the tag being imported |

##### Export section

The export section is extended to reference exception types by extending an
The export section is extended to reference tag types by extending an
`export_entry` as follows:

If the `kind` is `Event`:
If the `kind` is `Tag`:

| Field | Type | Description |
|-------|------|-------------|
| `index` | `varuint32` | the index into the corresponding event index space |
| `index` | `varuint32` | the index into the corresponding tag index space |

##### Name section

Expand All @@ -498,12 +477,12 @@ follows:
| --------- | ---- | ----------- |
| [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 |
| [Tag](#tag-names) | `3` | Assigns names to tag types |

###### Event names
###### Tag names

The event names subsection is a `name_map` which assigns names to a subset of
the exception indices (Used for both imports and module-defined).
The tag names subsection is a `name_map` which assigns names to a subset of
the tag indices (Used for both imports and module-defined).

### Control flow operators

Expand All @@ -516,7 +495,7 @@ throws, and rethrows as follows:
| `catch` | `0x07` | index : `varint32` | begins the catch block of the try block |
| `catch_all` | `0x19` | | begins the catch_all block of the try block |
| `delegate` | `0x18` | relative_depth : `varuint32` | begins the delegate block of the try block |
| `throw` | `0x08` | index : `varint32` | Creates an exception defined by the exception `index`and then throws it |
| `throw` | `0x08` | index : `varint32` | Creates an exception defined by the tag and then throws it |
| `rethrow` | `0x09` | relative_depth : `varuint32` | Pops the `exnref` on top of the stack and throws it |

The *sig* fields of `block`, `if`, and `try` operators are block signatures
Expand Down