WebAssembly / WebAssembly/binaryen

[wasm-as/wasm-dis]: Don't say the input/output is WebAssembly Text because it's not

Open
#4,550 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
WebAssembly
Stars
8.6k
Forks
885
Avg merge
1d 19h
Merged PRs (30d)
69

Description

The s-expression language used by wasm-as and wasm-dis is non-compliant. It's not even just a subset, it's simultaneously a subset and a superset. So using it with compliant WAT code with certain extensions is impossible. So either we should not call it .wat/WebAssembly text, or make it compliant.

Examples

I will present a few examples to motivate this.

Source order

All memory segments must be before data segments, in source location
$ cat memory-before-data.wat
(module
  (data (i32.const 0) "Hello, world!\n")
  (memory 1))
$ wasm-as memory-before-data.wat
[parse exception: data but no memory (at 2:2)]Fatal: error in parsing input
$ wat2wasm memory-before-data.wat
$ cat memory-before-data.fixed.wat
(module
  (memory 1)
  (data (i32.const 0) "Hello, world!\n"))
$ wasm-as memory-before-data.fixed.wat
$ wat2wasm memory-before-data.fixed.wat
All globals must be defined before they are used, with respect to source location
$ cat global-before-use.wat
(module
  (func $foo (result i32) (global.get $global))
  (global $global i32 (i32.const 0)))
$ wasm-as global-before-use.wat
[parse exception: bad global.get name (at 2:26)]Fatal: error in parsing input
$ wat2wasm global-before-use.wat
$ cat global-before-use.fixed.wat
(module
  (global $global i32 (i32.const 0))
  (func $foo (result i32) (global.get $global)))
$ wasm-as global-before-use.fixed.wat
$ wat2wasm global-before-use.fixed.wat
Explanation

As defined in 6.6.13 of the WASM spec, "a module consists of a sequence of fields that can occur in any order" (180), excluding regarding composition of modules, where "all imports must occur before any regular definition of a function, table, memory or global, thereby maintaining the ordering of the respective index spaces" (181).

This is not an example of a syntactical limitation allowed as defined in section 7.2.1.

Folded instructions without correct number of arguments, but where those arguments are present on the stack

For example, consider the following function:

f(x) :=
    x = x + 1
    x + 5

While this is a bit contrived, I have come across this example in regular use. One may translate this imperative pseudocode into the following WAT:

$ cat folded-instrs.wat
(module
  (func $foo (param $x i32) (result i32)
    (local.tee $x (i32.add (local.get $x) (i32.const 1)))
    (i32.add (i32.const 5))))
$ wasm-as folded-instrs.wat
[parse exception: expected more elements in list (at 4:4)]Fatal: error in parsing input
$ wat2wasm folded-instrs.wat

There is no way to fix this within the input format of wasm-as, meaning using local.tee in any position but within another folded expression is not allowed.
This also means that using multiple returns in a compliant way is impossible (contrived, but minimal example):

$ cat multiple-returns-folded.wat
(module
  (func $foo (result i32 i32)
    (i32.const 10)
    (i32.const 15))
  (func $bar (result i32)
    (i32.add (call $foo))))
$ wasm-as multiple-returns-folded.wat                                                               
[parse exception: expected more elements in list (at 6:4)]Fatal: error in parsing input
$ wat2wasm multiple-returns-folded.wat

Note the following: as defined in section 6.5.10, "folded instructions are solely syntactic sugar, no additional syntactic or type-based checking is implied". Also, instructions in the folded form are defined as such: '(' plaininstr foldedinstr* ')'. The usage of * in foldedinstr implies that the number of elements does not have to "align" with the instruction used, as no additional syntactic checking is to be done (174).

This is not an example of a syntactical limitation allowed as defined in section 7.2.1.

This means that the only way to do multiple returns is to use the tuple syntax, which is not a part of WebAssembly Text, which I would generally consider okay, as it would be a superset. However, as this is the only way (that I can find) to use multiple returns in this s-expression language (and is the way shown by wasm-dis), I consider this to be another example of noncompliance.

Flat form is not supported.

This one is somewhat self-explanatory. Only the s-expression format of WAT is supported by wasm-as/wasm-dis, not the "flat"/non-folded format that is also supported by tools such as wabt.

This is not as much of a problem as the previous examples, but again, it is not example of a syntactical limitation allowed as defined in section 7.2.1.

Notes

All section and page references are relative to the section and page numbers shown on the current (Release 1.1, Draft 2022-03-21) WebAssembly Specification PDF.

Conclusion

Yes, this is pedantic. But I find that this seems like a terrible decision to make, as binaryen and its tooling is used by several important tools, such as emscripten. While I don't know if wasm-as/wasm-dis are specifically used anywhere, it still seems counterintuitive to have a tool that seems "officially" developed by the WebAssembly group (as a repository in its GitHub organization) to not actually support compliant examples of WAT.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the reported cases through the wasm-as and wasm-dis entry points, comparing their accepted and emitted s-expression forms with compliant WebAssembly Text behavior. Done requires a decided scope: either the tools are renamed to avoid claiming WAT compatibility or their handling of source order, folded instructions, multiple returns, and flat form is made compliant.

Written by the indexing model from the issue text.

Assessment

Tech stack
wasm
Domain
compilers, devtools
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.