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

Proposed instruction format for reintroducing exnref #281

Open
@aheejin

Description

@aheejin

It’s been a while since we posted #280 and did a presentation in the 8/1 CG meeting. I think this is time we kick off more concrete discussions on what to do for the next steps.


CG Meeting Schedule

We reserved two slots in September CG meeting:
On 9/12, we are going to make a brief announcement that we have @titzer as a ch-champion of the EH proposal, and let people know that discussions are taking place in Github. On 9/26, we will have a 15-min slot for the recap of our proposed option and some possible discussions. I hoped we could do it all on 9/12 but the slot had already been fully reserved. And we plan to do a vote on the actual switch at the October hybrid CG meeting (remote option is available).


Proposed Instruction Format

And we’d like to propose below as our endorsed option to reintroduce exnref.

try blocktype
catch i li
catch j lj
...
catch_all l
  instruction*
end

In the folded format, this can be also written as

(try (result ...) (catch $i $li) (catch $j $lj) ... (catch_all $l)
  ...
)

When an exception is thrown within instruction*, it is checked against each of the tags in order in the list of catches, and if it is caught by one of the catches, the control flow branches to the corresponding label with extracted values and the exception’s exnref. So if a tag contains a single i32, its target label’s result type will be a multivalue of (i32, exnref). The catch_all label’s return type, if present, is just an exnref.

So an example of a try with two tags and a catch_all would be:

block $li (result …, exnref)
  block $lj  (result …, exnref)
    block $l (result exnref)
      try blocktype (catch i li) (catch j lj) (catch_all l)
        instruction*
      end
    end
    handler code for catch_all
  end
  handler code for catch j
end
handler code for catch i

This is a variant of Option B we presented on 8/1. The difference is we bundle the catch labels with try, preceding the instructions that they guard, for ease of decoding. Because catches are with the try, we end the block with a normal end, as in blocks and loops.

This option doesn’t have the many-partitioned blocks of try-catch-...-catch_all anymore; instead now try is a block that additionally has attached catch and catch_all clauses. Note that we don’t need the (do) syntax in the text format anymore. Also in binary format, the handler list can be just a vector of immediates as in br_table, so we don’t need actual opcodes for catch and catch_all.

(Our presentation on 8/1 incorrectly included br_on_exn for Option B, which is not necessary because catch pushes extracted values along with an exnref. The slides have been fixed.)

rethrow will take an explicit exnref, not the label. The current rethrow instruction, which takes a label, creates semantic dependency on the lexical context which has been a challenge to some compiler code transformations.

throw instruction will remain the same.

try-delegate will be removed from the new spec because we can achieve the same semantics using exnref and branches.

We chose this option because several stakeholders we talked to expressed preference for it. The reasons include:

  • More in line with other Wasm regular control flow instructions, e.g., blocks and branches
  • The number of required opcodes are about half of the current proposal (no try-delegate, no need for catch and catch_all opcodes)
  • Simpler decoding from the VM side

I was able to talk with several VM and toolchain authors and they said the plan seemed doable.

@rossberg prototyped this option in https://github.com/WebAssembly/exception-handling/tree/exnref-1b branch. You can also see the diff in main...exnref-1b#diff-667145a59d9b08f9350bb76322feec7bbe56dda640a84dd5a9f0a65097ec452e.


Migration Plan

If we choose to adopt this option, the migration will progress cautiously given the circumstance that the current EH instructions have been already shipped to the web. The VMs will be supporting both current and the new instructions for the foreseeable future so apps already deployed won’t be disrupted. Emscripten + LLVM toolchain will support the new option under a flag first, and switch to it after it is stabilized. We also plan to provide a converter tool from the old binary to the new format to facilitate the use of the new instructions without the need for recompilation. We have a tentative plan, or more of a hope, for the deprecation of the current instructions, but this will only happen when we can be sure that the usage of the old instructions is low enough, which may turn out infeasible. Before any deprecation, we will maintain the documentation of the current instructions in the supplemental Phase 3 documentation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions