-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Any formal execution definition of exception handling? #87
Comments
There is nothing written up in publishable form yet. So let me just dump the rules as an extension to the PLDI paper (or rather, the somewhat updated CACM version) in ASCII art here. Hope that helps answering your question. :) Abstract SyntaxValue Types
Exception Types
Instructions
Exceptions
Modules
TypingContexts
Rules
ReductionStores
Exception Instances
Module Instances
Values
Administrative Instructions
Throw Contexts
Rules
|
Thank you for the response! In the proposal,
Also in the reduction rule, exception values are represented as |
No, the typing rule for Exnref is an abstract (reference) type. It is an implementation detail how and where its argument values are stored. It is separate from any linear memory. |
This PR adds the dependency to multi-value to the exception handling proposal text and to the README. I wrote an explanation of this dependency on the proposal text, but it's easier to see this once the verification and execution steps of `br_on_exn` and of `try` blocks are written out, as done [here](#87 (comment)) by @rossberg : Validation: ``` ft = t1* -> t2* C, label t2* |- e1* : t1* -> t2* C, label t2* |- e2* : exnref -> t2* ----------------------------------- C |- try ft e1* catch e2* end : ft C_label(l) = C_exn(x) = t* ------------------------------------- C |- br_on_exn l x : exnref -> exnref ``` Execution: ``` v^n (try ft e1* catch e2* end) --> catch_m{e2*} (label_m{} v^n e1* end) end) (iff ft = t1^n -> t2^m) S; F; catch_m{e*} T[v^n (throw a)] end --> S; F; label_m{} (exn a v^n) e* end (iff S_exn(a) = {typ t^n}) F; (exn a v*) (br_on_exn l x) --> F; v* (br l) (iff F_exn(x) = a) ``` Concerning the functionality of `try`-`catch` blocks, note especially the passing of `v^n` values into a `label_m{}`. Concerning the functionality of `br_on_exn`, note especially the execution step resulting in a `br` instruction.
Following the informal formal spec by Andreas Rossberg : WebAssembly#87 (comment) and the discussions in the issues.
@rossberg , with the addition of throw contexts,
Invoking I suppose this is the case meant by "the embedder defines how to handle the uncaught exception". But in this case it is not true any more that "Reduction terminates when a thread’s instruction sequence has been reduced to a result, that is, either a sequence of values or to a trap." (e.g., in the definition of evaluation contexts). Should some other form of "result" (which is not a sequence of values or a trap) be defined to cover such cases of unresolved throw contexts? |
@ioannad, yes, correct: with exceptions we will naturally need to extend the notion of result to include Basically, it all needs to mirror what we have for traps. Except that there also is the try rule to intercept a throw. |
… (WebAssembly#87) Change the test generators to use `ref.func` and remove `passive`. At some point we'll want to remove the generators, but for let's try to maintain them.
Per the vote on WebAssembly#69, this PR removes subtyping from the proposal. List of changes: * Syntax: - remove `nullref` type - rename `anyref` type to `externref` - extend `ref.null` and `ref.is_null` instructions with new immediate of the form `func` or `extern` (this will later have to generalise to a `constype` per the [typed references proposal](https://github.com/WebAssembly/function-references)) * Typing rules: - `ref.null`, `ref.is_null`: determine reference type based on new immediate - `select`, `call_indirect`, `table.copy`, `table.init`: drop subtyping - `br_table`: revert to rule requiring same label types - `elem` segment: drop subtyping - `global` import: drop subtyping (link time) * Remove subtyping rules and bottom type. * Revert typing algorithm (interpreter and spec appendix). * JS API: - remove `"nullref"` - rename `"anyref"` to `"externref"` * Scripts: - rename `ref` result to `ref.extern` - rename `ref.host` value to `ref.extern` - drop subtyping from invocation type check * JS translation: - extend harness with separate eq functions for each ref type * Adjust tests: - apply syntax changes - remove tests for subtyping - change tests exercising subtyping in other ways
This PR adds the dependency to multi-value to the exception handling proposal text and to the README. I wrote an explanation of this dependency on the proposal text, but it's easier to see this once the verification and execution steps of `br_on_exn` and of `try` blocks are written out, as done [here](WebAssembly#87 (comment)) by @rossberg : Validation: ``` ft = t1* -> t2* C, label t2* |- e1* : t1* -> t2* C, label t2* |- e2* : exnref -> t2* ----------------------------------- C |- try ft e1* catch e2* end : ft C_label(l) = C_exn(x) = t* ------------------------------------- C |- br_on_exn l x : exnref -> exnref ``` Execution: ``` v^n (try ft e1* catch e2* end) --> catch_m{e2*} (label_m{} v^n e1* end) end) (iff ft = t1^n -> t2^m) S; F; catch_m{e*} T[v^n (throw a)] end --> S; F; label_m{} (exn a v^n) e* end (iff S_exn(a) = {typ t^n}) F; (exn a v*) (br_on_exn l x) --> F; v* (br l) (iff F_exn(x) = a) ``` Concerning the functionality of `try`-`catch` blocks, note especially the passing of `v^n` values into a `label_m{}`. Concerning the functionality of `br_on_exn`, note especially the execution step resulting in a `br` instruction.
…sal. This adds the [informal formal core spec](WebAssembly#87 (comment)) laid out by Andreas Rossberg, and the core spec outlined in the [proposal overview](https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md). I have aimed for this to be as complete as possible for the above "informal formal spec" and proposal overview, meaning I added prose for all the relevant parts in syntax, validation, execution, binary format, text format, and the appendix, as well as an example for throw contexts.
This adds: - the informal formal core spec laid out by Andreas Rossberg: WebAssembly#87 (comment) and - the core spec outlined in the proposal overview: https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md I have aimed for this to be as complete as possible for the above "informal formal spec" and proposal overview, meaning I added prose for all the relevant parts in syntax, validation, execution, binary format, text format, and the appendix, as well as an example for throw contexts. I also updated the README.md to: - remove mention to multi-value which is now part of the main spec, and - add a build status icon for the exception-handling modified spec.
This adds: - the informal formal core spec laid out by Andreas Rossberg: WebAssembly#87 (comment) and - the core spec outlined in the proposal overview: https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md I have aimed for this to be as complete as possible for the above "informal formal spec" and proposal overview, meaning I added prose for all the relevant parts in syntax, validation, execution, binary format, text format, and the appendix, as well as an example for throw contexts. I also updated the README.md to: - remove mention to multi-value which is now part of the main spec, and - add a build status icon for the exception-handling modified spec.
Included in this PR: - Detailed core formal spec additions aiming to fully implement: + the "informal formal" core spec laid out by Andreas @rossberg here: #87 (comment) and + the core spec outlined in the [proposal overview](https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md), while removing the mention of "events" everywhere but in the binary format , + prose for the above in: syntax, validation, execution, binary format, text format, and the appendix, as well as an example for throw contexts. - Travis-ci build status icon to `README.md`. The contents of this PR get built and deployed on my fork's github page successfully, using [the howto instructions](https://github.com/WebAssembly/proposals/blob/master/howto.md#setting-up-travis-and-github-page). Not included in this PR: - Neither the new values representing unresolved throw contexts, nor the additional rules for the execution contexts, which we discussed in #87, are added here. I plan to add these separately. - No JS API/Web API changes. Side comments: - In [document/core/text/types.rst](https://ioannad.github.io/exception-handling/core/text/types.html#text-refedtype): I'm not sure whether `refedtype ::= ... | event ⇒ exnref` should have `event` there or something else (perhaps `exception`?) However, since currently the only events are exceptions, this is probably not really an issue. - The "informal formal spec" defines the administrative instruction which represents an exception package as `exnref`, i.e., the same name as the type. I called this administrative instruction `ref.exn` instead for two reasons; to match the style of `ref.null` and `ref.extern`, and to avoid ambiguity in the discussions. - I removed multi-value mentions from `README.md` because multi-value is now part of the main spec. For the same reason I didn't add "multi-value" to the list of included proposals at the top of the core spec landing page.
EDIT: A reworked version of this formal spec overview is now added as a file with PR #143 . I leave the text below for reference, but please note this spec below is not correct. 3rd proposal formal specThis is an initial attempt to clarify the additions to formal spec in the new EH proposal (as of September 18, 2020). I wrote this "informal formal spec" roughly in the style of the previous informal formal spec above. The abstract syntax was given by @aheejin. This is my understanding of the typing and reduction steps for the new (old) instructions, mainly based on the the 1st proposal and several discussions in issues. In this I assume I have a couple of questions inline below, but I opened separate issues for those, to keep this issue about fixing the formal spec. Abstract SyntaxException Types
Instructions
Exceptions (definitions)
Modules
TypingTo verify that a To validate Contexts
Rules
The last rule above could be modified to allow the unwind block to return values, for example a default value that should be returned when the instructions of the try block throw an exception. This seems unneccessary because ReductionIn order to describe the interaction of To make sure we don't execute any instructions that appear after the throw, a further administrative instruction These new administrative instructions Moreover, apart from throw contexts I added "protected contexts", to talk about the case when an exception is thrown and caught outside a Throw contexts now include Stores
Exception Instances
Module Instances
Administrative Instructions
Protected Contexts
Throw Contexts
Rules
I would be happy if anyone could point out things that are wrong or that I misunderstood. (cc. @aheejin) |
I can't tell what the semantics of |
Good stuff. It's great to have a semantics written down and see the open questions crystalise more clearly. It is unfortunate that we need ad-hoc flags and markers in the typing rules to deal with the lack of composability in this version of the proposal, but I see no way around it. The typing rules seem right. As for the type of the unwind body, I think in principle we could allow a polymorphic result type, since it essentially ends in a branch, but that seems useless and would just complicate the operational semantics. I'm a bit more confused about the operational semantics. Can you explain the role of the new P contexts and their distinction from T? I am not sure why catch_br appears in both -- or, in fact, in either of them. For example, the reduction rules for
would go to (1), not (2) as it should.
Hm, this looks odd. I believe it should be something like
Can you explain the need for the complex side condition on this one? I would have expected something like
Something is missing here, I think: the outer catch first needs to check if it actually handles the exception. The There also does not seem to be a rule for the case where a catch does not handle a thrown exception, and it instead has to find an outer handler. I suspect this all will get extremely complicated (or even impossible) with the current approach. The only way I can think of to keep the rules tractable is by constructing the continuation incrementally. That could be done by reifying it as an evaluation context in the administrative
and so on. But in fact, if I read the answer to #130 correctly (I'm not sure I fully understand what the intended interaction is), then this could be simplified by not gathering contexts in the throw, but merely the sequence of unwind instructions to execute once the handler is found. That would also allow to get rid of the
This looks simpler and would clearly encode the intention that the unwind phase follows the catches. However, I'm not sure what is supposed to happen if an unwind block itself throws... Should the handler still be active, although it already caught? In that case, some additional wrapping around
I believe the enclosing caught_m and P is redundant in this rule. |
Thank you for the feedback, @rossberg and @RossTate. Sorry for the delay, I was tied up until today (and btw had to miss yesterday's SG meeting as well). @RossTate my understanding of @rossberg thank you so much for the detailed review! Some quick remarks before I start reworking the formal spec to incorporate your suggestions and comments.
My intention was to distinguish the case when a
My understanding is that any instruction after a I really like your suggestion of the new administrative
This was an attempt to distinguish the case when there is no
About |
No, but the catch_br here is part of the try, not an instruction after throw. (Ah, the text format actually requires writing this as |
@ioannad But in what context/continuation is that exception thrown? The answer affects how this example behaves: |
@rossberg oh, right, of course! I guess the notation and indentation threw me off.
@RossTate I'm not sure I understand what reasoning you mean. I think the operational semantics I gave for |
Ah yes, in the presence of two-phase unwind (which effectively is a limited form of resumption), rethrow has to be more explicit about maintaining the original throw point. I think that semantics can only be modelled correctly if the throw context or unwind instructions is reified in the exception like suggested above, and also remembered in the caught form. It's similar to how the semantics for effect handlers works, except that the effect value is second-class. I think something like
or similarly with This is mostly unrelated to crippling the scoping capabilities of rethrow, though. |
@rossberg It sounds like you are saying my example, |
Thank you for the clarification, @aheejin, I am having a hard time understanding the discussion in #124. I will direct any further comments on
I agree that mixing up the issues is very confusing. I'll post any further questions in their respective issues, and leave this issue for clarifications on the formal notation. |
Thanks for the clarifications, @aheejin. I can see how this all came about. But I still feel rather uncomfortable about the general turn we have taken wrt hypothetical two-phase EH. My impression is that the current direction is based on multiple implicit assumptions that all are somewhat questionable, especially:
The current direction OTOH seems to take us down a road where we end up building in special support for specific ad-hoc high-level language features. That is not aligned well with Wasm's goal of being a low-level and language-neutral engine. Taking a step back, obviously, there has to be a primitive mechanism for non-local control transfer/abort, and basic throw/catch as in the current proposal can be viewed as just that. In a way, it's just a glorified and well-behaved longjmp with unwind. But given that, everything more complex seems better suited to be expressed in user space. To wit, let me sketch how one could, quite easily, compile 2PEH with filters under the current proposal, without any use of try-unwind:
This can easily be extended to multiple catch clauses etc. There is a small overhead here in that each try has to push/pop the shadow stack. But before we plan for lowering (potentially multiple semantic variations of) similar machinery into Wasm, my take is that there should be sufficient evidence that this overhead is practically relevant, for the minority of languages that need it. |
I very much agree that point 1 is a misconception in the current proposal, but I disagree with point 2 (or more precisely, it's more nuanced, as I'll discuss below).
I agree with this, though there's a missing piece, which is that you need a way to unwind, e.g. destructors, (part of)
This is not true.
There are multiple problems with this suggestion, many of which line up with the reasons why we aren't telling programs to implement exception handling with shadow stacks.
Here you're using a global table to encode thread-local state. According to WebAssembly/design#1375 (comment), this is "the (somewhat embarrassing) current hack we use for web workers, but it isn't the plan for a first-class (pure wasm) threads".
This helper function has a bug. It pops handlers during the search. Those handlers need to stay on in case, during unwinding after the search has completed, an unwinder throws an exception that should be handled by one of those handlers. (There is Common Lisp code that specifically relies on this behavior.)
This has two bugs. For the first bug, you need to pop the handler regardless of how control exits. That should include when foreign code causes non-local control to exit the block, which is covered by using The second bug is that, if the handler function matches, then you need to make sure to go to this specific call frame's catcher (as there might be multiple frames for the same function on the stack). So you need to dynamically generate a unique identifier for the call frame and somehow store that in/with the pushed handler (so that it can be put in the event's payload), and similarly the catch needs to check that the identifier in the payload matches the current call frame's generated identifier. (This is not a problem for, say, C++ handlers. Though even then the payload should probably specify which of the compiled C++- Note that in more advanced 2PEH languages/implementations, the handler would normally reference and even mutate values in the corresponding call frame. So these languages will require allocating a closure each time you push the handler, updating the closure every time a relevant value is mutated, and pulling changes from the closure when the handler is popped. This work is wasted if the handler is never invoked.
Note that a foreign Reviewing the above exercise, I see that the above implementation strategy needs There are also issues with how it composes with other features in the pipeline. In particular, algebraic effects or first-class stacks provide ways to change the current stack and consequently change the handlers on the stack. This means that the global table can become out of touch with reality. I also identified a number of inefficiencies for more advanced 2PEH language implementations caused by trying to maintain this table as a shadow of the real stack. All these problems would be addressed by actually using the real stack to implement 2PEH rather than some attempted portrait of the stack. |
My whole point is that these might not be "missing", because they do not necessarily need to be primitive in a low-level VM. Anything that can be done in user space without significant loss ought to be done there.
I don't see that. A longjmp's target is first-class and selected completely dynamically, not lexically.
I think you are misrepresenting @lukewagner's comment. He was referring to thread-local state being implicitly identified with instance state right now, because there's no fork and no explicit sharing annotation, not to using thread-local state at all -- of course RTSs will need TLS for certain things, e.g., to maintain the shadow stack for C. In any case, this question seems completely orthogonal.
You are right, I was prematurely optimising code size by moving the pop from the catch to $throw while writing down the sketch. I hope we can agree that this is easily fixed.
Remember this was just a sketch. I agree that to interact cleanly with foreign code you'll need to run pop in a finalizer, but catch-all/rethrow will do just fine.
I think that's not true. For a given catch, the innermost instance of handler in the shadow stack will correspond to the innermost handler on the Wasm stack by construction. I don't see why anything else would be needed.
Well, this relates directly to the problem I keep pointing out with your vision for an engine solution: the implicit assumption that an engine could execute code in a call frame that is not on top of the stack. In most engines I have seen that won't work without implementing fragmented stack frames, for reasons I have pointed out several times. I highly doubt fragmented stack frames are something engine makers would be willing to accept -- it seems like a bad idea for Wasm. So I believe that any built-in solution will almost inevitably have the exact same limitation.
Such a catch-all will run in the 2nd phase, where it seems like it would evoke exactly the behaviour it should? If it rethrows, e.g., because it encodes a finally, then unwinding continues as one would expect. If it swallows (a.k.a. handles) the exception, that seems fine as well, the outer handlers will remain on the shadow stack and thus active (provided my mistake above is corrected).
See above, there may well be other potential issues I'm missing right now, but this probably isn't one of them.
Interaction with continuations is the main concern here, I agree. This one I don't have a good answer for right now -- though I do point out that this doesn't represent a new problem, we'll already need to solve that somehow for other existing uses of shadow stack, as in C. OTOH, this mirrors my dual concern with baking ad-hoc mechanisms into the language that risk ending up with a hacky combined semantics if they lack a proper foundation. |
@rossberg Thanks for your writeup. What you wrote is very much like what I thought a VM would do for two-phase internally, and I don't really have a preference whether it should be done in the VM side or in the user side, as long as it shows reasonable performance. But I'm still not sure how that handles cleanup code.
|
Clean-up code would compile to a plain try-catch_all-rethrow without a counterpart on the shadow handler stack. So it runs as expected when a
The observation underlying this scheme is that 2PEH should not be understood as 1PEH + a separate unwind phase afterwards, but as 1PEH + a separate search phase before. Throw/catch becomes the unwinding primitive, not the search primitive. So,
Hm, I believe that's orthogonal. While I only showed a source-level try compiling to try-catch, it can likewise be compiled to try-delegate when needed. Whether it's catch or delegate is a handler-side detail that does not affect the search and unwind mechanism leading up to it (or being resumed from it). You only have to ensure that you pop the necessary shadow handlers if delegation skips over respective handlers (which would be simpler if we replaced |
@rossberg All high-level and low-level systems with 2PEH (that I know of) have an |
I still don't understand how your scheme support cleanup code in the first phase. In the first phase, we should search for a matching handler. This shouldn't include cleanup code. If there's no matching handler, the program should crash without unwinding the stack. You also don't like an option that filter functions in Or, do you think we should delegate everything to user space so each handler does its own thing, including saying "I'm cleanup code" "I'm a user handler" or something? Also you are suggesting If your scheme can answer both of these problems, I actually support its removal. |
@rossberg It is important to be aware that this is not true. Only languages that do not strictly speak need 2PEH can have this property, and even then not all such languages do. As an example of this latter subset, in Python the kind of exception that is caught by a given This is why the macro-implementation of Common Lisp's Of course, we are not adding such a construct at the moment, and maybe we never will. Or maybe we will design a completely different way to do 2PEH. We just wanted to make room for such extensions, and the |
The first phase searches the shadow handler table and does not execute anything. Clean-up code is not in that table, so isn't taken into account.
As I said, clean-up code isn't even considered in the search. IOW, it is implemented differently from handlers (by the compiler) and no dynamic differentiation is needed. So catch and unwind are different just as they would be as Wasm constructs, except that the distinction is fully implemented in user code.
Oh, I am not proposing to change anything about rethrow. I am demonstrating that we would not need to change anything to implement 2PEH. Rethrow already does what it takes. I am showing a producer-side implementation technique that would use it in a certain way (and that may be non-obvious if one only thinks about 2PEH in a particular way). And interacts correctly with another 1PEH language that uses rethrow in the conventional way. There is one caveat, though, and that might be what you are getting at: if the 2PEH source language has a source-level
Huh? Handlers on the real stack have a 1-to-1 correspondence with handlers on the shadow stack. That's the very definition of a shadow stack. If there are multiple invocations of the same function with a handler then there are multiple entries for that handler on the shadow stack, in the same order. That is all you need. You seem to be conflating this with a completely separate problem, which is that some languages might require those entries to have access to some context from the handler's enclosing function. In such a setting, you have to program up the context closure, either by using Wasm closures (func.bind) as filters, or short of that, the good old way of threading through a context parameter manually. The same would be true for built-in 2PEH filters, because even then a filter cannot (realistically) be expected to be runnable in the function's frame, as I have pointed out various times already. |
In your sketch, every handler has a corresponding
You have said this many times, and yet it is not in line with what implementers said in other discussions. Regardless, |
EH control transfer is non-lexical by nature. Sorry, I don't see how there is a bug of the kind you are claiming. Can you provide an example of a throw that you think would go wrong?
I don't know who you talked to and what you asked them, but I have worked on some of V8's calling conventions myself, and hence can tell you with some confidence that this will not fly without fundamental changes to its stack usage and assumptions about it, and likely affecting performance. I can't speak for other engines, but I would be very surprised if it worked seamlessly for them.
I'm arguing that we need to support features in a non-additive manner and that there are too many premature assumptions right now. |
2PEH has two phases. The search phase is non-lexical by nature—you are searching the stack for a matching handler. But the unwinding phase is lexical—the matching handler indicates where to transfer control to (after unwinding). As I mentioned, this is explicit in Common Lisp, which desugars
Suppose |
Ah, okay, excellent point. Thanks! I stand corrected. Of course, it wouldn't be hard to work around that by using a secondary dynamic token and compare that in the handler. But I admit that reduces the appeal of that solution. A more elegant solution would be possible if we removed the (somewhat artificial) limitation of static exception tag allocation in the EH proposal, which might be desirable for other things as well. |
Thanks for helping me find the right illustrative example. Did that also help convey to you the rationale of |
Yeah, I'm still uncomfortable with committing to ad-hoc solutions prematurely and without a strategy that sound sounds different from "let's built in every feature". Dynamic tag generation would be a more orthogonal and principled solution to the particular problem you pointed out. OTOH, the potential harm of unwind is hopefully limited, so I won't die on this hill. But I do remain worried about the path this approach puts us on. |
At present the proposal has dynamically scoped local and non-local control but only lexically scoped local, so it seems natural to complete the square with lexically scoped non-local control. Regarding principles, lexically scoped non-local control has stronger parametricity properties. It also supports more efficient (in terms of order of complexity) non-local control transfers because there is no need to search. Dynamic tag generation can emulate lexically scoped non-local control but with weaker guarantees and poorer performance, and the current proposal can already emulate dynamic tag generation. As for the path, completing the square seems to cover the single-stack control space very well. |
I'm not very sure why we are discussing lexical vs. dynamically scoping here. Do we plan to support any dynamically scoped language? Is wasm a dynamically scoped model? (I think no) I share @rossberg's concern that, even if we need a functionality similar to |
I agree with this. And as I feared in a comment to PR#137, trying to specify |
This is an attempt to formally describe @aheejin's 3rd proposal, which she presented to the Wasm CG, and which was voted to be the new EH proposal, on September 18, 2020. This is not formal spec that I have developed, but a formal description of this 3rd proposal. This is a reworked form of my [first attempt on this formal spec overview](WebAssembly#87 (comment)) edited with my new understanding of the spec based on the discussion below, and in other issues, and according to @aheejin 's [3rd proposal overview](https://github.com/WebAssembly/exception-handling/blob/f7a4f60d11fb6326fc13f84d3889b11d3873f08a/proposals/Exceptions.md) in PR WebAssembly#137. This is in the form of a document as @tlively [requested](WebAssembly#142 (comment)), to make discussion on specific points easier. I wrote this formal spec overview roughly in the style of the 2nd proposal's [formal spec overview](WebAssembly#87 (comment)) by @rossberg. Particular points of interest: - In this I assume `rethrow` does have an immediate, as it is now described in WebAssembly#137. - The instruction `unwind` now reduces to `catch_all ... rethrow` as specified in Heejin's overview. - Because unwind is much simpler in this MVP, there is no `throw_point` anymore and `caught_m` is much simpler. - The introduction of `caught_m` now also introduces a label around the catch instructions, which label a rethrow instruction can reference. - Added explanation of the peculiar side condition in try's execution rule - just trying to make the rules more compact. I would be happy if anyone could point out things that are wrong or that I misunderstood.
Yes, I think continuing discussions in a dedicated issue or PR is more desirable. This issue started as a question from someone else that if we had a formal spec at all, and got expanded to include a number of topics I can't even count. |
This PR adds the dependency to multi-value to the exception handling proposal text and to the README. I wrote an explanation of this dependency on the proposal text, but it's easier to see this once the verification and execution steps of `br_on_exn` and of `try` blocks are written out, as done [here](WebAssembly#87 (comment)) by @rossberg : Validation: ``` ft = t1* -> t2* C, label t2* |- e1* : t1* -> t2* C, label t2* |- e2* : exnref -> t2* ----------------------------------- C |- try ft e1* catch e2* end : ft C_label(l) = C_exn(x) = t* ------------------------------------- C |- br_on_exn l x : exnref -> exnref ``` Execution: ``` v^n (try ft e1* catch e2* end) --> catch_m{e2*} (label_m{} v^n e1* end) end) (iff ft = t1^n -> t2^m) S; F; catch_m{e*} T[v^n (throw a)] end --> S; F; label_m{} (exn a v^n) e* end (iff S_exn(a) = {typ t^n}) F; (exn a v*) (br_on_exn l x) --> F; v* (br l) (iff F_exn(x) = a) ``` Concerning the functionality of `try`-`catch` blocks, note especially the passing of `v^n` values into a `label_m{}`. Concerning the functionality of `br_on_exn`, note especially the execution step resulting in a `br` instruction.
…bly#121) Included in this PR: - Detailed core formal spec additions aiming to fully implement: + the "informal formal" core spec laid out by Andreas @rossberg here: WebAssembly#87 (comment) and + the core spec outlined in the [proposal overview](https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md), while removing the mention of "events" everywhere but in the binary format , + prose for the above in: syntax, validation, execution, binary format, text format, and the appendix, as well as an example for throw contexts. - Travis-ci build status icon to `README.md`. The contents of this PR get built and deployed on my fork's github page successfully, using [the howto instructions](https://github.com/WebAssembly/proposals/blob/master/howto.md#setting-up-travis-and-github-page). Not included in this PR: - Neither the new values representing unresolved throw contexts, nor the additional rules for the execution contexts, which we discussed in WebAssembly#87, are added here. I plan to add these separately. - No JS API/Web API changes. Side comments: - In [document/core/text/types.rst](https://ioannad.github.io/exception-handling/core/text/types.html#text-refedtype): I'm not sure whether `refedtype ::= ... | event ⇒ exnref` should have `event` there or something else (perhaps `exception`?) However, since currently the only events are exceptions, this is probably not really an issue. - The "informal formal spec" defines the administrative instruction which represents an exception package as `exnref`, i.e., the same name as the type. I called this administrative instruction `ref.exn` instead for two reasons; to match the style of `ref.null` and `ref.extern`, and to avoid ambiguity in the discussions. - I removed multi-value mentions from `README.md` because multi-value is now part of the main spec. For the same reason I didn't add "multi-value" to the list of included proposals at the top of the core spec landing page.
…bly#121) Included in this PR: - Detailed core formal spec additions aiming to fully implement: + the "informal formal" core spec laid out by Andreas @rossberg here: WebAssembly#87 (comment) and + the core spec outlined in the [proposal overview](https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md), while removing the mention of "events" everywhere but in the binary format , + prose for the above in: syntax, validation, execution, binary format, text format, and the appendix, as well as an example for throw contexts. - Travis-ci build status icon to `README.md`. The contents of this PR get built and deployed on my fork's github page successfully, using [the howto instructions](https://github.com/WebAssembly/proposals/blob/master/howto.md#setting-up-travis-and-github-page). Not included in this PR: - Neither the new values representing unresolved throw contexts, nor the additional rules for the execution contexts, which we discussed in WebAssembly#87, are added here. I plan to add these separately. - No JS API/Web API changes. Side comments: - In [document/core/text/types.rst](https://ioannad.github.io/exception-handling/core/text/types.html#text-refedtype): I'm not sure whether `refedtype ::= ... | event ⇒ exnref` should have `event` there or something else (perhaps `exception`?) However, since currently the only events are exceptions, this is probably not really an issue. - The "informal formal spec" defines the administrative instruction which represents an exception package as `exnref`, i.e., the same name as the type. I called this administrative instruction `ref.exn` instead for two reasons; to match the style of `ref.null` and `ref.extern`, and to avoid ambiguity in the discussions. - I removed multi-value mentions from `README.md` because multi-value is now part of the main spec. For the same reason I didn't add "multi-value" to the list of included proposals at the top of the core spec landing page.
This is an attempt to formally describe @aheejin's 3rd proposal, which she presented to the Wasm CG, and which was voted to be the new EH proposal, on September 18, 2020. This is not formal spec that I have developed, but a formal description of this 3rd proposal. This is a reworked form of my [first attempt on this formal spec overview](WebAssembly#87 (comment)) edited with my new understanding of the spec based on the discussion below, and in other issues, and according to @aheejin 's [3rd proposal overview](https://github.com/WebAssembly/exception-handling/blob/f7a4f60d11fb6326fc13f84d3889b11d3873f08a/proposals/Exceptions.md) in PR WebAssembly#137. This is in the form of a document as @tlively [requested](WebAssembly#142 (comment)), to make discussion on specific points easier. I wrote this formal spec overview roughly in the style of the 2nd proposal's [formal spec overview](WebAssembly#87 (comment)) by @rossberg. Particular points of interest: - In this I assume `rethrow` does have an immediate, as it is now described in WebAssembly#137. - The instruction `unwind` now reduces to `catch_all ... rethrow` as specified in Heejin's overview. - Because unwind is much simpler in this MVP, there is no `throw_point` anymore and `caught_m` is much simpler. - The introduction of `caught_m` now also introduces a label around the catch instructions, which label a rethrow instruction can reference. - Added explanation of the peculiar side condition in try's execution rule - just trying to make the rules more compact. I would be happy if anyone could point out things that are wrong or that I misunderstood.
This is an attempt to formally describe @aheejin's 3rd proposal, which she presented to the Wasm CG, and which was voted to be the new EH proposal, on September 18, 2020. This is not formal spec that I have developed, but a formal description of this 3rd proposal. This is a reworked form of my [first attempt on this formal spec overview](WebAssembly#87 (comment)) edited with my new understanding of the spec based on the discussion below, and in other issues, and according to @aheejin 's [3rd proposal overview](https://github.com/WebAssembly/exception-handling/blob/f7a4f60d11fb6326fc13f84d3889b11d3873f08a/proposals/Exceptions.md) in PR WebAssembly#137. This is in the form of a document as @tlively [requested](WebAssembly#142 (comment)), to make discussion on specific points easier. I wrote this formal spec overview roughly in the style of the 2nd proposal's [formal spec overview](WebAssembly#87 (comment)) by @rossberg. Particular points of interest: - In this I assume `rethrow` does have an immediate, as it is now described in WebAssembly#137. - The instruction `unwind` now reduces to `catch_all ... rethrow` as specified in Heejin's overview. - Because unwind is much simpler in this MVP, there is no `throw_point` anymore and `caught_m` is much simpler. - The introduction of `caught_m` now also introduces a label around the catch instructions, which label a rethrow instruction can reference. - Added explanation of the peculiar side condition in try's execution rule - just trying to make the rules more compact. I would be happy if anyone could point out things that are wrong or that I misunderstood.
Hello.
I'm interested in formal execution definition of WASM with exception handling proposal included.
What I now think is that the
try catch end
block semantics withthrow
instruction can be described in reduction rules, similar to PLDI'17 MVP spec paper.Also, I heard from @aheejin that @rossberg has done some work on the formal spec of the proposal.
Are there in-progress works related to formal definition of exception handling?
The text was updated successfully, but these errors were encountered: