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

Generalize exceptions to events #49

Merged
merged 8 commits into from
Mar 8, 2018

Conversation

KarlSchimpf
Copy link
Contributor

Change the exception handling proposal to use a more general notion of "events", so that it will be easier to generalize the proposal when yeild/resume events are added.

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 embedder.
Copy link
Member

Choose a reason for hiding this comment

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

"is left to the implementation"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

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.
When an exception value is thrown, the embedder searches for the nearest
Copy link
Member

Choose a reason for hiding this comment

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

"the embedder searches" - it's the Wasm VM. How about: "When an exception is thrown, the active try block entered last is called the catching try block."

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.
As expected, it is left to the embedder to define how WebAssembly exceptions are
Copy link
Member

Choose a reason for hiding this comment

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

This seems to repeat what is already said on L193.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Deleted

`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, defined by the `then` and `else` instructions
Copy link
Member

Choose a reason for hiding this comment

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

There isn't really a then instruction.

Copy link
Member

Choose a reason for hiding this comment

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

Can't we add one, to be symmetric with if and else instruction pair?

has two instruction blocks, defined by the `then` and `else` instructions
like that of an `if` block.

The `if_except` instruction queries of the exception on top of the stack, and
Copy link
Member

Choose a reason for hiding this comment

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

Stray "of"

exception index defined in each module.
For event indices imported/exported, unique event tags are created for each
unique name imported/exported, and are aliased to the corresponding event index
defined in each module.

## Changes to the binary model
Copy link
Member

Choose a reason for hiding this comment

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

model -> format

### 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 defined by
Copy link
Member

Choose a reason for hiding this comment

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

See earlier comment. I would drop any reference to size, given that it is not observable in any way.

@sunfishcode
Copy link
Member

sunfishcode commented Feb 27, 2018

In some places (example), this feature is called "zero-cost exceptions", referring to implementation strategies in which non-throwing code is optimized, at the expense of making throwing slow. This is useful for languages like Rust and C++.

Is this proposal still intending to enable zero cost exceptions for WebAssembly?

I'm aware that this is a performance consideration, rather than a semantic consideration.

@eholk
Copy link
Contributor

eholk commented Feb 27, 2018

@sunfishcode - While we want to support many languages, I think the primary goal with this proposal is still to make sure C++ is well-supported. I agree that code that does not use throw or try/catch should not take a performance penalty just because the VM supports those exceptions.

Do you have concerns that this proposal will be hard to implement without imposing a pervasive cost on all code?

@sunfishcode
Copy link
Member

@eholk The term "zero cost" comes from the fact that in typical "zero cost" implementations, entering a try block does not involve executing any code. The main point is that even code that does use try/catch frequently should not take a (significant) performance penalty, in a "zero cost" system.

Unifying exception handling with yield/resume seems counter to the assumptions of a "zero cost" model, because the whole point of a generator, for example, is to yield, often many times. It'd help me to understand this whole proposal if such considerations were documented.

Copy link
Member

@aheejin aheejin left a comment

Choose a reason for hiding this comment

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

Mostly typo fixes

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 know where exceptions are stored, so that it can determine when an
Copy link
Member

Choose a reason for hiding this comment

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

needs to

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

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 ebedders that have garbage collection (such as JavaScript),
Copy link
Member

Choose a reason for hiding this comment

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

embedders

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

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
my send values back to the suspended instruction, allowing the originating code
Copy link
Member

Choose a reason for hiding this comment

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

may

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

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 WebAssemble.
Copy link
Member

Choose a reason for hiding this comment

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

WebAssembly

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

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`.
Copy link
Member

Choose a reason for hiding this comment

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

missing ` after end

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

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 poppod off the stack.
Copy link
Member

Choose a reason for hiding this comment

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

popped

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

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, and WebAssembly does not have
(direct) access to the stack trace.
Copy link
Member

Choose a reason for hiding this comment

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

  1. I thought the stack trace meant the call stack trace for debugging, but this says the operand stack traces. Are we not gonna have the call stack traces?

  2. The previous version implied that we might add two-phase unwinding in the future. Is there any reason it was deleted?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

1 - The stack trace is intended to be a call stack trace, and my read still states this.

  1. We may have two phase (for debugging), but we never stated that it would be mandatory. Dropped because that is an implementation detail and not a requirement.

Copy link
Contributor

Choose a reason for hiding this comment

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

For what it's worth, stack traces are also an implementation detail since there is no way to access them from Wasm.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed the end of the last sentence (on direct access), since it is optional of the implementation.

`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, defined by the `then` and `else` instructions
Copy link
Member

Choose a reason for hiding this comment

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

Can't we add one, to be symmetric with if and else instruction pair?


| Field | Type | Description |
|-------|------|-------------|
| `index` | `varuitn32` | the index into the corresponding event index space |
Copy link
Member

Choose a reason for hiding this comment

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

varuint32

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@aheejin
Copy link
Member

aheejin commented Mar 1, 2018

Can we add the syntactic sugar then to if_except/else/end as well, to be symmetric with the if/else instruction pair?

@aardappel
Copy link

@sunfishcode : I voiced some similar concerns here: #42

The paper @rossberg linked https://www.microsoft.com/en-us/research/publication/implementing-algebraic-effects-c/ is very interesting because it has some actual timings you can expect from such resumable exceptions, which initially look pretty bad (compared to an implementation specialized purely for, say, generators), but it also shows a transformation that in a common case can avoid a stack-swap all-together, which would result in a very fast generator.

I agree that it seems that exceptions and generators would have opposite requirements of what path should be fast. I am not sure if the transform mentioned in the paper can be applied commonly enough to bridge that gap.

Copy link
Contributor Author

@KarlSchimpf KarlSchimpf left a comment

Choose a reason for hiding this comment

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

Fixed misspellings.

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 know where exceptions are stored, so that it can determine when an
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

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 ebedders that have garbage collection (such as JavaScript),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

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
my send values back to the suspended instruction, allowing the originating code
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

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 WebAssemble.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

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`.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

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 poppod off the stack.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

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, and WebAssembly does not have
(direct) access to the stack trace.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

1 - The stack trace is intended to be a call stack trace, and my read still states this.

  1. We may have two phase (for debugging), but we never stated that it would be mandatory. Dropped because that is an implementation detail and not a requirement.


| Field | Type | Description |
|-------|------|-------------|
| `index` | `varuitn32` | the index into the corresponding event index space |
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@eholk
Copy link
Contributor

eholk commented Mar 7, 2018

@sunfishcode @aardappel - @lukewagner voices similar concerns about the cost of throwing and catching exceptions in #19. Why don't we consolidate this discussion there and update the proposal as needed based on the results of the discussion?

Copy link
Contributor

@eholk eholk left a comment

Choose a reason for hiding this comment

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

lgtm modulo nits

@@ -1,4 +1,4 @@
# Level 1 exception handling
Level 1 exception handling
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: I'd leave the # so this is a heading.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

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`.
Copy link
Contributor

Choose a reason for hiding this comment

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

@sunfishcode pointed out that this optional else block complicates decoding. We should consider making this not optional (#54). This is an issue for another PR though.

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 operand stack across
Copy link
Contributor

Choose a reason for hiding this comment

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

It's probably okay to be a little imprecise and just say "pop the stack across function calls" rather than specifying it's the operand stack.

Copy link
Member

@aheejin aheejin Mar 8, 2018

Choose a reason for hiding this comment

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

What I meant by "why only the operand stack traces and not call stack traces" here is this too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed "operand".


##### Exception section
##### event section
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: capitalize "Event."

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@KarlSchimpf KarlSchimpf merged commit b228f3a into WebAssembly:master Mar 8, 2018
@KarlSchimpf KarlSchimpf deleted the KarlSchimpf-fix branch March 8, 2018 20:42
ioannad pushed a commit to ioannad/exception-handling that referenced this pull request Feb 23, 2021
* 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
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants