Skip to content

Block-type annotations for branch-unrelated block-like instructions are redundant #1352

@RossTate

Description

@RossTate

Originally, and I believe still currently, all block-like instructions—meaning instructions with a matching end such as block/if/loop—in WebAssembly introduce a branch target. For efficient type-checking, it is important that the type of this branch target be annotated. To this end, block types were introduced. Originally block types were restricted, but those restrictions were lifted in the Multi-Value proposal.

But as WebAssembly grows, there will be more block-like instructions, and many will not be naturally related to branching. The first example on the horizon is let in the Typed Function References proposal. This instruction simply binds stack slots to fresh local variables that remain in scope until the matching end instruction.

Currently, let has a block-type annotation and introduces a branch target in order to be consistent with the existing block-like instructions whose purpose all happen to be to introduce branch targets. If we eliminate the feature-unrelated branch target of let, then its block-type annotation is redundant and is counter to one of let's main values: reducing type annotations. As discussed in the recent CG meeting, redundant type annotations not only increase binary size—they actually even slow down validation. As the type system gets richer, these downsides will only worsen because it will take more space to describe redundant type annotations (and it will be less common for type annotations to overlap) and it will take more time to validate redundant type annotations.

There seemed to be widespread support for removing redundant type annotations from non-block-like instructions, so here I wanted to discuss removing them from upcoming block-like instructions. There are three degrees to which this can be done, and I recommend getting consensus on each degree in order before proceeding to the next:

  1. Do not require redundant block-type annotations, e.g. on naturally control-unrelated instructions like let.
  2. Only require label-type annotations on unreleased control-related block-like instructions, e.g. try.
  3. Only require label-type annotations on released control-related block-like instructions: block/if/loop.

Regarding Degrees 2 and 3, in all of block/if/loop/try, only half of the block-type annotation is helpful: the half that you can branch to. For the other half, you only need to specify the number of operands to leave on the stack. But, as I said, it's best to defer discussion of this more complex issue until after the easier issue (Degree 1) has been resolved. I just wanted to mention this here because it's likely to come up in the discussion anyways, if only to explain why certain annotations are unnecessary, and because all the discussion of Degree 1 will be relevant to Degrees 2 and 3 and it would be jarring to start a completely new issue for those with much of its relevant context here. I'll update the following status as appropriate:

Status: Only Degree 1 in discussion. Please share your thoughts and assume all comments are within the scope of Degree 1 unless otherwise stated!

P.S. If you're wondering how the block-type annotation for let can be redundant, the "principal" input stack-type of a let block is the output stack-type of the previous instruction (minus whatever stack slots let binds to fresh local variables), and the "principal" output stack-type of a let block is the output stack-type of the last instruction of the block's body. Adding a block-type annotation would just add more steps to the type-checker: check that the output stack-type of the previous instruction is a subtype of the annotation's input stack-type, type-check the body using just the annotation's (weaker) input stack-type, check that the output stack-type of the last instruction of the block's body is a subtype of the annotation's output stack-type, and type-check subsequent instructions using just the annotation's (weaker) output stack-type.

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