WebAssembly / WebAssembly/binaryen

Optimization issue where allocation is not eliminated

Open
#8,641 2 comments 0 reactions 1 assignee View on GitHub

@stevenfontanella is already working on this.

Since Apr 22, 2026.

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

Description

Dart uses iterators pervasively, especially over lists (e.g. for (final value in list) { ... }). The iterable (list) provides a get:iterator method. The iterator then has a iterator.moveNext() and iterator.current. If we know which list type it is we'd like to avoid the iterator overhead.

We have been doing inlining on the dart2wasm side to avoid that. Now I'm experimenting with adjusting our inliner and have noticed an issue in binaryen:

  • if dart2wasm does more inlining the iterator allocation disppears after binaryen optimizations
  • if dart2wasm does less inlining, binaryen does the inlining for us, but the iterator allocation stays

Example: The dart code looks like this:

final a = A();
main() {
  a.doIt();
  a.doIt();
}

class A {
  final a1 = <int>[];
  final a2 = <double>[];
  final a3 = <String>[];

  void doIt() {
    for (final x in a1) {
      print(x);
    }
    for (final x in a2) {
      print(x);
    }
    for (final x in a3) {
      print(x);
    }
  }
}

Here we want to avoid the allocation of the iterator (a _GrowableListIterator wasm struct).

See allocation_elimination_issue.tar.gz. Unpacking with tar xvzf allocation_elimination_issue.tar.gz will give

# Dart2wasm does the inlining                                           
test.before.wasm
test.before.wasm.wat
# The test.before.wasm optimized via -Os -Os -Os
test.before.opt.wasm
test.before.opt.wasm.wat

# Dart2wasm does less inlining, binaryen does the rest (it inlines `call $"_GrowableListIterator.current= implicit setter"`)         
test.after.wasm
test.after.wasm.wat
# The test.after.wasm optimized via -Os -Os -Os
test.after.opt.wasm
test.after.opt.wasm.wat

Here we can see that (func $A.doit ...) is much larger if we leave the inlining to binaryen, as it doesn't eliminiate the _GrowableListIterator struct allocations.

(Optimization via wasm-opt --enable-gc --enable-reference-types --enable-multivalue --enable-exception-handling --enable-nontrapping-float-to-int --enable-sign-ext --enable-bulk-memory --enable-threads --enable-simd '--no-inline=*<noInline>*' --traps-never-happen -g -Os -Os -Os test.before.wasm -o test.before.opt.wasm and same for test.after.wasm -> test.after.opt.wasm)

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.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.